aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/git
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/modules/git')
-rwxr-xr-xdesktop/modules/git/gitcfg56
-rwxr-xr-xdesktop/modules/git/test-gitcfg.sh77
2 files changed, 133 insertions, 0 deletions
diff --git a/desktop/modules/git/gitcfg b/desktop/modules/git/gitcfg
new file mode 100755
index 0000000..df955bf
--- /dev/null
+++ b/desktop/modules/git/gitcfg
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# The global git config, for the drawer's git page.
+#
+# gitcfg list git config --global -z --list
+# gitcfg set <key> <old> <new> replace the one value equal to <old>
+# gitcfg add <key> <value> add a value
+# gitcfg unset <key> <value> remove the one value equal to <value>
+#
+# Every write goes through git config, so the file keeps its comments, layout
+# and quoting. --fixed-value makes a value a literal rather than a regex, so a
+# write touches one value of a multi-valued key, and the `--` before the key
+# keeps a leading dash an argument rather than an option.
+#
+# A write prints nothing on success. On failure it prints the reason on
+# stdout, for the page, and exits 1.
+
+set -u
+
+usage() {
+ printf 'usage: %s list | set <key> <old> <new> | add <key> <value> | unset <key> <value>\n' \
+ "${0##*/}" >&2
+ exit 2
+}
+
+g() {
+ local err
+ err="$(git config --global "$@" 2>&1)" || { printf '%s\n' "${err:-git config failed}"; exit 1; }
+}
+
+# --replace-all with no value equal to <old> appends <new> and succeeds, and
+# --unset of a missing value fails silently, so both check first: the file
+# may have changed in the editor since the page read it.
+has() {
+ git config --global --fixed-value --get-all -- "$1" "$2" >/dev/null \
+ || { printf '%s no longer holds that value\n' "$1"; exit 1; }
+}
+
+case "${1:-}" in
+ list) [[ $# -eq 1 ]] || usage; exec git config --global -z --list ;;
+ set) [[ $# -eq 4 ]] || usage; has "$2" "$3"; g --fixed-value --replace-all -- "$2" "$4" "$3" ;;
+ add) [[ $# -eq 3 ]] || usage; g --add -- "$2" "$3" ;;
+ unset) [[ $# -eq 3 ]] || usage; has "$2" "$3"; g --fixed-value --unset -- "$2" "$3" ;;
+ *) usage ;;
+esac
diff --git a/desktop/modules/git/test-gitcfg.sh b/desktop/modules/git/test-gitcfg.sh
new file mode 100755
index 0000000..328a575
--- /dev/null
+++ b/desktop/modules/git/test-gitcfg.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+#
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# The one runnable check for gitcfg. GIT_CONFIG_GLOBAL points git at a file
+# in a temp directory, so the real ~/.gitconfig is never read or written.
+#
+# Usage: ./test-gitcfg.sh (exit 0 = all passed)
+
+set -u
+
+here="$(cd "$(dirname "$0")" && pwd)"
+ctl="$here/gitcfg"
+tmp="$(mktemp -d)"
+trap 'rm -rf "$tmp"' EXIT
+export GIT_CONFIG_GLOBAL="$tmp/gitconfig"
+
+fail=0
+check() {
+ if [[ "$2" == "$3" ]]; then
+ echo "ok $1"
+ else
+ echo "FAIL $1"
+ printf ' want: %q\n got: %q\n' "$2" "$3"
+ fail=1
+ fi
+}
+vals() { git config --global --get-all "$1" | paste -sd,; }
+
+# Values starting with a dash, as versionsort.prereleasesuffix holds, and a
+# comment that every write must leave alone.
+printf '# keep me\n[v]\n\ts = -rc\n\ts = -beta\n\ts = -alpha\n' > "$GIT_CONFIG_GLOBAL"
+
+check "list" $'v.s\n-rc|v.s\n-beta|v.s\n-alpha|' "$("$ctl" list | tr '\0' '|')"
+
+out="$("$ctl" set v.s -beta -BETA)"; rc=$?
+check "set one of three: rc" 0 "$rc"
+check "set one of three: silent" "" "$out"
+check "set one of three: values" "-rc,-BETA,-alpha" "$(vals v.s)"
+
+# git would append here and exit 0; gitcfg must refuse instead.
+out="$("$ctl" set v.s -gone x)"; rc=$?
+check "set missing old: rc" 1 "$rc"
+check "set missing old: says so" 1 "$([[ -n "$out" ]] && echo 1)"
+check "set missing old: nothing appended" "-rc,-BETA,-alpha" "$(vals v.s)"
+
+out="$("$ctl" unset v.s -rc)"; rc=$?
+check "unset one of three: rc" 0 "$rc"
+check "unset one of three: values" "-BETA,-alpha" "$(vals v.s)"
+
+out="$("$ctl" unset v.s -gone)"; rc=$?
+check "unset missing: rc" 1 "$rc"
+check "unset missing: says so" 1 "$([[ -n "$out" ]] && echo 1)"
+
+out="$("$ctl" add a.b "x=y")"; rc=$?
+check "add with =: rc" 0 "$rc"
+check "add with =: value" "x=y" "$(vals a.b)"
+
+out="$("$ctl" add "bad key" v)"; rc=$?
+check "add bad key: rc" 1 "$rc"
+check "add bad key: git's error" 1 "$([[ "$out" == *section* ]] && echo 1)"
+
+check "comment kept" 1 "$(grep -c '^# keep me$' "$GIT_CONFIG_GLOBAL")"
+
+"$ctl" bogus >/dev/null 2>&1; rc=$?
+check "usage: rc" 2 "$rc"
+
+exit "$fail"