minimal/do: don't create a .did file until after a file is actually built.

With the new "continue" feature on by default, it turned out that
ctrl-c during a build, or a .do file returning an error, would mark a
target as "built" even though it hadn't been.  This would prevent
retrying it when you started minimal/do again.  Use a temp file
instead.

It's a little tricky: to prevent accidental recursion, we want to
create a file *before* building, but clean up that file when starting
the next session.  And we rename that file to the actual .did file
*after* building successfully.
This commit is contained in:
Avery Pennarun 2018-11-02 03:48:25 -04:00
commit ec72beb343
11 changed files with 39 additions and 21 deletions

4
.gitignore vendored
View file

@ -1,8 +1,8 @@
/.redo /.redo
/.do_built
/.do_built.dir
*~ *~
*.pyc *.pyc
*.tmp *.tmp
/redo-sh /redo-sh
*.did *.did
.do_built
.do_built.dir

View file

@ -78,11 +78,12 @@ if [ -z "$DO_BUILT" -a "$_cmd" != "redo-whichdo" ]; then
export DO_BUILT=$PWD/.do_built export DO_BUILT=$PWD/.do_built
: >>"$DO_BUILT" : >>"$DO_BUILT"
sort -u "$DO_BUILT" >"$DO_BUILT.new" sort -u "$DO_BUILT" >"$DO_BUILT.new"
if [ -n "$_do_opt_clean" ]; then echo "Cleaning up from previous run..." >&2
echo "Removing previously built files..." >&2 while read f; do
while read f; do printf "%s\0%s.did\0" "$f" "$f"; done <"$DO_BUILT.new" | [ -n "$_do_opt_clean" ] && printf "%s\0%s.did\0" "$f" "$f"
printf "%s.did.tmp\0" "$f"
done <"$DO_BUILT.new" |
xargs -0 rm -f 2>/dev/null xargs -0 rm -f 2>/dev/null
fi
mv "$DO_BUILT.new" "$DO_BUILT" mv "$DO_BUILT.new" "$DO_BUILT"
DO_PATH=$DO_BUILT.dir DO_PATH=$DO_BUILT.dir
export PATH=$DO_PATH:$PATH export PATH=$DO_PATH:$PATH
@ -276,7 +277,6 @@ _do()
echo "do: $target: no .do file ($PWD)" >&2 echo "do: $target: no .do file ($PWD)" >&2
return 1 return 1
fi fi
echo "$PWD/$target" >>"$DO_BUILT"
_dirsplit "$dopath" _dirsplit "$dopath"
dodir=$_dirsplit_dir dofile=$_dirsplit_base dodir=$_dirsplit_dir dofile=$_dirsplit_base
if _startswith "$dofile" "default."; then if _startswith "$dofile" "default."; then
@ -292,18 +292,22 @@ _do()
tmp=$(_relpath "$tmp") || return 97 tmp=$(_relpath "$tmp") || return 97
base=${target%$ext} base=${target%$ext}
[ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] || [ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] ||
: >>"$target.did" : >>"$target.did.tmp"
( _run_dofile "$target" "$base" "$tmp.tmp" ) ( _run_dofile "$target" "$base" "$tmp.tmp" )
rv=$? rv=$?
if [ $rv != 0 ]; then if [ $rv != 0 ]; then
printf "do: %s%s\n" "$DO_DEPTH" \ printf "do: %s%s\n" "$DO_DEPTH" \
"$dir$target: got exit code $rv" >&2 "$dir$target: got exit code $rv" >&2
rm -f "$tmp.tmp" "$tmp.tmp2" rm -f "$tmp.tmp" "$tmp.tmp2" "$target.did"
return $rv return $rv
fi fi
echo "$PWD/$target" >>"$DO_BUILT"
mv "$tmp.tmp" "$target" 2>/dev/null || mv "$tmp.tmp" "$target" 2>/dev/null ||
! test -s "$tmp.tmp2" || ! test -s "$tmp.tmp2" ||
mv "$tmp.tmp2" "$target" 2>/dev/null mv "$tmp.tmp2" "$target" 2>/dev/null
[ -e "$target.did.tmp" ] &&
mv "$target.did.tmp" "$target.did" ||
: >>"$target.did"
rm -f "$tmp.tmp2" rm -f "$tmp.tmp2"
else else
_debug "do $DO_DEPTH$target exists." >&2 _debug "do $DO_DEPTH$target exists." >&2

