aboutsummaryrefslogtreecommitdiff
path: root/update
diff options
context:
space:
mode:
Diffstat (limited to 'update')
-rwxr-xr-xupdate164
1 files changed, 164 insertions, 0 deletions
diff --git a/update b/update
new file mode 100755
index 0000000..fc2ba54
--- /dev/null
+++ b/update
@@ -0,0 +1,164 @@
+#! /usr/bin/env bash
+
+# Commit and push an update to an existing note.
+#
+# -c
+# Commit only, don't push.
+#
+usage="usage: $0 [-c]"
+
+owd=`pwd`
+trap "{ cd $owd; exit 1; }" ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo "$*" 1>&2; }
+function error () { info "$*"; exit 1; }
+
+push="y"
+
+while [ $# -gt 0 ]; do
+ case $1 in
+ -c)
+ push="n"
+ shift
+ ;;
+ *)
+ error "$usage"
+ ;;
+ esac
+done
+
+if git status --porcelain | grep -q '^M '; then
+ error "error: repository already has staged changes"
+fi
+
+# @@ We could probably handle the case where extra files are added to the
+# note. We just need to make sure they are not changes to other notes.
+#
+if git status --porcelain | grep -q '^?? '; then
+ error "error: repository has untracked files"
+fi
+
+modified="$(git status --porcelain | sed -n -e 's/^ M \(.*\)/\1/p')"
+
+mc="$(echo "$modified" | wc -w)"
+
+if [ "$mc" -eq 0 ]; then
+ error "error: nothing modified"
+fi
+
+if [ "$mc" -gt 1 ]; then
+ error "error: multiple modified files"
+fi
+
+# Extract the start line and count from the changeset header.
+#
+# The format is:
+#
+# @@ [+-]FROM-START,FROM-COUNT [+-]TO-START,TO-COUNT @@
+#
+# Note that if the changeset has only one line then the count is omitted.
+#
+function changeset_start ()
+{
+ echo "$1" | sed -e 's/^@@ [^ ]* [+-]\([^, ]*\).*$/\1/'
+}
+
+function changeset_count ()
+{
+ local r
+ r="$(echo "$1" | sed -n -e 's/^@@ [^ ]* [+-][^,]*,\([^ ]*\) @@$/\1/p')"
+ if [ -z "$r" ]; then
+ r="1"
+ fi
+ echo "$r"
+}
+
+#changeset_start "@@ -12,3 +13,11 @@"
+#changeset_count "@@ -12,3 +13,11 @@"
+#changeset_start "@@ -12 +13 @@"
+#changeset_count "@@ -12 +13 @@"
+
+h=
+if [ "$(basename "$modified")" = "list" ]; then
+ #
+ # This is a list of notes. The plan is to get the start line numbers for the
+ # first and last change set. We then scan the list line by line looking for
+ # headers until we hit the start of the first change set: the last header
+ # that we see should be our header. We also continue scanning until we hit
+ # the end of the last changeset: if we see any headers then we are updating
+ # multiple notes.
+ #
+
+ # Get the diff output as a list of change set headers.
+ #
+ diff="$(git diff -U0 | sed -n -e '/^@@ /p')"
+
+ fc="$(echo "$diff" | head -n 1)"
+ lc="$(echo "$diff" | tail -n 1)"
+
+ sl="$(changeset_start "$fc")"
+ el="$(($(changeset_start "$lc") + $(changeset_count "$lc") - 1))"
+
+ # Scan the list looking for headers.
+ #
+ l=
+ c="0"
+ while read l || [ -n "$l" ]; do
+
+ # Stop if we are past the end line.
+ #
+ c="$(($c + 1))"
+ if [ "$c" -gt "$el" ]; then
+ break
+ fi
+
+ # See if this is a header.
+ #
+ if echo "$l" | grep -q '^[-?!] '; then
+
+ # If we are past the start line then we are modifying multiple notes.
+ #
+ if [ "$c" -gt "$sl" ]; then
+ error "error: multiple modified notes in $modified:${sl}-${el}"
+ fi
+
+ # This is the last header.
+ #
+ h="$l"
+ fi
+ done < <(cat "$modified")
+
+ if [ -z "$h" ]; then
+ error "error: unable to find note header for $modified:${sl}-${el}"
+ fi
+else
+ # This is a file note. All we need to do is get its header (the first line).
+ #
+ h="$(head -n 1 "$modified")"
+fi
+
+# Header should start with one of [-?!].
+#
+sum="$(echo "$h" | sed -n -re 's/^[-?!] ([^[]*)( \[.*\])?$/\1/p')"
+
+if [ -z "$sum" ]; then
+ error "error: unable to parse note header '$h'"
+fi
+
+# By convention the first label is a note type (bug, feature, etc).
+#
+type="$(echo "$h" | sed -n -re 's/^[^[]*\[([^ ]*).*\]$/\1/p')"
+
+if [ -z "$type" ]; then
+ error "error: note header does not include note type as first label"
+fi
+
+# Ok, all looks good so add, commit and push the change.
+#
+git add "$modified"
+git ci -m "Update $type: $sum"
+
+if [ "$push" = "y" ]; then
+ git push
+fi