Commit graph

369 commits

Author SHA1 Message Date
Avery Pennarun
bc632982fc Split --raw-logs into --no-pretty and --no-log options.
--no-log: don't capture logs or run redo-log (same as pre-redo-log redo)
  --no-pretty: don't pretty-print logs, print @@REDO lines.

The latter is an option to both redo and redo-log.
2018-11-19 10:55:56 -05:00
Avery Pennarun
8b5a567b2e redo-log: prioritize the "foreground" process.
When running a parallel build, redo-log -f (which is auto-started by
redo) tries to traverse through the logs depth first, in the order
parent processes started subprocesses.  This works pretty well, but if
its dependencies are locked, a process might have to give up its
jobserver token while other stuff builds its dependencies.  After the
dependency finishes, the parent might not be able to get a token for
quite some time, and the logs will appear to stop.

To prevent this from happening, we can instantiate up to one "cheater"
token, only in the foreground process (the one locked by redo-log -f),
which will allow it to continue running, albeit a bit slowly (since it
only has one token out of possibly many).  When the process finishes,
we then destroy the fake token.  It gets a little complicated; see
explanation at the top of jwack.py.
2018-11-17 11:13:20 -05:00
Avery Pennarun
e10bd1a9eb redo-log: correctly indent first level of recursion.
We don't want to print "-" at all, but that doesn't mean we should
always omit indentation for the first level.
2018-11-17 10:27:44 -05:00
Avery Pennarun
5c4f710f4e Raw logs contain @@REDO lines instead of formatted data.
This makes them more reliable to parse.  redo-log can parse each line,
format and print it, then recurse if necessary.  This got a little ugly
because I wanted 'redo --raw-logs' to work, which we want to format the
output nicely, but not call redo-log.

(As a result, --raw-logs has a different meaning to redo and
redo-log, which is kinda dumb.  I should fix that.)

As an added bonus, redo-log now handles indenting of recursive logs, so
if the build was a -> a/b -> a/b/c, and you look at the log for a/b, it
can still start at the top level indentation.
2018-11-17 10:27:44 -05:00
Avery Pennarun
e1f30c2765 redo-log: status line should use actual terminal width.
This lets us pack more onto on line if the terminal is wider, and
operate correctly if it's narrower.
2018-11-17 10:27:44 -05:00
Avery Pennarun
b2411fe483 redo-log: capture and linearize the output of redo builds.
redo now saves the stderr from every .do script, for every target, into
a file in the .redo directory.  That means you can look up the logs
from the most recent build of any target using the new redo-log
command, for example:

	redo-log -r all

The default is to show logs non-recursively, that is, it'll show when a
target does redo-ifchange on another target, but it won't recurse into
the logs for the latter target.  With -r (recursive), it does.  With -u
(unchanged), it does even if redo-ifchange discovered that the target
was already up-to-date; in that case, it prints the logs of the *most
recent* time the target was generated.

With --no-details, redo-log will show only the 'redo' lines, not the
other log messages.  For very noisy build systems (like recursing into
a 'make' instance) this can be helpful to get an overview of what
happened, without all the cruft.

You can use the -f (follow) option like tail -f, to follow a build
that's currently in progress until it finishes.  redo itself spins up a
copy of redo-log -r -f while it runs, so you can see what's going on.

Still broken in this version:

- No man page or new tests yet.

- ANSI colors don't yet work (unless you use --raw-logs, which gives
  the old-style behaviour).

- You can't redirect the output of a sub-redo to a file or a
  pipe right now, because redo-log is eating it.

- The regex for matching 'redo' lines in the log is very gross.
  Instead, we should put the raw log files in a more machine-parseable
  format, and redo-log should turn that into human-readable format.

- redo-log tries to "linearize" the logs, which makes them
  comprehensible even for a large parallel build.  It recursively shows
  log messages for each target in depth-first tree order (by tracing
  into a new target every time it sees a 'redo' line).  This works
  really well, but in some specific cases, the "topmost" redo instance
  can get stuck waiting for a jwack token, which makes it look like the
  whole build has stalled, when really redo-log is just waiting a long
  time for a particular subprocess to be able to continue.  We'll need to
  add a specific workaround for that.
