From f345eae2903dcdd847753b838930a41a33ed9685 Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Wed, 17 Oct 2018 01:42:32 -0400 Subject: [PATCH] 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. --- minimal/do | 3 ++- t/102-empty/clean.do | 2 +- t/102-empty/touchtest.do | 30 +++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/minimal/do b/minimal/do index 3f20bc2..b64734e 100755 --- a/minimal/do +++ b/minimal/do @@ -33,6 +33,7 @@ dirname() _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 @@ -107,7 +108,7 @@ _run_dofile() _do() { local dir="$1" target="$2" tmp="$3" - if [ ! -e "$target" ] || [ -d "$target" -a ! -e "$target.did" ]; then + 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" diff --git a/t/102-empty/clean.do b/t/102-empty/clean.do index d8246d9..799f5f4 100644 --- a/t/102-empty/clean.do +++ b/t/102-empty/clean.do @@ -1 +1 @@ -rm -f touch1 *~ .*~ +rm -f touch1 touch1-ran *~ .*~ diff --git a/t/102-empty/touchtest.do b/t/102-empty/touchtest.do index 2b60d8f..2f3d5ca 100644 --- a/t/102-empty/touchtest.do +++ b/t/102-empty/touchtest.do @@ -2,12 +2,40 @@ # between "real" redo and minimal/do, so clean it up. rm -f touch1 +# simply create touch1 echo 'echo hello' >touch1.do redo touch1 [ -e touch1 ] || exit 55 +[ "$(cat touch1)" = "hello" ] || exit 56 + +# ensure that 'redo touch1' always re-runs touch1.do even if we have +# already built touch1 in this session, and even if touch1 already exists. +echo 'echo hello2' >touch1.do +redo touch1 +[ "$(cat touch1)" = "hello2" ] || exit 57 + +# ensure that touch1 is rebuilt even if it got deleted after the last redo +# inside the same session. Also ensure that we can produce a zero-byte +# output file explicitly. rm -f touch1 echo 'touch $3' >touch1.do redo touch1 [ -e touch1 ] || exit 66 -[ -z "$(cat touch1)" ] || exit 77 +[ -z "$(cat touch1)" ] || exit 67 + +# Also test that zero bytes of output does not create the file at all, as +# opposed to creating a zero-byte file. +rm -f touch1 +echo 'touch touch1-ran' >touch1.do +redo touch1 +[ -e touch1 ] && exit 75 +[ -e touch1-ran ] || exit 76 +rm -f touch1-ran + +# Make sure that redo-ifchange *won't* rebuild touch1 if we have already +# built it, even if building it did not produce an output file. +redo-ifchange touch1 +[ -e touch1 ] && exit 77 +[ -e touch1-ran ] && exit 78 + rm -f touch1.do