#!/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} } dirname() ( _dirsplit "$1" dir=${dir%/} echo "${dir:-.}" ) _dirsplit "$0" export REDO=$(cd "${dir:-.}" && echo "$PWD/$base") if [ "$base" = "redo-ifchange" ]; then ifchange=1; else ifchange=; fi DO_TOP= if [ -z "$DO_BUILT" ]; then export _do_opt_debug= export _do_opt_exec= export _do_opt_verbose= export _do_opt_continuable= fi while getopts dxvc _opt; do case $_opt in d) _do_opt_debug=1 ;; x) _do_opt_exec=x ;; v) _do_opt_verbose=v ;; c) _do_opt_continuable=1 ;; *) printf "\nusage: $0 [-d] [-x] [-v] [-c] \n" >&2 exit 99 ;; esac done shift "$((OPTIND - 1))" _debug() { [ -z "$_do_opt_debug" ] || echo "$@" >&2 } if [ -z "$DO_BUILT" ]; then DO_TOP=1 [ "$#" -gt 0 ] || set all # only toplevel redo has a default target export DO_BUILT=$PWD/.do_built : >>"$DO_BUILT" sort -u "$DO_BUILT" >"$DO_BUILT.new" if [ -z "$_do_opt_continuable" ]; then echo "Removing previously built files..." >&2 while read f; do printf "%s\0%s.did\0" "$f" "$f"; done <"$DO_BUILT.new" | xargs -0 rm -f 2>/dev/null fi 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() { local prefix= while :; do _find_dofile_pwd "$1" [ -e "$dofile" ] && break [ "$PWD" = "/" ] && break target=${PWD##*/}/$target tmp=${PWD##*/}/$tmp prefix=${PWD##*/}/$prefix cd .. done base=$prefix$base } _run_dofile() { export DO_DEPTH="$DO_DEPTH " export REDO_TARGET="$PWD/$target" local line1 set -e read line1 <"$PWD/$dofile" || true cmd=${line1#"#!/"} if [ "$cmd" != "$line1" ]; then set -$_do_opt_verbose$_do_opt_exec /$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2" else set -$_do_opt_verbose$_do_opt_exec :; . "$PWD/$dofile" >"$tmp.tmp2" fi } _do() { local dir="$1" target="$2" tmp="$3" if [ -z "$ifchange" ] || ( [ ! -e "$target" -o -d "$target" ] && [ ! -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_BUILT" ] || [ ! -d "$(dirname "$target")" ] || : >>"$target.did" ( _run_dofile "$target" "$base" "$tmp.tmp" ) rv=$? if [ $rv != 0 ]; then printf "do: %s%s\n" "$DO_DEPTH" \ "$dir$target: got exit code $rv" >&2 rm -f "$tmp.tmp" "$tmp.tmp2" return $rv fi mv "$tmp.tmp" "$target" 2>/dev/null || ! test -s "$tmp.tmp2" || mv "$tmp.tmp2" "$target" 2>/dev/null rm -f "$tmp.tmp2" else _debug "do $DO_DEPTH$target exists." >&2 fi } # Make corrections for directories that don't actually exist yet. _dir_shovel() { local dir base xdir=$1 xbase=$2 xbasetmp=$2 while [ ! -d "$xdir" -a -n "$xdir" ]; do _dirsplit "${xdir%/}" xbasetmp=${base}__$xbase xdir=$dir xbase=$base/$xbase _debug "xbasetmp='$xbasetmp'" >&2 done } _redo() { set +e for i in "$@"; do _dirsplit "$i" _dir_shovel "$dir" "$base" dir=$xdir base=$xbase basetmp=$xbasetmp ( cd "$dir" && _do "$dir" "$base" "$basetmp" ) [ "$?" = 0 ] || return 1 done } _redo "$@" [ "$?" = 0 ] || exit 1 if [ -n "$DO_TOP" ]; then if [ -z "$_do_opt_continuable" ]; 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 fi