Commit graph

53 commits

Author SHA1 Message Date
Avery Pennarun
b9987433c9 Disable the tests that don't work with minimal/do.
...only when running under minimal/do, of course.

The tests in question mostly fail because they're testing particular
dependency-related behaviour, and minimal/do doesn't support dependencies,
so naturally it doesn't work.
2010-12-11 21:06:12 -08:00
Avery Pennarun
0da5c7c082 Add a redo-always command: it adds an "always dirty" dependency to your target.
This is mostly useless except when combined with redo-stamp... I think.
2010-12-11 07:02:45 -08:00
Avery Pennarun
1d26d99e0c Fix a deadlock with redo-oob.
If a checksummed target A used to exist but is now missing, and we tried to
redo-ifchange that exact file, we would unnecessarily run 'redo-oob A A';
that is, we have to build A in order to determine if A needs to be built.

The sub-targets of redo-oob aren't run with REDO_UNLOCKED, so this would
deadlock instantly.

Add an assertion to redo-oob to ensure we never try to redo-ifchange the
primary target (thus converting the deadlock into an exception).  And skip
doing redo-oob when the target is already the same as the thing we have to
check.
2010-12-11 06:16:32 -08:00
Avery Pennarun
e7f7119f2e If a checksummed file is deleted, we should still use redo-oob.
We were giving up and rebuilding the toplevel object, which did eventually
rebuild our checksummed file, but then the file turned out to be identical
to what it was before, so that nobody *else* who depended on it ended up
getting rebuilt.  So the results were indeterminate.

Now we treat it as if its dirtiness is unknown, so we build it using
redo-oob before building any of its dependencies.
2010-12-11 05:54:39 -08:00
Avery Pennarun
f702417ef3 The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty.  Eek!

Luckily, there's a safe solution.  If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.

If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.

Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed().  Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not.  Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.

...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 05:54:39 -08:00
Avery Pennarun
1355ade7c7 Correctly handle a checksummed file that depends on a non-checksummed file.
We were rebuilding the checksummed file every time because redo-ifchange was
incorrectly assuming that a child's changed_runid that's greater than my
changed_runid means I'm dirty.  But if my checked_runid is >= the child's
checked_runid, then I'm clean, because my checksum didn't change.

Clear as mud?
2010-12-11 05:54:39 -08:00
Avery Pennarun
22617d335c Half-support for using file checksums instead of stamps.
A new redo-stamp program takes whatever you give it as stdin and uses it to
calculate a checksum for the current target.  If that checksum is the same
as last time, then we consider the target to be unchanged, and we set
checked_runid and stamp, but leave changed_runid alone.  That will make
future callers of redo-ifchange see this target as unmodified.

However, this is only "half" support because by the time we run the .do
script that calls redo-stamp, it's too late; the caller is a dependant of
the stamped program, which is already being rebuilt, even if redo-stamp
turns out to say that this target is unchanged.

The other half is coming up.
2010-12-11 05:54:37 -08:00
Avery Pennarun
59201dd7a0 $3 and stdout no longer refer to the same file.
This is slightly inelegant, as the old style
	echo foo
	echo blah
	chmod a+x $3

doesn't work anymore; the stuff you wrote to stdout didn't end up in $3.
You can rewrite it as:
	exec >$3
	echo foo
	echo blah
	chmod a+x $3

Anyway, it's better this way, because now we can tell the difference between
a zero-length $3 and a nonexistent one.  A .do script can thus produce
either one and we'll either delete the target or move the empty $3 to
replace it, whichever is right.

As a bonus, this simplifies our detection of whether you did something weird
with overlapping changes to stdout and $3.
2010-12-11 00:29:04 -08:00
Avery Pennarun
f6d11d5411 If a user manually changes a generated file, don't ever overwrite it.
That way the user can modify an auto-generated 'compile' script, for
example, and it'll stay modified.

If they delete the file, we can then generate it for them again.

Also, we have to warn whenever we're doing this, or people might think it's
a bug.
2010-12-10 22:43:11 -08:00
Avery Pennarun
0126f6be1e Don't wipe the timestamp when a target fails to redo.
It's really a separate condition.  And since we're not removing the target
*file* in case of error - we update it atomically, and keeping it is better
than losing it - there's no reason to wipe the timestamp in that case
either.

However, we do need to know that the build failed, so that anybody else
(especially in a parallel build) who looks at that target knows that it
died.  So add a separate flag just for that.
2010-12-10 22:41:11 -08:00
Avery Pennarun
b86a32d33d flush-cache.sh: for speed, disable sqlite's synchronous mode. 2010-12-10 00:50:52 -08:00
Avery Pennarun
9e36106642 sqlite3: configure the timeout explicitly.
In flush-cache.sh, we have to do this, because the sqlite3 command-line tool
sets it to zero.  Inevitably during parallel testing, it'll end up
contending for a lock, and we really want it to wait a bit.

