From ebd01ebf8d77aeeea9d4c8eb577e5c5818093811 Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Mon, 13 Feb 2023 06:16:53 -0800 Subject: [PATCH] Greatly improve my sgit script Script no longer requires GNU sed but works with other sed implementations as well (only other one tested is macOS however). Uses getopts to parse options. Usage is now: usage: sgit [-h] [-V] [-v level] [-e command] -h print help and exit -V print version and exit -v level set verbosity level -e command append sed command to execute on globs which means that yes one can specify more than one glob. As long as one sed command is specified (chose -e to match sed) and one arg is specified after the last option then the command line is okay (whether the sed command or file is okay is another matter entirely). Verbose output to help test / debug features or if just interested in what's being done. --- bin/sgit | 125 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/bin/sgit b/bin/sgit index 8efe9f81d..918f21524 100755 --- a/bin/sgit +++ b/bin/sgit @@ -1,24 +1,79 @@ #!/usr/bin/env bash # -# sgit - sed on all files under git control +# sgit - sed -i on all files under git control # -# usage: sgit +# usage: sgit -e 'sed command'... # -# sed must be GNU sed and we use -i'' just in case it's not. Even so sed under -# macOS will fail. This script could be improved to check for GNU sed and it -# might be an easy way to fix it in other sed implementations but it works for -# my purposes and since I want to work on the reason for this script (and not -# the script itself) I'm not going to worry about that. +# 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 hack and most likely error prone! +# 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) # -# firewall -# -# first check that this is a git repo! +export SGIT_VERSION="0.0.2-1 13-02-2023" # format: major.minor.patch-release DD-MM-YYYY +USAGE="usage: $(basename "$0") [-h] [-V] [-v level] [-e command] + + -h print help and exit + -V print version and exit + -v level set verbosity level + -e command append sed command to execute on globs + +sgit version: $SGIT_VERSION" + +export VERBOSITY=0 +export SED_COMMANDS="" +# parse args +# +while getopts :hVv:e: flag; do + case "$flag" in + h) echo "$USAGE" 1>&2 + exit 2 + ;; + V) echo "$SGIT_VERSION" 1>&2 + exit 2 + ;; + v) VERBOSITY="$OPTARG"; + ;; + e) SED_COMMANDS="$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 + +# 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 @@ -26,26 +81,6 @@ if [[ "$status" -ne 0 ]]; then exit 1 fi -# check number of args -if [[ "$#" -lt 2 ]]; then - echo "$(basename "$0"): ERROR: usage: $(basename "$0") " 1>&2 - exit 2 -fi - -export SED_COMMANDS="" -export GLOB="" -# go through the command line, extracting the sed commands. When we've reached -# the end (one arg left) we know we have the glob to pass to git ls-files. -# We do it this way because apparently $BASH_ARG[VC] are not set unless in -# extended debugging mode (shopt -s extdebug). -i=0; -while [[ "$i" -le "$#" ]]; do - SED_COMMANDS="$SED_COMMANDS -e $1"; - ((i++)) - shift 1 -done -GLOB="$1" - # This is 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 @@ -60,13 +95,21 @@ GLOB="$1" # 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). # -# NOTE: it is a burden on the user to specify a glob that will only match -# regular files. Although we could try and figure out if each matching file is a -# regular file it would mean we would have to go through the list a line at a -# time and then add it to a new list if it's a regular file and this seems -# unnecessary. Besides doing '.' will not cause a problem so it might be fine. - -# shellcheck disable=SC2086 -# SC2086 (info): Double quote to prevent globbing and word splitting. We can't -# disable this because we need to have word splitting. -git ls-files "$GLOB" | xargs sed -i'' $SED_COMMANDS +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 + echo "debug[1]: about to run: git ls-files $1 | xargs sed -i '' $SED_COMMANDS" 1>&2 + fi + # shellcheck disable=SC2086 + # SC2086 (info): Double quote to prevent globbing and word splitting. We can't + # quote this because we need to have word splitting. + git ls-files "$1" | xargs /usr/bin/sed -i '' $SED_COMMANDS + ((i++)) + shift 1 +done