View file

@ -1 +1,3 @@
/fail /fail
/want-fail
/maybe-fail

View file

@ -4,7 +4,6 @@ rm -f this-doesnt-exist
redo-ifcreate this-doesnt-exist >/dev/null 2>&1 || exit 34 # expected to pass redo-ifcreate this-doesnt-exist >/dev/null 2>&1 || exit 34 # expected to pass
rm -f fail rm -f fail
! redo-ifchange fail >/dev/null 2>&1 || exit 44 # expected to fail ! redo-ifchange fail >/dev/null 2>&1 || exit 44 # expected to fail
@ -16,3 +15,14 @@ redo-ifchange fail >/dev/null 2>&1 || exit 55 # expected to pass
# Make sure we don't leave this lying around for future runs, or redo # Make sure we don't leave this lying around for future runs, or redo
# might mark it as "manually modified" (since we did!) # might mark it as "manually modified" (since we did!)
rm -f fail rm -f fail
rm -f maybe-fail
: >want-fail
! redo-ifchange maybe-fail >/dev/null 2>&1 || exit 66
rm -f want-fail
../flush-cache
redo-ifchange maybe-fail || exit 67 # failed last time, must retry
: >want-fail
../flush-cache
redo-ifchange maybe-fail || exit 68 # passed last time, no dep, no redo
rm -f want-fail

View file

@ -1 +1 @@
rm -f fail *~ .*~ rm -f fail maybe-fail want-fail *~ .*~

2
t/201-fail/maybe-fail.do Normal file
View file

@ -0,0 +1,2 @@
[ -e 'want-fail' ] && exit 1
echo x

View file

@ -1,4 +1,4 @@
*.did *.ran
*.extra *.extra
a a
b b

View file

@ -1,4 +1,4 @@
echo x >>a.did echo x >>a.ran
rm -f $2.extra rm -f $2.extra
echo foo >$2.extra echo foo >$2.extra
ln -s $2.extra $3 ln -s $2.extra $3

View file

@ -1,14 +1,14 @@
rm -f a a.extra b b.did rm -f a a.extra b b.ran
d0="" d0=""
redo a redo a
redo-ifchange b redo-ifchange b
d1=$(cat b.did) d1=$(cat b.ran)
[ "$d0" != "$d1" ] || exit 11 [ "$d0" != "$d1" ] || exit 11
# b only rebuilds if a changes # b only rebuilds if a changes
../flush-cache ../flush-cache
redo-ifchange b redo-ifchange b
d2=$(cat b.did) d2=$(cat b.ran)
[ "$d1" = "$d2" ] || exit 12 [ "$d1" = "$d2" ] || exit 12
. ../skip-if-minimal-do.sh . ../skip-if-minimal-do.sh
@ -20,7 +20,7 @@ d2=$(cat b.did)
../flush-cache ../flush-cache
redo a redo a
redo-ifchange b redo-ifchange b
d3=$(cat b.did) d3=$(cat b.ran)
[ "$d2" != "$d3" ] || exit 13 [ "$d2" != "$d3" ] || exit 13
# Explicitly check that changing a's symlink target (a.extra) does *not* # Explicitly check that changing a's symlink target (a.extra) does *not*
@ -30,5 +30,5 @@ d3=$(cat b.did)
../flush-cache ../flush-cache
touch a.extra touch a.extra
redo-ifchange b redo-ifchange b
d4=$(cat b.did) d4=$(cat b.ran)
[ "$d3" = "$d4" ] || exit 14 [ "$d3" = "$d4" ] || exit 14

View file

@ -1,3 +1,3 @@
echo x >>b.did echo x >>b.ran
redo-ifchange a redo-ifchange a
cat a >$3 cat a >$3

View file

@ -1 +1 @@
rm -f *~ .*~ a b *.extra *.did rm -f *~ .*~ a b *.extra *.ran