In state.py, it's not as important since the default is nonzero.  But
python-sqlite3's default of 5 seconds makes me a little too nervous; I can
imagine a disk write waiting for more than 5 seconds sometime.  So let's use
60 instead.
2010-12-10 00:50:52 -08:00
Avery Pennarun
a62bd50d44 Switch state.py to use sqlite3 instead of filesystem-based stamps.
It passes all tests when run serialized, but still gives weird errors
(OperationalError: database is locked) when run with -j5.  sqlite3 shouldn't
be barfing just because the database is locked, since the default timeout is
5 seconds, and it's dying *way* faster than that.
2010-12-10 00:50:52 -08:00
Avery Pennarun
8dad223225 flush-cache: run it as a separate program, not using 'source'
That way it doesn't clutter up 'redo -x' as much.
2010-12-10 00:50:52 -08:00
Avery Pennarun
0979a6e666 t/passfailtest.do: just return exit codes, don't print messages.
The exit code numbers are useful enough, and the messages are the sort of
thing that might turn into lies eventually.
2010-12-06 03:12:02 -08:00
Avery Pennarun
8953260d28 deps/test1.do: fix an == vs. =
In sh's [] command, you should use =, not ==.  I got away with this because
bash accepts ==, but that's non-portable.
2010-11-27 21:48:43 -08:00
Avery Pennarun
a5855641f8 This tests the chdir-related bug from the previous commit. 2010-11-25 06:37:24 -08:00
Avery Pennarun
f3413c0f7c doublestatic: fix dependencies if two files depend on one non-generated file.
If a and b both depend on c, and c is a static (non-generated) file that has
changed since the last successful build of a and b, we would try to redo
a, but would forget to redo b.  Now it does both.
2010-11-24 04:52:30 -08:00
Avery Pennarun
0ec15eeb09 If a target's .do file disappears, don't forget to stamp it.
If a file previously was generated but now isn't (ie. its .do file
disappears), we would never re-stamp that target, and so all its
dependencies would rebuild continually.
2010-11-24 03:44:37 -08:00
Avery Pennarun
60f5446733 Correctly handle dependencies for "cd somewhere; redo-ifchange somefile"
We would build 'somefile' correctly the first time, but we wouldn't
attach the dependency on somefile to the right $TARGET, so our target would
not auto-rebuild in the future based on somefile.
2010-11-24 03:06:33 -08:00
Avery Pennarun
984ad747f8 Remove special case for "dirname" -> "dirname/all"
It actually decreases readability of the .do files - by not making it
explicit when you're going into a subdir.

Plus it adds ambiguity: what if there's a dirname.do *and* a dirname/all?
We could resolve the ambiguity if we wanted, but that adds more code, while
taking out this special case makes *less* code and improves readability.
I think it's the right way to go.
2010-11-24 02:48:27 -08:00
Avery Pennarun
282bb0488e If the created target is a directory, it's okay for the .do to create it.
Normally, creating the target $1 yourself is bad; create $3 instead.  But if
$1 is a directory, we'll allow it.  That way 'redo subdir' can call
subdir.do, and subdir.do can both create the directory *and* run a bunch of
sub-.do files on it.
2010-11-24 02:30:54 -08:00
Avery Pennarun
83dd52c209 Targets created from stdout should be rw-, not rwx.
I had forgotten to pass the create mode to open().  Oops!
2010-11-24 02:26:15 -08:00
Avery Pennarun
77eacf1423 Fix some missing 'clean.do' rules. 2010-11-23 01:12:46 -08:00
Avery Pennarun
ac36c5bbb1 t/deps/dirtest: test correct dependency checking for targets named 'dirname'
We had a bug (fixed in the previous commit) where doing 'redo-ifchange
dirname' (which runs dirname/all.do) would not create the stamp correctly,
so that it would always show up as dirty.

