summaryrefslogtreecommitdiffstats
path: root/do
diff options
context:
space:
mode:
Diffstat (limited to 'do')
-rwxr-xr-xdo150
1 files changed, 150 insertions, 0 deletions
diff --git a/do b/do
new file mode 100755
index 0000000..901e4f3
--- /dev/null
+++ b/do
@@ -0,0 +1,150 @@
+#!/bin/sh
+#
+# A minimal alternative to djb redo that doesn't support incremental builds.
+# For the full version, visit http://github.com/apenwarr/redo
+#
+# The author disclaims copyright to this source file and hereby places it in
+# the public domain. (2010 12 14)
+#
+
+# By default, no output coloring.
+GREEN=""
+BOLD=""
+PLAIN=""
+
+if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then
+ GREEN="$(printf '\033[32m')"
+ BOLD="$(printf '\033[1m')"
+ PLAIN="$(printf '\033[m')"
+fi
+
+_dirsplit()
+{
+ base=${1##*/}
+ dir=${1%$base}
+}
+
+_dirsplit "$0"
+export REDO=$(cd "${dir:-.}" && echo "$PWD/$base")
+
+DO_TOP=
+if [ -z "$DO_BUILT" ]; then
+ DO_TOP=1
+ [ -n "$*" ] || set all # only toplevel redo has a default target
+ export DO_BUILT=$PWD/.do_built
+ : >>"$DO_BUILT"
+ echo "Removing previously built files..." >&2
+ sort -u "$DO_BUILT" | tee "$DO_BUILT.new" |
+ while read f; do printf "%s\0%s.did\0" "$f" "$f"; done |
+ xargs -0 rm -f 2>/dev/null
+ mv "$DO_BUILT.new" "$DO_BUILT"
+ DO_PATH=$DO_BUILT.dir
+ export PATH=$DO_PATH:$PATH
+ rm -rf "$DO_PATH"
+ mkdir "$DO_PATH"
+ for d in redo redo-ifchange; do
+ ln -s "$REDO" "$DO_PATH/$d";
+ done
+ [ -e /bin/true ] && TRUE=/bin/true || TRUE=/usr/bin/true
+ for d in redo-ifcreate redo-stamp redo-always; do
+ ln -s $TRUE "$DO_PATH/$d";
+ done
+fi
+
+
+_find_dofile_pwd()
+{
+ DOFILE=default.$1.do
+ while :; do
+ DOFILE=default.${DOFILE#default.*.}
+ [ -e "$DOFILE" -o "$DOFILE" = default.do ] && break
+ done
+ EXT=${DOFILE#default}
+ EXT=${EXT%.do}
+ BASE=${1%$EXT}
+}
+
+
+_find_dofile()
+{
+ PREFIX=
+ while :; do
+ _find_dofile_pwd "$1"
+ [ -e "$DOFILE" ] && break
+ [ "$PWD" = "/" ] && break
+ TARGET=${PWD##*/}/$TARGET
+ PREFIX=${PWD##*/}/$PREFIX
+ cd ..
+ done
+ BASE=$PREFIX$BASE
+}
+
+
+_run_dofile()
+{
+ export DO_DEPTH="$DO_DEPTH "
+ export REDO_TARGET=$PWD/$TARGET
+ set -e
+ read line1 <"$PWD/$DOFILE"
+ cmd=${line1#"#!/"}
+ if [ "$cmd" != "$line1" ]; then
+ /$cmd "$PWD/$DOFILE" "$@" >"$TARGET.tmp2"
+ else
+ . "$PWD/$DOFILE" >"$TARGET.tmp2"
+ fi
+}
+
+
+_do()
+{
+ DIR=$1
+ TARGET=$2
+ if [ ! -e "$TARGET" ] || [ -e "$TARGET/." -a ! -e "$TARGET.did" ]; then
+ printf '%sdo %s%s%s%s\n' \
+ "$GREEN" "$DO_DEPTH" "$BOLD" "$DIR$TARGET" "$PLAIN" >&2
+ echo "$PWD/$TARGET" >>"$DO_BUILT"
+ DOFILE=$TARGET.do
+ BASE=$TARGET
+ EXT=
+ [ -e "$TARGET.do" ] || _find_dofile "$TARGET"
+ if [ ! -e "$DOFILE" ]; then
+ echo "do: $TARGET: no .do file" >&2
+ return 1
+ fi
+ [ ! -e "$DO_BUILD" ] || : >>"$TARGET.did"
+ ( _run_dofile "$BASE" "$EXT" "$TARGET.tmp" )
+ RV=$?
+ if [ $RV != 0 ]; then
+ printf "do: %s%s\n" "$DO_DEPTH" \
+ "$DIR$TARGET: got exit code $RV" >&2
+ rm -f "$TARGET.tmp" "$TARGET.tmp2"
+ return $RV
+ fi
+ mv "$TARGET.tmp" "$TARGET" 2>/dev/null ||
+ ! test -s "$TARGET.tmp2" ||
+ mv "$TARGET.tmp2" "$TARGET" 2>/dev/null
+ rm -f "$TARGET.tmp2"
+ else
+ echo "do $DO_DEPTH$TARGET exists." >&2
+ fi
+}
+
+
+redo()
+{
+ for i in "$@"; do
+ _dirsplit "$i"
+ ( cd "$dir" && _do "$dir" "$base" ) || return 1
+ done
+}
+
+
+set -e
+redo "$@"
+
+if [ -n "$DO_TOP" ]; then
+ echo "Removing stamp files..." >&2
+ [ ! -e "$DO_BUILT" ] ||
+ while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" |
+ xargs -0 rm -f 2>/dev/null
+fi