2018-11-17 10:27:43 -05:00
Avery Pennarun
80aafaf290 Use signal.setitimer instead of signal.alarm.
This gives us more precise timeouts, so that when _try_read hits a race
condition, we don't suffer as badly.
2018-11-17 10:27:43 -05:00
Avery Pennarun
d0607d0091 Refactor the huge README.md into the more structured mkdocs.
I also cleaned up the installation section and added links to various
competing redo implementations.

The new README.md is basically just link to the docs on
readthedocs.org, and a link to the mailing list.

These docs need a *lot* more work, but this is enough of an improvement
that I'll commit it anyway for now.
2018-11-16 05:22:09 -05:00
apenwarr
bde3b5526f
Merge pull request #22 from SeamusConnor/master
Replaced all instances of 'python' with 'python2'

I think it's quite dumb that arch linux *ever* changed the default /usr/bin/python to python3, but oh well.  This patch seems to be okay now that even debian provides a /usr/bin/python2 symlink for the last several years.
2018-11-16 02:29:12 -05:00
Avery Pennarun
baae4fe213 Move mkdocs.yml into root directory, so readthedocs.org will work. 2018-11-16 01:14:15 -05:00
Avery Pennarun
4cf156e930 Generate a basic documentation website with the mkdocs toolkit.
No content yet other than man pages.  To make the man pages render
nicely in mkdocs, I removed the static %-headers and put the code for
them into default.md.tmp.do instead.  That way, the raw input redo-*.md
files will look right in mkdocs.
2018-11-16 00:50:18 -05:00
Avery Pennarun
2eb9e91c7c .gitignore and clean.do: add minimal/.do* 2018-11-16 00:32:07 -05:00
Seamus Connor
190b4c34ff Replaced all instances of 'python' with 'python2'
On systems where 'python' refers to python3, redo
failed to launch. All invocations of python have been
made explicitly python2 invocations. All tests pass
on an Arch Linux system as of this commit.
2018-11-14 10:52:09 -08:00
Avery Pennarun
6d7020b987 options.py: typo in comment 2018-11-13 07:00:11 -05:00
Avery Pennarun
bb80118298 Cyclic dependency checker: don't give up token in common case.
The way the code was written, we'd give up our token, detect a cyclic
dependency, and then try to get our token back before exiting.  Even
with -j1, the temporary token release allowed any parent up the tree to
continue running jobs, so it would take an arbitrary amount of time
before we could exit (and report an error code to the parent).

There was no visible symptom of this except that, with -j1, t/355-deps-cyclic
would not finish until some of the later tests finished, which was
surprising.

