diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-16 11:17:24 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-16 11:17:24 +0200 |
| commit | 044ed0720b9af19ad0e586adf907f77f908f0bf3 (patch) | |
| tree | f52caf92c02650cdf74121061f4c01dc7e5c376e | |
| parent | 23f666e92ce0ea6b40f241a33edee43160ee0d81 (diff) | |
| download | quickshell-044ed0720b9af19ad0e586adf907f77f908f0bf3.tar.gz quickshell-044ed0720b9af19ad0e586adf907f77f908f0bf3.zip | |
feat(git): gitcfg, global git config through git itself
list, set, add and unset over git config --global. --fixed-value lets a
write touch one value of a multi-valued key. set and unset check the old
value is still there first: --replace-all with no match appends and exits
0, and the file may have changed in an editor since the page read it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
| -rwxr-xr-x | desktop/modules/git/gitcfg | 56 | ||||
| -rwxr-xr-x | desktop/modules/git/test-gitcfg.sh | 77 |
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" |
