apenwarr-redo/minimal/do
Avery Pennarun 7142c342ae minimal/do: faster deletion of stamp files.
"while/read/printf | xargs -0" is much faster than while/read/rm, because it
doesn't fork so many times.
2011-01-01 04:15:12 -08:00

120 lines
2.4 KiB
Bash
Executable file

#!/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)
#
_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
export DO_BUILT=$PWD/.do_built
if [ -e "$DO_BUILT" ]; then
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"
fi
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()
{
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}
}
_run_dofile()
{
export DO_DEPTH="$DO_DEPTH "
export REDO_TARGET=$PWD/$TARGET
set -e
. "$PWD/$DOFILE" >"$TARGET.tmp2"
}
_do()
{
DIR=$1
TARGET=$2
if [ ! -e "$TARGET" ] || [ -e "$TARGET/." -a ! -e "$TARGET.did" ]; then
printf '\033[32mdo %s\033[1m%s\033[m\n' \
"$DO_DEPTH" "$DIR$TARGET" >&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
: >>"$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
if [ -n "$*" ]; then
redo "$@"
else
redo all
fi
if [ -n "$DO_TOP" ]; then
echo "Removing stamp files..." >&2
while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" |
xargs -0 rm -f 2>/dev/null
fi