To fix it, let's just check for a cyclic dependency first, then release
the token only once we're sure things are sane.
2018-11-13 07:00:09 -05:00
Tony Garnock-Jones
427deb199f Use os.path.realpath to allow symlinking to install
from e.g. /opt/redo/bin into /usr/local/bin (#21)
2018-11-12 23:56:38 -05:00
Alexey Shamrin
1ad6e8ca0d escape $2 in generated compile script example (#19) 2018-11-07 00:55:53 -05:00
Alexey Shamrin
59eb7e8f1e add link to projects using redo; fix t/example mention (#20)
also rename t/111-compile2 to t/111-example
2018-11-07 00:54:57 -05:00
Avery Pennarun
2a936a7574 Print a nicer error message when asked to build an empty string ('').
This happens sometimes, for example, if you do
	whatever | while read x; do
		redo-ifchange "$x"
	done
and the input contains blank lines.

We could ignore the request for blankness, but it seems like that
situation might indicate a more serious bug in your parser, so it's
probably better to just abort with a meaningful error.
2018-11-03 22:02:26 -04:00
Avery Pennarun
2023d36676 minimal/do: didn't work correctly with multi-level auto dir creation.
If we tried to build target a/b/c/d and a/b/c didn't exist yet, we
would correctly name the temp file something like a__b/c__d.tmp.  But
if a/b didn't exist yet, we named the temp file a/b__c/d.tmp, which
didn't work.  Instead, name it a/b__c__d.tmp as expected.
2018-11-02 04:27:28 -04:00
Avery Pennarun
ec72beb343 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.
2018-11-02 04:25:35 -04:00
Avery Pennarun
25d24d117f minimal/do: less aggressive 'all' default; add fake redo-{sources,targets,ood}.
If redo-ifchange is a symlink to minimal/do, and we run it from
*outside* an existing session, it shouldn't default to 'all'.

redo-sources, redo-targets, and redo-ood aren't too useful with
minimal/do, but they should exist in case someone tries to use them, so
just symlink them to /bin/true, like we do with redo-ifcreate.
2018-11-02 03:48:09 -04:00
Avery Pennarun
a14aa4c86d minimal/do whichdo: should print ../default.do if ../$1.do exists.
It would be incorrect to print ../$1.do (we only use $1.do in the
*current* directly, not prefix dirs; we only use default*.do in
those).  However, when we found ../default.do, we forgot to print it,
because of a silly logic error.
2018-11-02 03:13:45 -04:00
Avery Pennarun
7b8fda5e18 minimal/do: add redo-whichdo support and internal unit tests.
Adding redo-whichdo wasn't so hard, except that it exposed a bunch of
mistakes in the way minimal/do was choosing .do files.  Most of the
wrong names it tried didn't matter (since they're very unlikely to
exist) except that they produce the wrong redo-whichdo output.

Debugging that took so much effort that I added unit tests for some
functions to make it easier to find problems in the future.

Note: this change apparently makes minimal/do about 50% slower than
before, because the _find_dofiles algorithm got less optimized (but
more readable).  It's still not very slow, and anyway, since it's
minimal/do, I figured readable/correct code probably outweighed a bit
of speed.  (Although if anyone can come up with an algorithm that's
clear *and* works better, I won't turn it down :)  I feel like I must
be doing it the hard way...)
2018-11-02 02:20:52 -04:00
Avery Pennarun
b0a6bd79f9 minimal/do: invert the sense of the -c option.
After playing with "continuable" mode for a while, it seems to me that
what most people want will be incremental builds by default (albeit
without any dependency checking to rebuild a target if sources change).
This lets you run minimal/do several times in a row to incrementally
build up your project while you're playing around.  If you want to
start over, use -c.

As a result, in test.do we now recommend using 'minimal/do -c test'
since minimal/do now strays even further from proper redo semantics
otherwise.

While we're here, update the usage message to describe what all the new
options mean.
2018-11-02 02:20:52 -04:00
Avery Pennarun
e40dc5bad2 redo-whichdo: fix a bug where the last dir was checked twice, and add tests.
When we can't find a .do file, we walk all the way back to the root
directory.  When that happens, the root directory is actually searched
twice.  This is harmless (since a .do file doesn't exist there anyway)
but causes redo-whichdo to produce the wrong output.

Also, add a test, which I forgot to do when writing whichdo in the
first place.

To make the test work from the root directory, we need a way to
initialize redo without actually creating a .redo directory.  Add a
init_no_state() function for that purpose, and split the necessary path
functions into their own module so we can avoid importing builder.py.
2018-11-02 02:20:52 -04:00
Avery Pennarun
f835becde4 redo-whichdo: updated output format.
The new format is just a list of .do files we tried, with a newline
after each one.  If we successfully found a .do file, we exit 0, else
we exit 1.

As discussed on the redo-list mailing list, it's easier to parse
without the extra cruft.  This makes users figure out $1 and $2
themselves, but that's not very hard, and maybe for the best.
2018-11-02 02:20:52 -04:00
Avery Pennarun
711b05766f Print a better message when detecting pre-existing cyclic dependencies.
We already printed an error at build time, but added the broken
dependency anyway.  If the .do script decided to succeed despite
redo-ifchange aborting, the target would be successfully created
and we'd end up with an infinite loop when running isdirty() later.

The result was still "correct", because python helpfully aborted
the infinite loop after the recursion got too deep.  But let's
explicitly detect it and print a better error message.

(Thanks to Nils Dagsson Moskopp's redo-testcases repo for exposing this
problem.  If you put a #!/bin/sh header on your .do script means you
need to run 'set -e' yourself if you want .do scripts to abort after an
error, which you almost always do, and those testcases don't, which
exposed this bug if you ran the tests twice.)
2018-11-02 02:20:52 -04:00
Avery Pennarun
d143cca7da class Lock: set lockfile = None before trying to open a file.
In case the open causes a delay and we got a KeyboardInterrupt, this
prevents a weird error from the destructor about an uninitialized variable.
2018-11-02 02:20:52 -04:00
Avery Pennarun
f4f9ed97ec t/clean.do: don't forget to run s??/clean. 2018-11-02 02:20:52 -04:00
Avery Pennarun
eb004d531e shelltest: downgrade #48 to a warning.
This is the test that
   x=y f
does *not* unset x after running f, if f is a shell function.  Apparently
that's the right thing to do, but freebsd dash 0.5.10.2 fails it.  This is
surprising because debian dash 0.5.8-2.4 passes, and it is presumably older.
Downgrade this to a warning because we want freebsd to have some cheap sh
variant that passes with redo, and nobody should be *relying* on this
insane behaviour anyway.

freebsd 11.2 sh (but not freebsd dash) fails test #24.  That one seems
rather serious, so I don't want to downgrade it to a warning.
2018-10-29 07:35:56 +00:00
Avery Pennarun
52236a3aed builder.py: don't spin while fighting for a file lock.
If we end up in builder phase 2, where we might need to
build stuff that was previously locked by someone else,
we will need to obtain a job token *and* the lock at the
same time in order to continue.  To prevent deadlocks,
we don't wait synchronously for one lock while holding the
other.

If several instances are fighting over the same lock and
there are insufficient job tokens for everyone, timing
could cause them to fight for a long time.  This seems
to happen a lot in freebsd for some reason.  To be a good
citizen, sleep for a while after each loop iteration.
This should ensure that eventually, most of the fighting
instances will be asleep by the time the next one tries to
grab the token, thus breaking the deadlock.
2018-10-29 07:31:28 +00:00
Avery Pennarun
6c81b110be Tests: use cc instead of gcc.
This fixes problems where llvm is installed without a 'gcc' alias.
2018-10-29 07:20:33 +00:00
Avery Pennarun
0fc2e46708 minimal/do: add support for -x -v -d -c options.
-x, -v, and -d are the same as redo.

-c means "continuable", which disables the feature that deletes (and
forgets) all targets at the start of each run.  This is a little risky,
since minimal/do still doesn't understand dependencies, but it allows
you to run minimal/do several times in succession, so that

    minimal/do -c a
    minimal/do -c b
is the same as
    minimal/do a b
2018-10-17 02:57:33 -04:00
Avery Pennarun
f345eae290 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:54:29 -04:00
Avery Pennarun
887df98ead builder.py: refresh the File object after obtaining the lock.
We need to create the File object to get its f.id, then lock that id.
During that gap, another instance of redo may have modified the file or
its state data, so we have to refresh it.

This fixes 'redo -j10 t/stress'.
2018-10-13 01:37:08 -04:00
Avery Pennarun
999ba4fb13 t/stress: add a test that usually triggers a bug using 950-curse.
It looks like we're updating the stamp for t/countall while another
task is replacing the file, which suggests a race condition in our
state management database.
2018-10-12 05:48:56 -04:00
Avery Pennarun
d8811601f1 Better logging for 'manual override' detection.
The first time we notice a file has been overridden, log the old and
new stamp data, which might give a hint about how this happened.

Currently if I do
    rm t/950-curse/countall
    while :; do redo -j10 t/950-curse/all --shuffle || break; done

it will end up complaining that countall has been overridden within
just a few runs, even though it definitely hasn't been.  There seems to
be someone reading a file stamp while someone else is redoing the
file, but I haven't found it yet.
2018-10-12 05:20:35 -04:00
Avery Pennarun
aa423a723f t/660-stamp: don't run at the same time as other tests in redo -j.
flush-cache can cause files affected by redo-stamp to get rebuilt
unnecessarily, which the test is specifically trying to validate.
Since other tests run flush-cache at random times when using -j, this
would cause random test failures.
2018-10-12 05:20:27 -04:00
Avery Pennarun
728a19cd52 t/*: some cleanups so switching between redo and minimal/do works.
Because the two programs use separate state databases, it helps if we
clean up some temp files between runs.  Otherwise they might think you
created some targets "by hand" and refuse to rebuild them.
2018-10-12 05:20:27 -04:00
Avery Pennarun
637521070b t/all.do: use redo instead of redo-ifchange.
I'm not quite sure what I was thinking, using redo-ifchange there, but
the result was that some tests wouldn't run if you run 'redo test'
repeatedly, even after modifying redo itself.

Also tweaked t/950-curse so that it always runs, not just the first
time.
2018-10-12 05:19:43 -04:00
Avery Pennarun
a3077a4a4d minimal/do: fix failure with paths containing spaces.
We grew a test for these at some point, but minimal/do didn't actually
pass it.

sh syntax oddity: if you say
    x=$1 y=$2
then it works fine when $1 and $2 contain spaces.  But if you say
    export x=$1 y=$2
(or "local" instead of "export") then $1 and $2 will be split on IFS,
and it won't do what you think.  I guess this is because 'export' and
'local' are like commands, and command arguments are split if not
quoted.
2018-10-12 05:18:44 -04:00
Avery Pennarun
0d174f92c3 redo-sh: downgrade failures that affected dash; add a bash warning.
I feel a little dirty doing this, but the way the code was before, redo
almost always picked bash as the shell.  bash is way too overpowered
and this led to bashisms in do scripts unnecessarily.  The two failures
in dash are things that I would really like to have, but they haven't
materialized after 6 years, so I guess we should be realistic.

To appropriately penalize bash for asking for trouble, I added a
warning about [ 1 == 1 ] syntax being valid (as opposed to the POSIX
correct [ 1 = 1 ]).  This allows dash to be selected ahead of bash.

I also moved 'sh' to the end of the list, because although it's the
weakest shell on some systems, on other systems it's just bash.  And I
put zsh in front of bash, because fewer people have zsh and we want
them to test zsh.
2018-10-12 05:18:25 -04:00
Alan Falloon
9354e78871 Null out lock vars so that __del__ gets called
The builder was holding lock variables in the loop which means that
sometimes a state.Lock object would be created for the same file-id
twice, triggering the assertion. Assign the lock variables to None to
ensure that the state.Lock objects are destroyed before creating the
next one in the loop.
2018-10-11 23:15:37 -04:00
Alan Falloon
f4b4c400b2 Handle errors on rename of target file.
[apenwarr: this is the remaining part after part of the original was
included in someone else's separate patch.]
2018-10-11 23:12:07 -04:00
Avery Pennarun
c724523473 Docs: Add missing commands to redo.md, and add redo-whichdo.md. 2018-10-11 05:56:21 -04:00
Avery Pennarun
84fb972fb7 Documentation: Fix some markdown formatting bugs. 2018-10-11 05:56:21 -04:00
Daniele Varrazzo
adbaaf38ce Use py-setproctitle to clean up ps output in redo scripts
* Change the process title with a cleaned-up version of the script
* Document the use of setproctitle in the README
2018-10-11 03:52:20 -04:00
Avery Pennarun
2affe20fb2 redo.me: missing .do in do search path description.
[Noticed by mait on github.]
2018-10-11 03:34:25 -04:00
Daniel Benamy
4c09289fb4 Fix missing blank line that breaks README.md formatting. 2018-10-11 03:30:31 -04:00