It's a little bit complicated to simulate, but this does it.
2010-11-23 01:08:32 -08:00
Avery Pennarun
3fcd677428 Add t/deps/basic, to test basic autodependency behaviour.
Unfortunately it failed before the previous patch, so that's why this test
is needed :(

The test is a little ugly, because the bug I'm testing for didn't happen
except if you ran 'redo' two times in a row, not two times inside the same
redo session.  That's because dependency caching inside the one session
prevents the accidental rebuild.
2010-11-22 22:53:40 -08:00
Avery Pennarun
6d767e2a65 user-friendliness sanity checks: catch common mistakes regarding $1/$2/$3.
.do files should never modify $1, and should write to *either* $3 or stdout,
but not both.  If they write to both, it's probably because they forgot to
redirect stdout to stderr, a very easy mistake to make but a hard one to
detect.

Now redo detects it for you and prints an informative message.
2010-11-22 04:43:33 -08:00
Avery Pennarun
660e26c276 A test for the previous redo-ifchange bug. 2010-11-21 07:15:48 -08:00
Avery Pennarun
4d47b5ec7f Add a new test for filenames with spaces. 2010-11-21 06:20:16 -08:00
Avery Pennarun
e8584c8d76 Add a new passfailtest.
This tests that the target file isn't removed or changed if building fails.
2010-11-21 06:12:27 -08:00
Avery Pennarun
39ef065443 Refactor all.do and test.do in various directories.
Now 'redo test' runs the tests, but 'redo t' just builds the programs.

Also removed wvtest stuff; we're not really using it properly anyway and
it's not helping our testing right now.  It might come back later.
2010-11-21 05:47:48 -08:00
Avery Pennarun
27407f8f8e t/all.do: make sure the subdir all.do's always run.
...not just when their dependencies are dirty.  Some of them want to do some
explicit checks of redo's behaviour.
2010-11-21 05:39:00 -08:00
Avery Pennarun
b19a918894 Test for the previous bugfix.
This fails if you make test *twice* without the preceding patch.
Unfortunately I couldn't find a good way to make it fail if you only make
test once.
2010-11-21 04:41:03 -08:00
Avery Pennarun
de042fc2f2 t/curse: add a Makefile so we can compare speed when using GNU make.
redo: 5.4s
redo -j4: 3.0s
make: 2.3s
make -j4: 1.4s
make SHELL=/bin/dash: 1.2s
make SHELL=/bin/dash -j4: 0.83s

We have some distance to go yet.  Of course, redo is still written in
python, not C, so it's very expensive, and the on-disk dependency store is
very inefficient.
2010-11-21 00:31:48 -08:00
Avery Pennarun
2f5814c0fe Add curse/all to t/all, now that it passes. 2010-11-19 07:33:45 -08:00
Avery Pennarun
362ca2997a A whole bunch of cleanups to state.Lock.
Now t/curse passes again when parallelized (except for the countall
mismatch, since we haven't fixed the source of that problem yet).  At least
it's consistent now.

There's a bunch of stuff rearranged in here, but the actual important
problem was that we were doing unlink() on the lock fifo even if ENXIO,
which meant a reader could connect in between ENXIO and unlink(), and thus
never get notified of the disconnection.  This would cause the build to
randomly freeze.
2010-11-19 06:07:41 -08:00
Avery Pennarun
65d4639b48 t/curse: test that 'redo' (not redo-ifchange) always redoes a command.
...if the containing .do file is getting redone at all, of course.

Currently passes in serial mode, fails in parallel.
2010-11-19 02:20:17 -08:00
Avery Pennarun
ec6f61949b t/curse: test to make sure the same file isn't generated more than once.
redo currently passes this when running serially, but not in parallel.
2010-11-19 00:55:36 -08:00
Avery Pennarun
9b23b2c67a Add t/curse, a multi-level dependency build that really aggravates redo.
...because it seems my locking isn't very good.  It exposes annoying
problems involving rebuilding the same files more than once, screwing up
stamp files with redo -j, and being unnecessarily slow when checking
dependencies.  So it's a pretty good test considering how simple it is.

Didn't add it to t/all.do yet, because it would fail.
2010-11-19 00:28:16 -08:00
Avery Pennarun
eae3e7cdef Add t/example, a basic example build environment suitable for a tutorial. 2010-11-18 22:48:46 -08:00
Avery Pennarun
b9853d3858 minimal/do: handle nonzero exit codes and set $1/$2 correctly.
Also add some tests to confirm this.
2010-11-17 19:07:27 -08:00
Avery Pennarun
c7585558ef If the .do script deletes $3, don't die. 2010-11-17 17:55:16 -08:00
Avery Pennarun
abbde40a4f Add README.md and LICENSE.
LGPLv2, by the way.
2010-11-17 00:53:58 -08:00
Avery Pennarun
c1f09f564b Support for default.*.do rules.
I *think* this was the last missing part from djb's spec.  Certainly it's an
important one for any real project.
2010-11-16 03:04:11 -08:00
Avery Pennarun
4243f31e1b Add minimal/do, a stripped-down redo implementation in 977 bytes of sh.
This could be good for distributing with your packages, so that people who
don't have redo installed can at least build it.  Also, we could use it for
building redo itself.

Will surely need to get slightly bigger as I inevitably discover I've
forgotten a critical feature.
2010-11-16 00:27:52 -08:00
Avery Pennarun
534dd9813f t/*.do: add some time delays.
These only take effect if you export SLEEP=1.  Useful for testing
parallelism.
2010-11-13 02:17:22 -08:00
Avery Pennarun
edd8382a52 Change the default rule name from 'it' to 'all'.
This is a departure from how djb seems to have it set up, but I just like it
better.  It's more like the reasonably-common Makefile standard.  (Although
what make *actually* does is just use the first target declared in the
file.)
2010-11-13 01:40:37 -08:00
Avery Pennarun
7505048093 redo-if*.py: import fewer things from helpers.
Just to keep track of how many helper functions we actually are using.  In
case I get brave and try to convert to C sometime.
2010-11-13 01:40:01 -08:00
Avery Pennarun
5417d0165a redo-ifcreate: barf if the file already exists.
I'm pretty sure this must be the intended behaviour.  It's kind of
meaningless to use this to declare a dependency on a file that might start
to exist later, if the file already exists.
2010-11-13 01:22:11 -08:00
Avery Pennarun
c57de820fb Move 'redo --ifchange' into 'redo-ifchange' to match djb's style.
It does simplify the logic of both redo.py and redo-ifchange.py, I suppose.
2010-11-13 00:47:49 -08:00