Files
ioccc/bin/sgit
T
Cody Boone Ferguson 05e83b60ff Bug fix sgit - new version 0.0.5-1 16-02-2023
A problem existed where more than one command would not work (always or
in some conditions depending on the command: not sure which). This
prevented a fix in years.html which will be in the next commit. The sgit
repo has been updated with this fix as well.

The fix is to remove space from IFS and to change "${SED_COMMANDS[*]}"
to be "${SED_COMMANDS[@]}".
2023-02-16 04:38:40 -08:00

183 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# sgit - sed -i on all files under git control
#
# usage: sgit -e 'sed command'... <glob...>
#
# This script will allow one to update files under git control without having to
# come up with a list of files and then passing those to the command. It allows
# for multiple sed commands (all with in-place editing) and multiple globs.
#
# DISCLAIMER AND WARNING: this is something of a hack and might be error prone.
# It works for what is needed but possibly could be improved. Even so I like it
# how it is and I don't think it would do good to add any additional features
# except perhaps allowing for one to specify path to sed.
#
# - Cody Boone Ferguson (@xexyl)
#
export SGIT_VERSION="0.0.5-1 16-02-2023" # format: major.minor.patch-release DD-MM-YYYY
USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-x] [-I] [-o sed_options] [-s sed] [-e command] <glob...>
-h print help and exit
-V print version and exit
-v level set verbosity level
-x turn on tracing (set -x)
-I disable in place editing
-o sed options (don't pass '-')
-s sed set path to sed
-e command append sed command to execute on globs
sgit version: $SGIT_VERSION"
SED="$(type -P sed)"
export SED
export SED_OPTIONS=""
export I_FLAG=
export VERBOSITY=0
# we need an array for sed commands
declare -a SED_COMMANDS
# we need to remove ' ' from the IFS!
IFS=$'\t\n'
# parse args
#
while getopts :hVv:xIo:s:e: flag; do
case "$flag" in
h) echo "$USAGE" 1>&2
exit 2
;;
V) echo "$SGIT_VERSION" 1>&2
exit 2
;;
v) VERBOSITY="$OPTARG";
;;
x) set -x
;;
I) I_FLAG="-I"
;;
o) SED_OPTIONS="-$OPTARG"
;;
s) SED="$OPTARG"
;;
e) SED_COMMANDS+=(-e "$OPTARG")
;;
:) echo "$0: ERROR: option -$OPTARG requires an argument" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 3
;;
*)
;;
esac
done
shift $(( OPTIND - 1 ));
# firewall
# check that SED_COMMANDS is not empty!
if [[ -z "${SED_COMMANDS[*]}" ]]; then
echo "$(basename "$0"): ERROR: you must specify at least one sed command" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 2
fi
# check that sed is executable
if [[ -z "$SED" ]]; then
echo "$(basename "$0"): ERROR: sed cannot be empty" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 2
elif [[ ! -f "$SED" ]]; then
echo "$(basename "$0"): ERROR: sed is not a regular file: $SED" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 2
elif [[ ! -x "$SED" ]]; then
echo "$(basename "$0"): ERROR: sed is not an executable file: $SED" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 2
fi
# also check number of remaining args
if [[ "$#" -eq 0 ]]; then
echo "$(basename "$0"): ERROR: you must specify at least one glob" 1>&2
echo 1>&2
echo "$USAGE" 1>&2
exit 2
fi
# then check that this is a git repo!
git status 2>/dev/null 1>&2
status="$?"
if [[ "$status" -ne 0 ]]; then
echo "$(basename "$0"): ERROR: ${PWD} not a git repository" 1>&2
exit 1
fi
if [[ $VERBOSITY -gt 1 ]]; then
echo "debug[2]: sed commands: ${SED_COMMANDS[*]}" 1>&2
fi
# This might not the best performance because it does this on all files of the
# glob rather than only those files matched by the glob with matching text but
# it's better than it used to be (it used to run git ls-files on the repo for
# each sed command so the more you had the slow it would become as it had to get
# the list of files each time!).
#
# A better approach would be to somehow use git grep to find files that match
# but this would complicate the command line (at least in anyway I can think of
# how to do it) so we do it on all files in the repo.
#
# But these would possibly require additional args to the command and
# unnecessarily complicate matters. Anyway it's a hack so it doesn't have to be
# perfect (not that there even is such a thing as perfect).
#
if [[ "$VERBOSITY" -gt 1 ]]; then
echo "debug[2]: looping through all globs" 1>&2
fi
i=0
while [[ "$i" -le "$#" ]]; do
if [[ "$VERBOSITY" -gt 1 ]]; then
echo "debug[2]: found glob: $1" 1>&2
fi
if [[ "$VERBOSITY" -ge 1 ]]; then
if [[ -z "$I_FLAG" ]]; then
if [[ -n "$SED_OPTIONS" ]]; then
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"\" $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2
else
echo "debug[1]: about to run: git ls-files $1 | xargs $SED -i\"\" ${SED_COMMANDS[*]}" 1>&2
fi
else
if [[ -n "$SED_OPTIONS" ]]; then
echo "debug[1]: about to run: git ls-files $1 | xargs $SED $SED_OPTIONS ${SED_COMMANDS[*]}" 1>&2
else
echo "debug[1]: about to run: git ls-files $1 | xargs $SED ${SED_COMMANDS[*]}" 1>&2
fi
fi
fi
if [[ -z "$I_FLAG" ]]; then
if [[ -n "$SED_OPTIONS" ]]; then
git ls-files "$1" | xargs "$SED" -i"" "$SED_OPTIONS" "${SED_COMMANDS[@]}"
else
git ls-files "$1" | xargs "$SED" -i"" "${SED_COMMANDS[@]}"
fi
else
if [[ -n "$SED_OPTIONS" ]]; then
git ls-files "$1" | xargs "$SED" "$SED_OPTIONS" "${SED_COMMANDS[@]}"
else
git ls-files "$1" | xargs "$SED" "${SED_COMMANDS[@]}"
fi
fi
((i++))
shift 1
done