From 775bad449ab8b48a6882a2628f406463821222cd Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Thu, 23 Apr 2015 15:40:39 -0700 Subject: [PATCH] update-all-config: new utility to update projects' config Inspects all (or specified projects) for incorrect config issues and corrects them or just diagnoses (--dry-run). It handles config values and correcting permissions and group on files and directories. It does not update hooks themselves (but will make sure they have correct group and permissions). update-all-hooks will update any out-of-date hooks. It also does not create the personal mob directory but does perform basic permissions checks and corrections if it exists. Signed-off-by: Kyle J. McKay --- toolbox/update-all-config.sh | 296 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100755 toolbox/update-all-config.sh diff --git a/toolbox/update-all-config.sh b/toolbox/update-all-config.sh new file mode 100755 index 0000000..fac48d6 --- /dev/null +++ b/toolbox/update-all-config.sh @@ -0,0 +1,296 @@ +#!/bin/sh + +# Update all out-of-date config in all current projects and add missing bits + +# If one or more project names are given, just update those instead + +# update-all-config [--dry-run] [projname]... + +set -e + +. @basedir@/shlib.sh + +force= +dryrun= +[ "$1" != "--force" -a "$1" != "-f" ] || { force=1; shift; } +[ "$1" != "--dry-run" -a "$1" != "-n" ] || { dryrun=1; shift; } +case "$1" in -*) echo "Invalid options: $1" >&2; exit 1;; esac + +umask 002 +dmode=02775 +dperm='drwxrwsr-x' +fmode=0664 +fperm='-rw-rw-r--' +if [ -z "$cfg_owning_group" ]; then + if [ -z "$force" ]; then + echo "No owning_group set, refusing to run without --force" >&2 + exit 1 + fi + dmode=02777 + dperm='drwxrwsrwx' + fmode=0666 + fperm='-rw-rw-rw-' +fi + +get_perm() { + ls -ldH "$1" | cut -d ' ' -f 1 +} + +get_grp() { + ls -ldH "$1" | awk '{print $4}' +} + +wrote= +pmsg() { + [ -n "$hdr" ] || { hdr=1; [ -z "$wrote" ] || echo ""; echo "$proj:"; } + printf ' %s\n' "$*" + wrote=1 +} + +change_dperm() { + result= + oldperm="$(get_perm "$1")" + [ -n "$dryrun" ] || chmod $dmode "$1" 2>/dev/null || result=$? + pmsg "$1/:" "$oldperm" '->' "$dperm" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +change_group() { + result= + oldgrp="$(get_grp "$1")" + [ -n "$dryrun" ] || chgrp "$cfg_owning_group" "$1" 2>/dev/null || result=$? + isdir= + ! [ -d "$1" ] || isdir='/' + pmsg "$1$isdir:" group "$oldgrp" '->' "$cfg_owning_group" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +change_fperm() { + result= + oldperm="$(get_perm "$1")" + msg= + [ "$oldperm" = "$fperm" ] || { msg=1; [ -n "$dryrun" ]; } || chmod $fmode "$1" 2>/dev/null || result=$? + [ -z "$msg" ] || pmsg "$1:" "$oldperm" '->' "$fperm" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +change_fpermr() { + result= + oldperm="$(get_perm "$1")" + scratch="${oldperm#??}" + newperm="-r${scratch%??????}" + scratch="${scratch#???}" + newperm="${newperm}r${scratch%???}" + scratch="${scratch#???}" + newperm="${newperm}r$scratch" + [ -n "$dryrun" ] || [ "$oldperm" = "$newperm" ] || chmod a+r "$1" 2>/dev/null || result=$? + pmsg "$1:" "$oldperm" '->' "$newperm" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +change_fpermnox() { + result= + oldperm="$(get_perm "$1")" + newperm="${oldperm%???????}-" + scratch="${oldperm#????}" + newperm="${newperm}${scratch%????}-" + scratch="${scratch#???}" + newperm="${newperm}${scratch%?}-" + [ -n "$dryrun" ] || [ "$oldperm" = "$newperm" ] || chmod a-x "$1" 2>/dev/null || result=$? + pmsg "$1:" "$oldperm" '->' "$newperm" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +change_fpermx() { + result= + oldperm="$(get_perm "$1")" + newperm="${oldperm%???????}x" + scratch="${oldperm#????}" + newperm="${newperm}${scratch%????}x" + scratch="${scratch#???}" + newperm="${newperm}${scratch%?}x" + [ -n "$dryrun" ] || [ "$oldperm" = "$newperm" ] || chmod a+x "$1" 2>/dev/null || result=$? + pmsg "$1:" "$oldperm" '->' "$newperm" ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +do_mkdir() { + result= + [ -n "$dryrun" ] || mkdir "$1" 2>/dev/null || [ -d "$1" ] || result=1 + pmsg "$1/:" created ${result:+FAILED!} ${dryrun:+(dryrun)} +} + +nl="$(printf '\n.')" +nl="${nl%?}" +readconfiglist() { + if [ -n "$dryrun" ] && ! [ -e config ]; then + configlist= + else + configlist="$(git config --list --file config)" + [ -z "$configlist" ] || configlist="$configlist$nl" + fi +} + +configitem() { + while read -r _item; do + case "$_item" in "$1"=*) + printf '%s' "${_item#*=}" + return 0 + esac + done <<-EOT + $configlist + EOT + return 1 +} + +isbooltrue() { + case "$1" in 1|[Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]) return 0; esac + return 1 +} + +isboolfalse() { + case "$1" in 0|[Ff][Aa][Ll][Ss][Ee]|[Nn][Oo]|[Oo][Ff][Ff]) return 0; esac + return 1 +} + +isbool() { + isbooltrue "$1" || isboolfalse "$1" || return 1 +} + +do_config() { + unset= + msg= + [ "$1" != "--unset" ] || { unset=1; shift; _x="$1"; shift; msg="$*"; set -- "$_x"; } + item="$1"; shift + result= + existsnot= + oldval="$(configitem "$item")" || existsnot=1 + ccmd=unset + arg="$item" + [ -n "$existsnot" -o -z "$unset" ] || [ $(printf '%s' "$configlist" | grep "^${item%%.*}\.[^.][^.]*=" | wc -l) -ne 1 ] || { ccmd="remove-section"; arg="${item%%.*}"; } + [ -n "$dryrun" ] || [ -n "$unset" -a -n "$existsnot" ] || git config --file config ${unset:+--$ccmd} "$arg" "$@" 2>/dev/null || result=1 + if [ -n "$existsnot" ]; then + [ -n "$unset" ] || pmsg "config $item:" created "\"$*\"" ${result:+FAILED!} ${dryrun:+(dryrun)} + else + if [ -n "$unset" ]; then + pmsg "config $item:" removed $msg "\"$oldval\"" ${result:+FAILED!} ${dryrun:+(dryrun)} + else + pmsg "config $item:" "\"$oldval\"" '->' "\"$*\"" ${result:+FAILED!} ${dryrun:+(dryrun)} + fi + fi +} + +mkdirs='refs info hooks ctags htmlcache objects objects/info' +mkfiles='config info/lastactivity' +fixfpermsfiles='HEAD config description packed-refs README.html info/lastactivity' +fixfpermsfiles="$fixfpermsfiles info/alternates info/http-alternates info/packs" +fixfpermsfiles="$fixfpermsfiles .nofetch .clonelog .clone_in_progress .clone_failed" +fixfpermsfiles="$fixfpermsfiles .banged .bangagain .banglog .nogc .bypass .bypass_fetch" +fixfpermsdirs='ctags' + +boolvars='gitweb.statusupdates' +falsevars='receive.denynonfastforwards' +false0vars='gc.auto receive.autogc' +truevars='receive.updateserverinfo repack.writebitmaps' + +base="${cfg_reporoot%/}" +cmd='cut -d : -f 1 < "$cfg_chroot/etc/group" | grep -v ^_repo' +[ $# -eq 0 ] || cmd='printf "%s\n" "$@"' +eval "$cmd" | \ +( + while read -r proj; do + proj="${proj#$base/}" + proj="${proj%.git}" + projdir="$base/$proj.git" + [ -d "$projdir" ] || { echo "$proj: does not exist -- skipping"; continue; } + is_git_dir "$projdir" || { echo "$proj: is not a .git directory -- skipping"; continue; } + cd "$projdir" + bad= + hdr= + for mdir in $mkdirs; do + if ! [ -d "$mdir" ]; then + if [ -e "$mdir" ]; then + echo "$proj: bypassing project, exists but not directory: $mdir" >&2 + bad=1 + break + fi + do_mkdir "$mdir" + fi + done + [ -z "$bad" ] || continue + while read -r fixdir; do + [ -z "$fixdir" ] || change_dperm "$fixdir" + done <<-EOT + $(find . -xdev -type d -not -perm $dmode -print) + EOT + for mkfile in $mkfiles; do + if [ -e "$mkfile" ]; then + if ! [ -f "$mkfile" ]; then + echo "$proj: bypassing project, exists but not file: $mkfile" >&2 + bad=1 + break + fi + else + result= + [ -n "$dryrun" ] || { >"$mkfile"; } 2>/dev/null || result=1 + pmsg "$mkfile:" created ${result:+FAILED!} ${dryrun:+(dryrun)} + fi + done + [ -z "$bad" ] || continue + [ -n "$dryrun" ] || change_fperm config + readconfiglist + grpshr="$(configitem core.sharedrepository || :)" + if [ -z "$grpshr" ] || isboolfalse "$grpshr"; then + do_config core.sharedrepository 1 + elif ! isbooltrue "$grpshr"; then + pmsg "WARNING: odd core.sharedrepository value left unchanged: \"$grpshr\"" + fi + isbooltrue "$(configitem core.bare || :)" || pmsg "WARNING: core.bare is not true (left unchanged)" + for bvar in $boolvars; do + ! old="$(configitem "$bvar")" || isbool "$old" || do_config --unset "$bvar" "(not a boolean)" + done + for fvar in $falsevars; do + old="$(configitem "$fvar" || :)" + isboolfalse "$old" || do_config "$fvar" false + done + for fvar in $false0vars; do + old="$(configitem "$fvar" || :)" + isboolfalse "$old" || do_config "$fvar" 0 + done + for tvar in $truevars; do + old="$(configitem "$tvar" || :)" + isbooltrue "$old" || do_config "$tvar" true + done + if [ -n "$cfg_owning_group" ]; then + while read -r fixgrp; do + [ -z "$fixgrp" ] || change_group "$fixgrp" + done <<-EOT + $(find . -xdev \( -type d -o -type f \) -not -group $cfg_owning_group -print) + EOT + fi + for fixfile in $fixfpermsfiles; do + if [ -e "$fixfile" ]; then + if ! [ -f "$fixfile" ]; then + echo "$proj: bypassing project, exists but not file: $fixfile" >&2 + bad=1 + break + fi + change_fperm "$fixfile" + fi + done + [ -z "$bad" ] || continue + for fixfile in $(find $fixfpermsdirs -xdev -type f -not -perm $fmode -print); do + change_fperm "$fixfile" + done + while read -r fixfileread; do + [ -z "$fixfileread" ] || change_fpermr "$fixfileread" + done <<-EOT + $(find . -xdev -type f -not -perm -a+r -print) + EOT + while read -r fixfilenox; do + [ -z "$fixfilenox" ] || change_fpermnox "$fixfilenox" + done <<-EOT + $(find . -xdev -type d \( -path ./hooks -o -path ./mob/hooks \) -prune -o -type f -perm +a+x -print) + EOT + while read -r fixfilex; do + case "$fixfilex" in ""|*.sample) :;; *) change_fpermx "$fixfilex"; esac + done <<-EOT + $(! [ -d hooks ] || find hooks -xdev -type f -not -perm -a+x -print + ! [ -d mob/hooks ] || find mob/hooks -xdev -type f -not -perm -a+x -print) + EOT + done +) -- 2.11.4.GIT