ardupilot/Tools/gittools/git-commit-subsystems

203 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
SCRIPT_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
GIT_DIR=$(git rev-parse --git-dir)
GIT_ROOT=$(git rev-parse --show-toplevel)
usage() {
cat >&$1 <<EOF
Usage: git commit-subsystems [OPTIONS]
Ardupilot's git extension.
Create a different commit for each ardupilot's subsystem (vehicles, libraries
and folders in the project's root). The items in OPTIONS are passed down to the
original git commit command with exception of options --message and --file (and
their short versions). Boths are related to the commit message:
commit-subsystems will treat the commit message from one of those two options
as a template such that occurrences of \$subsystem are replaced with the
subsystem being currently committed.
If neither --message or --file are passed, then the first commit's message will
be used as a template for the other messages and option --edit will be used for
the next commits. To avoid that behavior use --naive.
Another custom option is --raw: don't use commit message as a template.
EOF
}
MSG_FILE="$GIT_DIR/COMMIT_SUBSYSTEM_MSG"
extra_options=
process_msg() {
local subsystem=$1
local prev_subsystem=$2
if [[ -n "$option_m" || -n "$option_F" ]]; then
if [[ $option_F == - ]]; then
echo "Please, type the commits message template:"
option_F="$GIT_DIR/COMMIT_SUBSYSTEM_TEMPLATE"
cat - > "$option_F"
fi
if [[ -n "$option_m" ]]; then
echo "$option_m"
else
cat "$option_F"
fi | if $option_raw; then
cat
else
sed "s,\$subsystem,$cur_subsystem,g"
fi > "$MSG_FILE"
extra_options=(-F "$MSG_FILE")
elif [[ -n $prev_subsystem ]] && ! $option_naive; then # try to be "smart"
cat $GIT_DIR/COMMIT_EDITMSG \
| sed -e "/^\s*#/d" \
-e "s/.*\<$prev_subsystem\>.*/\0\n#\0/" \
| sed "/^[^#]/ s/\<$prev_subsystem\>/$subsystem/g" > "$MSG_FILE"
echo >> "$MSG_FILE"
echo "# This commit message was adapted by commit-subsystems" >> "$MSG_FILE"
extra_options=(-F "$MSG_FILE" --edit)
fi
}
commit_subsystem() {
local subsystem=$1
local prev_subsystem=$2
shift 2
process_msg $subsystem $prev_subsystem
if ! git commit ${extra_options[*]} "$@"; then
echo "Couldn't commit subsystem $subsystem, aborting..." >&2
exit 1
fi
}
args=()
option_m=
option_F=
option_naive=false
option_raw=false
while [[ -n "$1" ]]; do
opt="$1"
case "$opt" in
-h|--help)
usage 1
exit 0
;;
-m|--message)
shift
if [[ -z "$1" ]]; then
echo "Option $opt requires a commit message." >&2
exit 1
fi
option_m="$1"
;;
-F|--file)
shift
if [[ -z "$1" ]]; then
echo "Option $opt requires a file name." >&2
exit 1
fi
option_F="$1"
;;
--naive)
option_naive=true
;;
--raw)
option_raw=true
;;
*)
args+=("$1")
;;
esac
shift
done
if [[ -n $option_m && -n $option_F ]]; then
echo "Options -m and -F can't be combined." >&2
exit 1
fi
set -- "${args[@]}"
LIST=$GIT_DIR/COMMIT_SUBSYSTEMS_LIST
git diff --name-only --staged | $SCRIPT_DIR/path-libraries.sh -p > $LIST
git diff --name-only --staged | $SCRIPT_DIR/path-nonlibraries.sh -p >> $LIST
if [[ $(cat "$LIST" | wc -l) -eq 0 ]]; then
echo "Nothing to commit." >&2
exit 1
fi
echo "Reseting changes in order to add files separately..."
git reset >/dev/null
# head before commits - for recovery
RECOVERY_HEAD=$(git log -n 1 --format=%H)
exit_hook() {
local last_error=$?
set +e
[[ -a /dev/fd/3 ]] && exec 3<&-
[[ $last_error -eq 0 ]] && return 0
echo
echo "Program interrupted or finished with error(s), reseting head..." >&2
git reset $RECOVERY_HEAD >/dev/null
echo "Trying to re-add files..." >&2
if [[ ! -f $LIST ]]; then
echo "File with list of added files not found..." >&2
else
error=false
cat $LIST | while read subsystem path; do
if ! git add -- "$GIT_ROOT/$path"; then
echo "Couldn't add \"$path\"..." >&2
error=true
fi
done
if $error; then
echo "This is embarrassing, couldn't re-add all files. Sorry." >&2
else
echo "Files re-added." >&2
fi
fi
return 1
}
set -e
trap "exit 1" SIGINT
trap exit_hook EXIT
echo "Adding and committing subsystems..."
exec 3< $LIST
cur_subsystem=
prev_subsystem=
empty=true
while read -u 3 subsystem path; do
empty=false
if [[ $cur_subsystem != $subsystem ]]; then
if [[ -n $cur_subsystem ]]; then
commit_subsystem "$cur_subsystem" "$prev_subsystem" "$@"
echo
fi
prev_subsystem=$cur_subsystem
cur_subsystem=$subsystem
fi
if ! git add -- "$GIT_ROOT/$path"; then
echo "Couldn't add \"$path\", aborting..." >&2
exit 1
fi
done
# the last one
commit_subsystem "$cur_subsystem" "$prev_subsystem" "$@"
echo