From cde9f87dee8498529169aa83abc381ca3acac056 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <github-tech@jeltef.nl>
Date: Wed, 7 Aug 2024 19:04:05 +0200
Subject: [PATCH v6] Add script to keep .editorconfig in sync with
 .gitattributes

Our repo already contained an .editorconfig file, but it was not kept up
to date with .gitattributes. This adds a script that keeps these files
in sync. A big advantage of the editorconfig file is that it many
editors/IDEs get automatically configured to trim trailing newlines and
add a final newline on save. While .gitattributes only complains about
these problems instead of automatically fixing them.
---
 .editorconfig                      | 144 ++++++++++++++++++++++++++++-
 .gitattributes                     |   7 +-
 src/tools/generate_editorconfig.py |  80 ++++++++++++++++
 3 files changed, 224 insertions(+), 7 deletions(-)
 create mode 100755 src/tools/generate_editorconfig.py

diff --git a/.editorconfig b/.editorconfig
index d69a3d1dc4..235b15a4da 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,14 +1,148 @@
 root = true
 
-[*.{c,h,l,y,pl,pm}]
-indent_style = tab
+[*]
 indent_size = tab
+
+[*]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = unset
+tab_width = 8
+
+[*.[chly]]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = tab
+tab_width = 4
+
+[*.pl]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = unset
+tab_width = 4
+
+[*.pm]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = unset
 tab_width = 4
 
-[*.{sgml,xml}]
+[*.po]
+trim_trailing_whitespace = true
+insert_final_newline = unset
 indent_style = space
-indent_size = 1
+tab_width = 8
+
+[*.sgml]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+tab_width = 1
+
+[*.xml]
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+tab_width = 1
 
 [*.xsl]
+trim_trailing_whitespace = true
+insert_final_newline = true
 indent_style = space
-indent_size = 2
+tab_width = 2
+
+[*.data]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[contrib/pgcrypto/sql/pgp-armor.sql]
+trim_trailing_whitespace = unset
+insert_final_newline = true
+indent_style = unset
+tab_width = 8
+
+[src/backend/catalog/sql_features.txt]
+trim_trailing_whitespace = unset
+insert_final_newline = true
+indent_style = unset
+tab_width = 8
+
+[*.out]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/interfaces/ecpg/test/expected/*]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[configure]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[ppport.h]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/backend/regex/COPYRIGHT]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/backend/snowball/libstemmer/*.c]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/backend/utils/mb/Unicode/*-std.txt]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/include/snowball/libstemmer/*]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/timezone/data/*]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/tools/pg_bsd_indent/*]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/tools/pg_bsd_indent/tests/*]
+indent_style = unset
+indent_size = unset
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+
+[src/tools/pg_bsd_indent/*.[ch]]
+trim_trailing_whitespace = unset
+insert_final_newline = unset
+indent_style = unset
+tab_width = 8
+
+# We want editors to use tabs for indenting Perl files, but we cannot add it
+# such a rule to .gitattributes, because certain lines are still indented with
+# spaces (e.g. SYNOPSIS blocks).
+[*.{pl,pm}]
+indent_style = tab
diff --git a/.gitattributes b/.gitattributes
index e9ff4a56bd..7e2fa4a4ac 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,10 +1,12 @@
+# IMPORTANT: After updating this file, also run src/tools/generate_editorconfig.py
 *		whitespace=space-before-tab,trailing-space
 *.[chly]	whitespace=space-before-tab,trailing-space,indent-with-non-tab,tabwidth=4
 *.pl		whitespace=space-before-tab,trailing-space,tabwidth=4
 *.pm		whitespace=space-before-tab,trailing-space,tabwidth=4
 *.po		whitespace=space-before-tab,trailing-space,tab-in-indent,-blank-at-eof
-*.sgml		whitespace=space-before-tab,trailing-space,tab-in-indent
-*.x[ms]l	whitespace=space-before-tab,trailing-space,tab-in-indent
+*.sgml		whitespace=space-before-tab,trailing-space,tab-in-indent,tabwidth=1
+*.xml		whitespace=space-before-tab,trailing-space,tab-in-indent,tabwidth=1
+*.xsl		whitespace=space-before-tab,trailing-space,tab-in-indent,tabwidth=2
 
 # Avoid confusing ASCII underlines with leftover merge conflict markers
 README		conflict-marker-size=32
@@ -29,3 +31,4 @@ src/include/snowball/libstemmer/*	-whitespace
 src/timezone/data/*			-whitespace
 src/tools/pg_bsd_indent/*		-whitespace
 src/tools/pg_bsd_indent/tests/*		-whitespace
+src/tools/pg_bsd_indent/*.[ch]		whitespace=-blank-at-eol,-blank-at-eof,tabwidth=8
diff --git a/src/tools/generate_editorconfig.py b/src/tools/generate_editorconfig.py
new file mode 100755
index 0000000000..26ce8d1bba
--- /dev/null
+++ b/src/tools/generate_editorconfig.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+
+import os
+
+
+def cd_to_repo_root():
+    abspath = os.path.abspath(__file__)
+    dname = os.path.join(os.path.dirname(abspath), "..", "..")
+    os.chdir(dname)
+
+
+def main():
+    cd_to_repo_root()
+
+    with open(".gitattributes", "r") as f:
+        lines = f.read().splitlines()
+
+    new_contents = """root = true
+
+[*]
+indent_size = tab
+"""
+
+    for line in lines:
+        if line.startswith("#") or len(line) == 0:
+            continue
+        name, git_rules = line.split()
+        if git_rules == "-whitespace":
+            rules = [
+                "indent_style = unset",
+                "indent_size = unset",
+                "trim_trailing_whitespace = unset",
+                "insert_final_newline = unset",
+            ]
+        elif git_rules.startswith("whitespace="):
+            git_whitespace_rules = git_rules.replace("whitespace=", "").split(",")
+            rules = []
+            if "-blank-at-eol" in git_whitespace_rules:
+                rules += ["trim_trailing_whitespace = unset"]
+            else:
+                rules += ["trim_trailing_whitespace = true"]
+
+            if "-blank-at-eof" in git_whitespace_rules:
+                rules += ["insert_final_newline = unset"]
+            else:
+                rules += ["insert_final_newline = true"]
+
+            if "tab-in-indent" in git_whitespace_rules:
+                rules += ["indent_style = space"]
+            elif "indent-with-non-tab" in git_whitespace_rules:
+                rules += ["indent_style = tab"]
+            else:
+                rules += ["indent_style = unset"]
+
+            tab_width = "8"
+            for rule in git_whitespace_rules:
+                if rule.startswith("tabwidth="):
+                    tab_width = rule.replace("tabwidth=", "")
+            rules += [f"tab_width = {tab_width}"]
+
+        else:
+            continue
+
+        rules = "\n".join(rules)
+        new_contents += f"\n[{name}]\n{rules}\n"
+
+    new_contents += """
+# We want editors to use tabs for indenting Perl files, but we cannot add it
+# such a rule to .gitattributes, because certain lines are still indented with
+# spaces (e.g. SYNOPSIS blocks).
+[*.{pl,pm}]
+indent_style = tab
+"""
+
+    with open(".editorconfig", "w") as f:
+        f.write(new_contents)
+
+
+if __name__ == "__main__":
+    main()

base-commit: 2bb969f3998489e5dc4fe9f2a61185b43581975d
-- 
2.34.1

