apenwarr-redo/docs/redo-stamp.md
Avery Pennarun f6fe00db5c Directory reorg: move code into redo/, generate binaries in bin/.
It's time to start preparing for a version of redo that doesn't work
unless we build it first (because it will rely on C modules, and
eventually be rewritten in C altogether).

To get rolling, remove the old-style symlinks to the main programs, and
rename those programs from redo-*.py to redo/cmd_*.py.  We'll also move
all library functions into the redo/ dir, which is a more python-style
naming convention.

Previously, install.do was generating wrappers for installing in
/usr/bin, which extend sys.path and then import+run the right file.
This made "installed" redo work quite differently from running redo
inside its source tree.  Instead, let's always generate the wrappers in
bin/, and not make anything executable except those wrappers.

Since we're generating wrappers anyway, let's actually auto-detect the
right version of python for the running system; distros can't seem to
agree on what to call their python2 binaries (sigh). We'll fill in the
right #! shebang lines.  Since we're doing that, we can stop using
/usr/bin/env, which will a) make things slightly faster, and b) let us
use "python -S", which tells python not to load a bunch of extra crap
we're not using, thus improving startup times.

Annoyingly, we now have to build redo using minimal/do, then run the
tests using bin/redo.  To make this less annoying, we add a toplevel
./do script that knows the right steps, and a Makefile (whee!) for
people who are used to typing 'make' and 'make test' and 'make clean'.
2018-12-04 02:53:40 -05:00

3.4 KiB

NAME

redo-stamp - detect if the current target has meaningfully changed

SYNOPSIS

redo-stamp <$3

DESCRIPTION

Normally, when redo(1) builds a target T, all the other targets that depend on T are marked as out of date. Even if the rebuilt T is identical to the old one, all its dependents need to be rebuilt.

By calling redo-stamp from your .do script, you can tell redo that even though the current target is building, its output may turn out to be unchanged. If it hasn't, redo may then be able to avoid building other targets that depend on this target.

redo-stamp marks the current target as changed or unchanged by comparing its stdin to the input that was provided last time redo-stamp was called for this target.

The stamp data can be anything you want. Some possibilities are:

  • the actual target file contents:

      redo-stamp <$3
    
  • a list of filenames:

      find -name '*.[ch]' | sort | redo-stamp
    
  • the contents of a web page:

      curl http://example.org | redo-stamp
    

To ensure that your target gets checked every time, you might want to use redo-always(1).

DISCUSSION

While using redo-stamp is simple, the way it works is harder to explain. Deciding if a target is up to date or not is the job of redo-ifchange(1). Normally, a target is considered out of date when any of its dependencies (direct or indirect) have changed. When that happens, redo-ifchange runs the .do script for the target, which regenerates the entire dependency list, including rebuilding any dependencies as necessary.

Imagine that we have the following dependency chain:

T -> X -> Y -> Z

T depends on X, which depends on Y, which depends on Z. Now imagine someone has changed Z.

If someone runs redo-ifchange T, then redo-ifchange checks if X is up to date; to do that, it checks if Y is up to date; and to do that, it checks whether Z is up to date - which it isn't. Thus, Y is not up to date, which means X isn't, which means T isn't either, and so we need to run T.do. redo-ifchange won't directly redo X just because X is dirty; it redoes T, and T.do might eventually call redo-ifchange X if it needs to.

When using redo-stamp, the behaviour is different. Let's say Y has used redo-stamp. In the above sequence, Y is outdated because Z has changed. However, we don't know yet if Y's stamp has changed, so we don't yet know if we need to redo X, and thus we don't know if we need to redo T. We can't just run redo T, because that could waste a lot of time if it turns out T didn't need to be rebuilt after all.

What we do instead is note whether the only dependencies of T that are out of date are 'stamped' targets. If any dependencies of T are normal, out-of-date redo targets, then T needs to be rebuilt anyway; we don't have to do anything special.

If the only dependency of T that has changed is Y (a 'stamped' target), then we need to redo Y automatically in order to determine if T needs to be rebuilt. This is the only time that redo ever rebuilds a target that hasn't been explicitly asked for as part of a running .do script.

REDO

Part of the redo(1) suite.

CREDITS

The original concept for redo was created by D. J. Bernstein and documented on his web site (http://cr.yp.to/redo.html). This independent implementation was created by Avery Pennarun and you can find its source code at http://github.com/apenwarr/redo.

SEE ALSO

redo(1), redo-ifcreate(1), redo-ifchange(1), redo-always(1)