2010-11-15 20:39:34 -08:00
|
|
|
#!/bin/sh
|
|
|
|
|
#
|
|
|
|
|
# A minimal alternative to djb redo that doesn't support incremental builds.
|
|
|
|
|
# For the full version, visit http://github.com/apenwarr/redo
|
|
|
|
|
#
|
2010-12-14 17:58:16 -08:00
|
|
|
# The author disclaims copyright to this source file and hereby places it in
|
|
|
|
|
# the public domain. (2010 12 14)
|
|
|
|
|
#
|
2011-01-04 23:39:48 +11:00
|
|
|
|
|
|
|
|
# By default, no output coloring.
|
2011-03-05 18:48:27 -08:00
|
|
|
green=""
|
|
|
|
|
bold=""
|
|
|
|
|
plain=""
|
2011-01-04 23:39:48 +11:00
|
|
|
|
2011-01-04 14:11:29 -08:00
|
|
|
if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then
|
2011-03-05 18:48:27 -08:00
|
|
|
green="$(printf '\033[32m')"
|
|
|
|
|
bold="$(printf '\033[1m')"
|
|
|
|
|
plain="$(printf '\033[m')"
|
2011-01-04 23:39:48 +11:00
|
|
|
fi
|
|
|
|
|
|
2011-01-01 03:14:32 -08:00
|
|
|
_dirsplit()
|
|
|
|
|
{
|
|
|
|
|
base=${1##*/}
|
|
|
|
|
dir=${1%$base}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-22 22:09:56 -07:00
|
|
|
dirname()
|
|
|
|
|
(
|
|
|
|
|
_dirsplit "$1"
|
|
|
|
|
dir=${dir%/}
|
|
|
|
|
echo "${dir:-.}"
|
|
|
|
|
)
|
|
|
|
|
|
2011-01-01 03:14:32 -08:00
|
|
|
_dirsplit "$0"
|
|
|
|
|
export REDO=$(cd "${dir:-.}" && echo "$PWD/$base")
|
minimal/do: redo vs redo-ifchange, and fix empty target handling.
We previously assumed that redo and redo-ifchange are the same in
minimal/do's design, because it rebuilds all targets on every run, and
so there's no reason to ever build the same target more than once.
Unfortunately that's incorrect: if you run 'redo x' from two points in
a single run (or even twice in the same .do file), we expect x to be
built twice. If you wanted redo to decide whether to build it the
second time, you should have used redo-ifchange.
t/102-empty/touchtest was trying to test for this. However, a
second bug in minimal/do made the test pass anyway. minimal/do would
*always* rebuild any target x that produced no output, not caring
whether it had tried to build before, whether you used redo or
redo-ifchange. And while we tested that redo would redo a file that
had been deleted, we didn't ensure that it would redo a file that was
*not* deleted, nor that redo-ifchange would *not* redo that file.
Fix both bugs in minimal/do, and make t/102-empty/touchtest cover the
missing cases.
2018-10-17 01:42:32 -04:00
|
|
|
if [ "$base" = "redo-ifchange" ]; then ifchange=1; else ifchange=; fi
|
2010-11-15 20:39:34 -08:00
|
|
|
|
2011-01-01 03:42:35 -08:00
|
|
|
DO_TOP=
|
2010-11-15 20:39:34 -08:00
|
|
|
if [ -z "$DO_BUILT" ]; then
|
2011-01-01 03:42:35 -08:00
|
|
|
DO_TOP=1
|
2011-02-26 18:01:31 -08:00
|
|
|
[ -n "$*" ] || set all # only toplevel redo has a default target
|
2011-01-01 03:14:32 -08:00
|
|
|
export DO_BUILT=$PWD/.do_built
|
2011-01-01 22:01:50 -08:00
|
|
|
: >>"$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"
|
2011-01-01 03:14:32 -08:00
|
|
|
DO_PATH=$DO_BUILT.dir
|
|
|
|
|
export PATH=$DO_PATH:$PATH
|
2010-12-11 21:47:55 -08:00
|
|
|
rm -rf "$DO_PATH"
|
|
|
|
|
mkdir "$DO_PATH"
|
|
|
|
|
for d in redo redo-ifchange; do
|
|
|
|
|
ln -s "$REDO" "$DO_PATH/$d";
|
|
|
|
|
done
|
2010-12-14 02:47:51 -08:00
|
|
|
[ -e /bin/true ] && TRUE=/bin/true || TRUE=/usr/bin/true
|
2010-12-11 21:47:55 -08:00
|
|
|
for d in redo-ifcreate redo-stamp redo-always; do
|
2010-12-14 02:47:51 -08:00
|
|
|
ln -s $TRUE "$DO_PATH/$d";
|
2010-12-11 21:47:55 -08:00
|
|
|
done
|
2010-11-15 20:39:34 -08:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
2011-01-15 21:44:08 -08:00
|
|
|
_find_dofile_pwd()
|
2010-11-21 00:16:37 -08:00
|
|
|
{
|
2011-03-05 18:48:27 -08:00
|
|
|
dofile=default.$1.do
|
2011-01-01 03:14:32 -08:00
|
|
|
while :; do
|
2011-03-05 18:48:27 -08:00
|
|
|
dofile=default.${dofile#default.*.}
|
|
|
|
|
[ -e "$dofile" -o "$dofile" = default.do ] && break
|
2010-11-21 00:16:37 -08:00
|
|
|
done
|
2011-03-05 18:48:27 -08:00
|
|
|
ext=${dofile#default}
|
|
|
|
|
ext=${ext%.do}
|
|
|
|
|
base=${1%$ext}
|
2011-01-01 03:14:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-15 21:44:08 -08:00
|
|
|
_find_dofile()
|
|
|
|
|
{
|
2011-03-05 18:48:27 -08:00
|
|
|
local prefix=
|
2011-01-15 21:44:08 -08:00
|
|
|
while :; do
|
|
|
|
|
_find_dofile_pwd "$1"
|
2011-03-05 18:48:27 -08:00
|
|
|
[ -e "$dofile" ] && break
|
2011-01-15 21:44:08 -08:00
|
|
|
[ "$PWD" = "/" ] && break
|
2011-03-05 18:48:27 -08:00
|
|
|
target=${PWD##*/}/$target
|
2011-03-22 22:09:56 -07:00
|
|
|
tmp=${PWD##*/}/$tmp
|
2011-03-05 18:48:27 -08:00
|
|
|
prefix=${PWD##*/}/$prefix
|
2011-01-15 21:44:08 -08:00
|
|
|
cd ..
|
|
|
|
|
done
|
2011-03-05 18:48:27 -08:00
|
|
|
base=$prefix$base
|
2011-01-15 21:44:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-01 03:14:32 -08:00
|
|
|
_run_dofile()
|
|
|
|
|
{
|
|
|
|
|
export DO_DEPTH="$DO_DEPTH "
|
2018-10-12 04:13:47 -04:00
|
|
|
export REDO_TARGET="$PWD/$target"
|
2011-03-05 18:48:27 -08:00
|
|
|
local line1
|
2011-01-01 03:14:32 -08:00
|
|
|
set -e
|
2012-02-09 00:39:38 -05:00
|
|
|
read line1 <"$PWD/$dofile" || true
|
2011-01-01 22:00:14 -08:00
|
|
|
cmd=${line1#"#!/"}
|
|
|
|
|
if [ "$cmd" != "$line1" ]; then
|
2011-03-22 22:09:56 -07:00
|
|
|
/$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2"
|
2011-01-01 22:00:14 -08:00
|
|
|
else
|
2011-03-22 22:09:56 -07:00
|
|
|
:; . "$PWD/$dofile" >"$tmp.tmp2"
|
2011-01-01 22:00:14 -08:00
|
|
|
fi
|
2010-11-21 00:16:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-11-15 20:39:34 -08:00
|
|
|
_do()
|
|
|
|
|
{
|
2018-10-12 04:13:47 -04:00
|
|
|
local dir="$1" target="$2" tmp="$3"
|
minimal/do: redo vs redo-ifchange, and fix empty target handling.
We previously assumed that redo and redo-ifchange are the same in
minimal/do's design, because it rebuilds all targets on every run, and
so there's no reason to ever build the same target more than once.
Unfortunately that's incorrect: if you run 'redo x' from two points in
a single run (or even twice in the same .do file), we expect x to be
built twice. If you wanted redo to decide whether to build it the
second time, you should have used redo-ifchange.
t/102-empty/touchtest was trying to test for this. However, a
second bug in minimal/do made the test pass anyway. minimal/do would
*always* rebuild any target x that produced no output, not caring
whether it had tried to build before, whether you used redo or
redo-ifchange. And while we tested that redo would redo a file that
had been deleted, we didn't ensure that it would redo a file that was
*not* deleted, nor that redo-ifchange would *not* redo that file.
Fix both bugs in minimal/do, and make t/102-empty/touchtest cover the
missing cases.
2018-10-17 01:42:32 -04:00
|
|
|
if [ -z "$ifchange" ] || ( [ ! -e "$target" -o -d "$target" ] && [ ! -e "$target.did" ] ); then
|
2011-01-04 23:39:48 +11:00
|
|
|
printf '%sdo %s%s%s%s\n' \
|
2011-03-05 18:48:27 -08:00
|
|
|
"$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
|
2011-01-01 03:14:32 -08:00
|
|
|
return 1
|
|
|
|
|
fi
|
2011-03-22 22:09:56 -07:00
|
|
|
[ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] ||
|
|
|
|
|
: >>"$target.did"
|
2011-12-31 02:45:38 -05:00
|
|
|
( _run_dofile "$target" "$base" "$tmp.tmp" )
|
2011-03-05 18:48:27 -08:00
|
|
|
rv=$?
|
|
|
|
|
if [ $rv != 0 ]; then
|
2010-12-11 20:36:42 -08:00
|
|
|
printf "do: %s%s\n" "$DO_DEPTH" \
|
2011-03-05 18:48:27 -08:00
|
|
|
"$dir$target: got exit code $rv" >&2
|
2011-03-22 22:09:56 -07:00
|
|
|
rm -f "$tmp.tmp" "$tmp.tmp2"
|
2011-03-05 18:48:27 -08:00
|
|
|
return $rv
|
2010-11-17 18:24:40 -08:00
|
|
|
fi
|
2011-03-22 22:09:56 -07:00
|
|
|
mv "$tmp.tmp" "$target" 2>/dev/null ||
|
|
|
|
|
! test -s "$tmp.tmp2" ||
|
|
|
|
|
mv "$tmp.tmp2" "$target" 2>/dev/null
|
|
|
|
|
rm -f "$tmp.tmp2"
|
2010-11-15 20:39:34 -08:00
|
|
|
else
|
2011-03-05 18:48:27 -08:00
|
|
|
echo "do $DO_DEPTH$target exists." >&2
|
2010-11-15 20:39:34 -08:00
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-03-22 22:09:56 -07:00
|
|
|
# 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
|
|
|
|
|
echo "xbasetmp='$xbasetmp'" >&2
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-02-08 23:59:46 -05:00
|
|
|
_redo()
|
2010-11-15 20:39:34 -08:00
|
|
|
{
|
2012-02-08 23:59:46 -05:00
|
|
|
set +e
|
2010-11-15 20:39:34 -08:00
|
|
|
for i in "$@"; do
|
2010-11-21 00:16:37 -08:00
|
|
|
_dirsplit "$i"
|
2011-03-22 22:09:56 -07:00
|
|
|
_dir_shovel "$dir" "$base"
|
|
|
|
|
dir=$xdir base=$xbase basetmp=$xbasetmp
|
2012-02-08 23:59:46 -05:00
|
|
|
( cd "$dir" && _do "$dir" "$base" "$basetmp" )
|
|
|
|
|
[ "$?" = 0 ] || return 1
|
2010-11-15 20:39:34 -08:00
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-02-08 23:59:46 -05:00
|
|
|
_redo "$@"
|
|
|
|
|
[ "$?" = 0 ] || exit 1
|
2011-01-01 03:42:35 -08:00
|
|
|
|
|
|
|
|
if [ -n "$DO_TOP" ]; then
|
|
|
|
|
echo "Removing stamp files..." >&2
|
2011-01-28 21:10:04 -08:00
|
|
|
[ ! -e "$DO_BUILT" ] ||
|
2011-01-01 04:07:57 -08:00
|
|
|
while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" |
|
|
|
|
|
xargs -0 rm -f 2>/dev/null
|
2011-01-01 03:42:35 -08:00
|
|
|
fi
|