├── t ├── s60-stamp │ ├── c │ ├── bob.do │ ├── all.do │ ├── a.do │ ├── b.do │ ├── usestamp.do │ ├── ab.do │ ├── clean.do │ ├── usestamp2.do │ ├── abc.do │ ├── stampy.do │ └── .gitignore ├── 350-deps │ ├── static.in │ ├── basic │ │ ├── 1.in │ │ ├── 2.in │ │ ├── .gitignore │ │ ├── clean.do │ │ ├── default.out.do │ │ └── test.do │ ├── broken.do │ ├── t2.do │ ├── t1dep.do │ ├── override │ │ ├── a.do │ │ ├── .gitignore │ │ ├── clean.do │ │ ├── b.do │ │ └── all.do │ ├── t1a.do │ ├── genfile1.do │ ├── static1.do │ ├── static2.do │ ├── overwrite1.do │ ├── all.do │ ├── .gitignore │ ├── clean.do │ ├── ifchange-fail.do │ ├── overwrite.do │ ├── test2.do │ ├── overwrite2.do │ ├── doublestatic.do │ ├── overwrite3.do │ ├── test1.do │ └── gentest.do ├── 122-defaults-parent │ ├── x │ │ └── file │ ├── .gitignore │ ├── clean.do │ ├── inner │ │ └── default.do │ ├── inner2 │ │ └── default.do │ └── all.do ├── 130-mode │ ├── .gitignore │ ├── mode1.do │ ├── clean.do │ └── all.do ├── 201-fail │ ├── fail.do │ ├── .gitignore │ ├── clean.do │ ├── maybe-fail.do │ └── all.do ├── 260-whichdo │ ├── fakesub │ │ └── .empty │ ├── default.y.z.do │ ├── fakesub2 │ │ ├── snork.do │ │ └── default.do │ ├── all.do │ ├── defaults.do │ ├── exists.do │ └── nonexists.do ├── 101-atime │ ├── .gitignore │ ├── all.do │ ├── atime.do │ ├── clean.do │ ├── tick.py │ └── atime2.do ├── 550-chdir │ ├── .gitignore │ ├── chdir1.do │ ├── clean.do │ ├── chdir2.do │ ├── chdir3.do │ └── all.do ├── 000-set-minus-e │ ├── .gitignore │ ├── clean.do │ ├── fatal.do │ └── all.do ├── 100-args │ ├── .gitignore │ ├── noargs │ │ ├── all.do │ │ └── run.do │ ├── clean.do │ ├── all.do │ ├── default.args.do │ ├── passfail.do │ ├── test2.args.do │ └── passfailtest.do ├── 103-unicode │ ├── all.do │ ├── clean.do │ └── unicode.do ├── 140-shuffle │ ├── .gitignore │ ├── clean.do │ ├── default.x.do │ └── all.do ├── 141-keep-going │ ├── .gitignore │ ├── clean.do │ ├── default.ok.do │ ├── default.fail.do │ └── all.do ├── 203-make │ ├── x.do │ ├── y.do │ ├── default.out.do │ ├── .gitignore │ ├── clean.do │ ├── Makefile │ ├── wipe-redo.sh │ ├── whichmake.do │ └── all.do ├── 204-makeflags │ ├── noflags.do │ ├── clean.do │ ├── closefds.py │ └── all.do ├── 205-readonly │ ├── .gitignore │ ├── clean.do │ └── all.do ├── 010-jobserver │ ├── default.x.do │ ├── .gitignore │ ├── parallel2.do │ ├── clean.do │ ├── default.spin.do │ ├── serialtest.do │ ├── second.do │ ├── parallel.do │ ├── paralleltest.do │ ├── all.do │ └── first.do ├── 111-example │ ├── config.sh │ ├── .gitignore │ ├── clean.do │ ├── default.o.do │ ├── Makefile │ ├── mystr.c │ ├── hello.do │ ├── mystr.h │ ├── main.c │ ├── all.do │ └── CC.do ├── 120-defaults-flat │ ├── c.c.c.b.b.a │ ├── all.do │ ├── c.do │ ├── .gitignore │ ├── clean.do │ ├── default.c.do │ ├── default.do │ ├── default.c.c.do │ └── default.b.do ├── 121-defaults-nested │ ├── all.do │ ├── a │ │ ├── b │ │ │ ├── file.x.y.z.do │ │ │ └── default.y.z.do │ │ ├── d │ │ │ └── default.do │ │ ├── default.z.do │ │ └── default.x.y.z.do │ ├── default.do │ ├── clean.do │ ├── .gitignore │ └── test.do ├── 220-ifcreate │ ├── .gitignore │ ├── clean.do │ ├── ifcreate1.do │ ├── ifcreate2.do │ └── all.do ├── 355-deps-cyclic │ ├── a.do │ ├── b.do │ ├── clean.do │ └── all.do ├── 370-logs │ ├── .gitignore │ ├── clean.do │ ├── y.do │ ├── x.do │ ├── a │ │ └── b │ │ │ └── xlog.do │ └── all.do ├── 104-space │ ├── all.do │ ├── clean.do │ └── space dir │ │ ├── space 2.do │ │ ├── clean.do │ │ ├── .gitignore │ │ ├── space file.do │ │ └── test.do ├── 250-makedir │ ├── .gitignore │ ├── dirtest │ │ ├── .gitignore │ │ ├── dir1 │ │ │ ├── stinky.do │ │ │ └── go.do │ │ ├── t1.do │ │ ├── clean.do │ │ └── all.do │ ├── all.do │ ├── autosubdir │ │ ├── clean.do │ │ ├── default.txt.do │ │ └── all.do │ ├── makedir.do │ ├── clean.do │ └── makedir2.do ├── 640-always │ ├── .gitignore │ ├── clean.do │ ├── always1.do │ └── all.do ├── 102-empty │ ├── all.do │ ├── .gitignore │ ├── blank.do │ ├── clean.do │ ├── silencetest.do │ └── touchtest.do ├── 200-shell │ ├── all.do │ ├── .gitignore │ ├── default.vartest.do │ ├── clean.do │ ├── nonshelltest.do │ ├── vartest.do │ └── shelltest.do ├── 202-del │ ├── .gitignore │ ├── all.do │ ├── clean.do │ ├── deltest.do │ ├── default.spam1.do │ ├── default.spam2.do │ ├── deltest2.do │ ├── deltest4.do │ └── deltest3.do ├── 999-installer │ ├── .gitignore │ ├── clean.do │ └── all.do ├── 105-sympath │ ├── .gitignore │ ├── clean.do │ ├── default.dyn.do │ └── all.do ├── 950-curse │ ├── countall.do │ ├── .gitignore │ ├── default.n0.do │ ├── clean.do │ ├── default.n1.do │ ├── seq │ ├── check-1.sh │ ├── all.do │ ├── default.n2.do │ └── check-2.sh ├── 110-compile │ ├── .gitignore │ ├── clean.do │ ├── hello.do │ ├── bellow.do │ ├── yellow.do │ ├── yellow.o.do │ ├── CC.do │ ├── LD.do │ ├── hello.c │ ├── all.do │ └── hello.o.do ├── 360-symlinks │ ├── b.do │ ├── .gitignore │ ├── clean.do │ ├── a.do │ └── all.do ├── sleep ├── 351-deps-forget │ ├── clean.do │ ├── sub.do │ ├── .gitignore │ └── bork.do ├── dotparams.od ├── nothing.od ├── skip-if-minimal-do.sh ├── flush-cache.do ├── .gitignore ├── clean.do ├── stress.do ├── all.do └── flush-cache.in ├── redo ├── __init__.py ├── version │ ├── prodname │ ├── .gitattributes │ ├── all.do │ ├── .gitignore │ ├── clean.do │ ├── gitvars.pre │ ├── __init__.py │ ├── _version.py.do │ ├── vars.do │ └── gitvars.do ├── .gitignore ├── clean.do ├── py.do ├── atoi.py ├── whichpython.do ├── title.py ├── cycles.py ├── cmd_targets.py ├── cmd_sources.py ├── cmd_always.py ├── cmd_ifcreate.py ├── helpers.py ├── cmd_whichdo.py ├── cmd_ood.py ├── cmd_unlocked.py ├── sh.do ├── cmd_stamp.py └── paths.py ├── minimal ├── fakedir │ └── .empty ├── default.zz.do └── test.do ├── docs ├── t │ ├── .gitignore │ └── testitem.md ├── cookbook │ ├── c │ │ ├── redoconf │ │ ├── libhello │ │ │ ├── lib hello.ver │ │ │ ├── lib hello.list │ │ │ ├── hello.h │ │ │ └── hello.c │ │ ├── all.do │ │ ├── test.do │ │ ├── all.od │ │ ├── configure │ │ ├── .gitignore │ │ ├── clean.do │ │ ├── all.hpp │ │ ├── rc │ │ │ ├── extra.rc.od │ │ │ ├── posix.rc.od │ │ │ ├── clock_gettime.rc.od │ │ │ └── printf_lld.rc.od │ │ ├── all.h │ │ ├── monotime.h │ │ ├── when.c.do │ │ ├── clean.od │ │ ├── slow.cc │ │ ├── flagtest.c │ │ ├── default.each.do │ │ ├── flagtest.o.od │ │ ├── main.h │ │ ├── arches.do │ │ ├── sources.do │ │ ├── test.od │ │ ├── all.rc.od │ │ ├── main.c │ │ ├── hello world.list.od │ │ ├── allconfig.do │ │ ├── configure.help │ │ └── monotime.c │ ├── latex │ │ ├── paper.deps │ │ ├── discovery.txt │ │ ├── clean.do │ │ ├── .gitignore │ │ ├── default.dvi.do │ │ ├── default.pdf.do │ │ ├── default.ps.do │ │ ├── mpg.R │ │ ├── mpg.eps.do │ │ ├── all.do │ │ ├── paper.latex │ │ └── default.runtex.do │ ├── container │ │ ├── libs.diffbase │ │ ├── debian.diffbase │ │ ├── simple.image.layers │ │ ├── debian.image.layers │ │ ├── debootstrap.options │ │ ├── xclean.do │ │ ├── default.load.do │ │ ├── rdinit │ │ ├── default.rundocker.do │ │ ├── need.sh │ │ ├── clean.do │ │ ├── default.layer.do │ │ ├── default.initrd.do │ │ ├── .gitignore │ │ ├── memcalc.py │ │ ├── try_fakeroot.sh │ │ ├── debdownload.fs.do │ │ ├── libs.fs.do │ │ ├── default.sha256.do │ │ ├── default.gz.do │ │ ├── default.runlocal.do │ │ ├── default.list.do │ │ ├── debootstrap.fs.do │ │ ├── simple.fs.do │ │ ├── dockjson.py │ │ ├── fileids.py │ │ ├── debian.fs.do │ │ ├── default.runkvm.do │ │ ├── default.image.do │ │ └── template.json │ ├── hello │ │ ├── all.do │ │ ├── clean.do │ │ ├── .gitignore │ │ ├── hello.c │ │ ├── test.do │ │ └── hello.do │ ├── redoconf-simple │ │ ├── redoconf │ │ ├── .gitignore │ │ ├── clean.do │ │ ├── configure │ │ ├── all.od │ │ ├── test.do │ │ ├── ssltest.h │ │ ├── hello.cc │ │ ├── all.hpp │ │ ├── skip-if-no-cxx.sh │ │ ├── configured.do │ │ ├── hello.list.od │ │ ├── all.do │ │ ├── ssltest.c │ │ ├── configure.help │ │ ├── all.rc.od │ │ └── test.od │ ├── defaults │ │ ├── date.do │ │ ├── all.do │ │ ├── .gitignore │ │ ├── clean.do │ │ ├── test.txt.in │ │ ├── version.py.in │ │ ├── test.py │ │ ├── include │ │ │ └── version.h.in │ │ ├── version.do │ │ └── default.do │ ├── clean.do │ └── all.do ├── requirements.txt ├── .gitignore ├── doc.list.do ├── default.1.do ├── clean.do ├── extra_style.css ├── default.md.tmp.do ├── git-import.do ├── test.do ├── all.do ├── md-to-man.do ├── git-export.do ├── mkdocs.do ├── fetchcode.js ├── redo-ifcreate.md ├── redo-sources.md ├── redo-always.md ├── GettingStarted.md ├── redo-ood.md ├── redo-targets.md └── FAQInterop.md ├── bin ├── .gitignore ├── clean.do ├── all.do ├── list.do └── default.do ├── MANIFEST.in ├── test.do ├── redoconf ├── rc │ ├── Wall.rc.od │ ├── Wextra.rc.od │ ├── _init.rc.od │ ├── zdefs.rc.od │ ├── libgl.rc.od │ ├── libsdl.rc.od │ ├── libssl.rc.od │ ├── libx11.rc.od │ ├── default.required.rc.od │ ├── libpng.rc.od │ ├── libgtk2.rc.od │ ├── libqt4.rc.od │ ├── default.h.rc.od │ ├── pkg-config.rc.od │ ├── default.autolib.rc.od │ ├── libm.rc.od │ ├── run.rc.od │ ├── default.h.precompiled.rc.od │ ├── CXX.rc.od │ ├── default.hpp.precompiled.rc.od │ └── shlib.rc.od ├── run.od ├── _compile.od ├── link.od ├── rc_vars.od ├── redoconf.h.od ├── default.precompile.od ├── link-shlib.od ├── _all.rc.od ├── trycompile ├── compile.od └── utils.sh ├── .gitignore ├── Makefile ├── all.do ├── clean.do ├── contrib └── bash_completion.d │ └── redo ├── README.md ├── install.do ├── setup.py └── mkdocs.yml /t/s60-stamp/c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /redo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /minimal/fakedir/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/350-deps/static.in: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /minimal/default.zz.do: -------------------------------------------------------------------------------- 1 | : 2 | -------------------------------------------------------------------------------- /t/122-defaults-parent/x/file: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/130-mode/.gitignore: -------------------------------------------------------------------------------- 1 | mode1 -------------------------------------------------------------------------------- /t/201-fail/fail.do: -------------------------------------------------------------------------------- 1 | false 2 | -------------------------------------------------------------------------------- /t/260-whichdo/fakesub/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /redo/version/prodname: -------------------------------------------------------------------------------- 1 | redo 2 | -------------------------------------------------------------------------------- /t/101-atime/.gitignore: -------------------------------------------------------------------------------- 1 | atime2 2 | -------------------------------------------------------------------------------- /t/101-atime/all.do: -------------------------------------------------------------------------------- 1 | redo atime 2 | -------------------------------------------------------------------------------- /t/350-deps/basic/1.in: -------------------------------------------------------------------------------- 1 | this is 1 -------------------------------------------------------------------------------- /t/350-deps/broken.do: -------------------------------------------------------------------------------- 1 | false 2 | -------------------------------------------------------------------------------- /t/550-chdir/.gitignore: -------------------------------------------------------------------------------- 1 | chdir1 2 | -------------------------------------------------------------------------------- /t/s60-stamp/bob.do: -------------------------------------------------------------------------------- 1 | echo $$ 2 | -------------------------------------------------------------------------------- /docs/t/.gitignore: -------------------------------------------------------------------------------- 1 | /*.1 2 | /*.html 3 | -------------------------------------------------------------------------------- /t/000-set-minus-e/.gitignore: -------------------------------------------------------------------------------- 1 | log 2 | -------------------------------------------------------------------------------- /t/100-args/.gitignore: -------------------------------------------------------------------------------- 1 | passfail 2 | -------------------------------------------------------------------------------- /t/101-atime/atime.do: -------------------------------------------------------------------------------- 1 | redo atime2 2 | -------------------------------------------------------------------------------- /t/103-unicode/all.do: -------------------------------------------------------------------------------- 1 | redo unicode 2 | -------------------------------------------------------------------------------- /t/130-mode/mode1.do: -------------------------------------------------------------------------------- 1 | echo hello 2 | -------------------------------------------------------------------------------- /t/140-shuffle/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /t/141-keep-going/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /t/203-make/x.do: -------------------------------------------------------------------------------- 1 | ./whichmake x >&2 2 | -------------------------------------------------------------------------------- /t/203-make/y.do: -------------------------------------------------------------------------------- 1 | ./whichmake y >&2 2 | -------------------------------------------------------------------------------- /t/204-makeflags/noflags.do: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /t/205-readonly/.gitignore: -------------------------------------------------------------------------------- 1 | /rodir 2 | -------------------------------------------------------------------------------- /t/260-whichdo/default.y.z.do: -------------------------------------------------------------------------------- 1 | : 2 | -------------------------------------------------------------------------------- /t/260-whichdo/fakesub2/snork.do: -------------------------------------------------------------------------------- 1 | : 2 | -------------------------------------------------------------------------------- /t/350-deps/basic/2.in: -------------------------------------------------------------------------------- 1 | this is 2 2 | -------------------------------------------------------------------------------- /t/350-deps/t2.do: -------------------------------------------------------------------------------- 1 | echo $$ >>t2.count -------------------------------------------------------------------------------- /t/550-chdir/chdir1.do: -------------------------------------------------------------------------------- 1 | echo hello 2 | -------------------------------------------------------------------------------- /t/s60-stamp/all.do: -------------------------------------------------------------------------------- 1 | redo stamptest 2 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | list 2 | redo 3 | redo-* 4 | -------------------------------------------------------------------------------- /docs/cookbook/c/redoconf: -------------------------------------------------------------------------------- 1 | ../../../redoconf -------------------------------------------------------------------------------- /docs/cookbook/latex/paper.deps: -------------------------------------------------------------------------------- 1 | mpg.eps 2 | -------------------------------------------------------------------------------- /minimal/test.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | ./do.test 3 | -------------------------------------------------------------------------------- /t/010-jobserver/default.x.do: -------------------------------------------------------------------------------- 1 | echo world 2 | -------------------------------------------------------------------------------- /t/100-args/noargs/all.do: -------------------------------------------------------------------------------- 1 | echo RAN >$3 2 | -------------------------------------------------------------------------------- /t/103-unicode/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf *.tmp 2 | -------------------------------------------------------------------------------- /t/111-example/config.sh: -------------------------------------------------------------------------------- 1 | CFLAGS="-Wall" 2 | -------------------------------------------------------------------------------- /t/120-defaults-flat/c.c.c.b.b.a: -------------------------------------------------------------------------------- 1 | chicken 2 | -------------------------------------------------------------------------------- /t/121-defaults-nested/all.do: -------------------------------------------------------------------------------- 1 | redo test 2 | -------------------------------------------------------------------------------- /t/122-defaults-parent/.gitignore: -------------------------------------------------------------------------------- 1 | /*.log 2 | -------------------------------------------------------------------------------- /t/130-mode/clean.do: -------------------------------------------------------------------------------- 1 | rm -f mode1 *~ .*~ 2 | -------------------------------------------------------------------------------- /t/203-make/default.out.do: -------------------------------------------------------------------------------- 1 | echo $1 >$3 2 | -------------------------------------------------------------------------------- /t/204-makeflags/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ 2 | -------------------------------------------------------------------------------- /t/220-ifcreate/.gitignore: -------------------------------------------------------------------------------- 1 | ifcreate?.log 2 | -------------------------------------------------------------------------------- /t/260-whichdo/fakesub2/default.do: -------------------------------------------------------------------------------- 1 | : 2 | -------------------------------------------------------------------------------- /t/350-deps/t1dep.do: -------------------------------------------------------------------------------- 1 | # nothing to do 2 | -------------------------------------------------------------------------------- /t/355-deps-cyclic/a.do: -------------------------------------------------------------------------------- 1 | redo-ifchange b 2 | -------------------------------------------------------------------------------- /t/355-deps-cyclic/b.do: -------------------------------------------------------------------------------- 1 | redo-ifchange a 2 | -------------------------------------------------------------------------------- /t/355-deps-cyclic/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ a b 2 | -------------------------------------------------------------------------------- /t/370-logs/.gitignore: -------------------------------------------------------------------------------- 1 | pid 2 | x 3 | y 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md 2 | include LICENSE 3 | -------------------------------------------------------------------------------- /docs/cookbook/c/libhello/lib hello.ver: -------------------------------------------------------------------------------- 1 | 1.2.5 2 | -------------------------------------------------------------------------------- /docs/cookbook/container/libs.diffbase: -------------------------------------------------------------------------------- 1 | simple 2 | -------------------------------------------------------------------------------- /t/000-set-minus-e/clean.do: -------------------------------------------------------------------------------- 1 | rm -f log *~ .*~ 2 | -------------------------------------------------------------------------------- /t/101-atime/clean.do: -------------------------------------------------------------------------------- 1 | rm -f atime2 *~ .*~ 2 | -------------------------------------------------------------------------------- /t/104-space/all.do: -------------------------------------------------------------------------------- 1 | redo "space dir/test" 2 | -------------------------------------------------------------------------------- /t/104-space/clean.do: -------------------------------------------------------------------------------- 1 | redo "space dir/clean" 2 | -------------------------------------------------------------------------------- /t/104-space/space dir/space 2.do: -------------------------------------------------------------------------------- 1 | echo $$ 2 | -------------------------------------------------------------------------------- /t/120-defaults-flat/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange c d 2 | -------------------------------------------------------------------------------- /t/140-shuffle/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *.log *~ .*~ 2 | -------------------------------------------------------------------------------- /t/140-shuffle/default.x.do: -------------------------------------------------------------------------------- 1 | echo $1 >>out.log 2 | -------------------------------------------------------------------------------- /t/141-keep-going/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *.log *~ .*~ 2 | -------------------------------------------------------------------------------- /t/350-deps/basic/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.out 3 | -------------------------------------------------------------------------------- /t/350-deps/override/a.do: -------------------------------------------------------------------------------- 1 | echo hello-a >$3 2 | -------------------------------------------------------------------------------- /t/370-logs/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ all x y pid 2 | -------------------------------------------------------------------------------- /t/550-chdir/clean.do: -------------------------------------------------------------------------------- 1 | rm -f chdir1 *~ .*~ 2 | -------------------------------------------------------------------------------- /bin/clean.do: -------------------------------------------------------------------------------- 1 | rm -f redo redo-* list whichpython 2 | -------------------------------------------------------------------------------- /docs/cookbook/c/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange all.each 2 | -------------------------------------------------------------------------------- /docs/cookbook/c/libhello/lib hello.list: -------------------------------------------------------------------------------- 1 | hello.c 2 | -------------------------------------------------------------------------------- /docs/cookbook/c/test.do: -------------------------------------------------------------------------------- 1 | redo-ifchange test.each 2 | -------------------------------------------------------------------------------- /docs/cookbook/hello/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange hello 2 | -------------------------------------------------------------------------------- /docs/cookbook/hello/clean.do: -------------------------------------------------------------------------------- 1 | rm -f hello *~ .*~ 2 | -------------------------------------------------------------------------------- /t/111-example/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | CC 3 | hello 4 | -------------------------------------------------------------------------------- /t/141-keep-going/default.ok.do: -------------------------------------------------------------------------------- 1 | echo $2 >>out.log 2 | -------------------------------------------------------------------------------- /t/250-makedir/.gitignore: -------------------------------------------------------------------------------- 1 | makedir.log 2 | makedir 3 | -------------------------------------------------------------------------------- /t/350-deps/t1a.do: -------------------------------------------------------------------------------- 1 | redo-ifchange t1dep 2 | echo $$ 3 | -------------------------------------------------------------------------------- /t/640-always/.gitignore: -------------------------------------------------------------------------------- 1 | always1 2 | always1.log 3 | -------------------------------------------------------------------------------- /docs/cookbook/c/all.od: -------------------------------------------------------------------------------- 1 | redo-ifchange "hello world" 2 | -------------------------------------------------------------------------------- /docs/cookbook/container/debian.diffbase: -------------------------------------------------------------------------------- 1 | debootstrap 2 | -------------------------------------------------------------------------------- /docs/cookbook/hello/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | *~ 3 | .*~ 4 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/redoconf: -------------------------------------------------------------------------------- 1 | ../../../redoconf -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs>=1.0.4 2 | mkdocs-exclude 3 | -------------------------------------------------------------------------------- /redo/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | sh 3 | whichpython 4 | py 5 | -------------------------------------------------------------------------------- /redo/version/.gitattributes: -------------------------------------------------------------------------------- 1 | gitvars.pre export-subst 2 | -------------------------------------------------------------------------------- /redo/version/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange vars _version.py 2 | -------------------------------------------------------------------------------- /t/102-empty/all.do: -------------------------------------------------------------------------------- 1 | redo silencetest touchtest blank 2 | -------------------------------------------------------------------------------- /t/104-space/space dir/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ "space 2" 2 | -------------------------------------------------------------------------------- /t/111-example/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *.tmp *~ *.o hello CC 2 | -------------------------------------------------------------------------------- /t/200-shell/all.do: -------------------------------------------------------------------------------- 1 | redo nonshelltest shelltest vartest 2 | -------------------------------------------------------------------------------- /t/202-del/.gitignore: -------------------------------------------------------------------------------- 1 | deltest2 2 | /destruct 3 | /x 4 | -------------------------------------------------------------------------------- /t/203-make/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.out 3 | whichmake 4 | -------------------------------------------------------------------------------- /t/203-make/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ *.out whichmake *.log 2 | -------------------------------------------------------------------------------- /t/220-ifcreate/clean.do: -------------------------------------------------------------------------------- 1 | rm -f ifcreate?.log *~ .*~ 2 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/.gitignore: -------------------------------------------------------------------------------- 1 | log 2 | dir1/stinky 3 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/dir1/stinky.do: -------------------------------------------------------------------------------- 1 | echo "I'm stinky" 2 | -------------------------------------------------------------------------------- /t/260-whichdo/all.do: -------------------------------------------------------------------------------- 1 | redo exists nonexists defaults 2 | -------------------------------------------------------------------------------- /t/999-installer/.gitignore: -------------------------------------------------------------------------------- 1 | install.log 2 | test.tmp 3 | -------------------------------------------------------------------------------- /docs/cookbook/container/simple.image.layers: -------------------------------------------------------------------------------- 1 | libs 2 | simple 3 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/.gitignore: -------------------------------------------------------------------------------- 1 | /out 2 | /out.* 3 | -------------------------------------------------------------------------------- /redo/version/.gitignore: -------------------------------------------------------------------------------- 1 | /vars 2 | /gitvars 3 | /_version.py 4 | -------------------------------------------------------------------------------- /t/102-empty/.gitignore: -------------------------------------------------------------------------------- 1 | touch1 2 | silence 3 | silence.do 4 | -------------------------------------------------------------------------------- /t/104-space/space dir/.gitignore: -------------------------------------------------------------------------------- 1 | /space file 2 | /space 2 3 | -------------------------------------------------------------------------------- /t/104-space/space dir/space file.do: -------------------------------------------------------------------------------- 1 | redo-ifchange "space 2" 2 | -------------------------------------------------------------------------------- /t/105-sympath/.gitignore: -------------------------------------------------------------------------------- 1 | /*.dyn 2 | /src 3 | /x 4 | /y 5 | 6 | -------------------------------------------------------------------------------- /t/111-example/default.o.do: -------------------------------------------------------------------------------- 1 | redo-ifchange CC 2 | . ./CC "$@" 3 | -------------------------------------------------------------------------------- /t/200-shell/.gitignore: -------------------------------------------------------------------------------- 1 | /nonshelltest 2 | /chicken.vartest 3 | -------------------------------------------------------------------------------- /t/201-fail/.gitignore: -------------------------------------------------------------------------------- 1 | /fail 2 | /want-fail 3 | /maybe-fail 4 | -------------------------------------------------------------------------------- /t/201-fail/clean.do: -------------------------------------------------------------------------------- 1 | rm -f fail maybe-fail want-fail *~ .*~ 2 | -------------------------------------------------------------------------------- /t/202-del/all.do: -------------------------------------------------------------------------------- 1 | redo deltest deltest2 deltest3 deltest4 2 | -------------------------------------------------------------------------------- /t/350-deps/basic/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ *.log *.out 2 | 3 | -------------------------------------------------------------------------------- /t/350-deps/override/.gitignore: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | *.log 4 | stamp 5 | -------------------------------------------------------------------------------- /t/350-deps/override/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ stamp *.log a b 2 | -------------------------------------------------------------------------------- /t/640-always/clean.do: -------------------------------------------------------------------------------- 1 | rm -f always1 always1.log *~ .*~ 2 | 3 | -------------------------------------------------------------------------------- /t/999-installer/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf test.tmp install.log *~ .*~ 2 | -------------------------------------------------------------------------------- /docs/cookbook/latex/discovery.txt: -------------------------------------------------------------------------------- 1 | It seems that \(E = m c^2\). 2 | -------------------------------------------------------------------------------- /t/100-args/clean.do: -------------------------------------------------------------------------------- 1 | rm -f passfail *~ .*~ */*~ */.*~ noargs/all 2 | -------------------------------------------------------------------------------- /t/102-empty/blank.do: -------------------------------------------------------------------------------- 1 | redo-ifchange 2 | redo-ifcreate 3 | redo 4 | -------------------------------------------------------------------------------- /t/102-empty/clean.do: -------------------------------------------------------------------------------- 1 | rm -f touch1 touch1-ran *~ .*~ silence.do 2 | -------------------------------------------------------------------------------- /t/105-sympath/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf y 2 | rm -f src x *.dyn *~ .*~ 3 | -------------------------------------------------------------------------------- /t/121-defaults-nested/a/b/file.x.y.z.do: -------------------------------------------------------------------------------- 1 | echo file $2 ${1#$2} 2 | -------------------------------------------------------------------------------- /t/121-defaults-nested/a/d/default.do: -------------------------------------------------------------------------------- 1 | echo default $2 ${1#$2} 2 | -------------------------------------------------------------------------------- /t/121-defaults-nested/a/default.z.do: -------------------------------------------------------------------------------- 1 | echo default.z $2 ${1#$2} 2 | -------------------------------------------------------------------------------- /t/201-fail/maybe-fail.do: -------------------------------------------------------------------------------- 1 | [ -e 'want-fail' ] && exit 1 2 | echo x 3 | -------------------------------------------------------------------------------- /t/202-del/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf destruct x 2 | rm -f deltest2 *~ .*~ 3 | -------------------------------------------------------------------------------- /t/202-del/deltest.do: -------------------------------------------------------------------------------- 1 | # remove an empty output file 2 | rm -f $3 3 | -------------------------------------------------------------------------------- /t/250-makedir/all.do: -------------------------------------------------------------------------------- 1 | redo makedir2 dirtest/all autosubdir/all 2 | -------------------------------------------------------------------------------- /t/250-makedir/autosubdir/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf *.tmp 2 | rm -f *~ .*~ 3 | -------------------------------------------------------------------------------- /t/950-curse/countall.do: -------------------------------------------------------------------------------- 1 | echo $1 >>out.countall 2 | echo hello 3 | -------------------------------------------------------------------------------- /docs/cookbook/container/debian.image.layers: -------------------------------------------------------------------------------- 1 | debootstrap 2 | debian 3 | -------------------------------------------------------------------------------- /redo/clean.do: -------------------------------------------------------------------------------- 1 | redo version/clean 2 | rm -f python py *.pyc */*.pyc 3 | -------------------------------------------------------------------------------- /t/105-sympath/default.dyn.do: -------------------------------------------------------------------------------- 1 | redo-ifchange src 2 | echo dynamic >$3 3 | -------------------------------------------------------------------------------- /t/110-compile/.gitignore: -------------------------------------------------------------------------------- 1 | CC 2 | LD 3 | [yb]ellow 4 | hello 5 | *.o 6 | -------------------------------------------------------------------------------- /t/121-defaults-nested/a/b/default.y.z.do: -------------------------------------------------------------------------------- 1 | echo default.y.z $2 ${1#$2} 2 | -------------------------------------------------------------------------------- /t/121-defaults-nested/default.do: -------------------------------------------------------------------------------- 1 | echo root $2 ${1#$2} "$(dirname $3)" 2 | -------------------------------------------------------------------------------- /t/141-keep-going/default.fail.do: -------------------------------------------------------------------------------- 1 | echo $2 fail >>out.log 2 | exit 1 3 | -------------------------------------------------------------------------------- /t/202-del/default.spam1.do: -------------------------------------------------------------------------------- 1 | rm -rf x 2 | mkdir x 3 | echo 'stdout' 4 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/t1.do: -------------------------------------------------------------------------------- 1 | redo-ifchange dir1/go 2 | echo $$ >>log 3 | -------------------------------------------------------------------------------- /t/s60-stamp/a.do: -------------------------------------------------------------------------------- 1 | redo-always 2 | echo a | redo-stamp 3 | echo a > $3 4 | -------------------------------------------------------------------------------- /t/s60-stamp/b.do: -------------------------------------------------------------------------------- 1 | redo-always 2 | echo b | redo-stamp 3 | echo b > $3 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /*.1 2 | /md-to-man 3 | /*.html 4 | /*.man.md 5 | /*.list 6 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ 2 | rm -rf out out.* 3 | -------------------------------------------------------------------------------- /docs/doc.list.do: -------------------------------------------------------------------------------- 1 | ls redo*.md t/*.md >$3 2 | redo-always 3 | redo-stamp <$3 4 | -------------------------------------------------------------------------------- /t/110-compile/clean.do: -------------------------------------------------------------------------------- 1 | rm -f hello [by]ellow *.o CC LD *~ .*~ 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/120-defaults-flat/c.do: -------------------------------------------------------------------------------- 1 | redo-ifchange $1.c 2 | echo c.do 3 | cat $1.c 4 | -------------------------------------------------------------------------------- /t/200-shell/default.vartest.do: -------------------------------------------------------------------------------- 1 | : ${PREFIX=not defined} 2 | echo "$PREFIX" 3 | -------------------------------------------------------------------------------- /t/202-del/default.spam2.do: -------------------------------------------------------------------------------- 1 | rm -rf x 2 | mkdir x 3 | echo 'redir' >$3 4 | 5 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/dir1/go.do: -------------------------------------------------------------------------------- 1 | redo-ifchange stinky 2 | echo $$ >>log 3 | -------------------------------------------------------------------------------- /t/350-deps/genfile1.do: -------------------------------------------------------------------------------- 1 | redo-ifchange genfile2 2 | echo $$ >>genfile.log 3 | -------------------------------------------------------------------------------- /t/350-deps/static1.do: -------------------------------------------------------------------------------- 1 | redo-ifchange static.in 2 | echo $$ >>static.log 3 | -------------------------------------------------------------------------------- /t/350-deps/static2.do: -------------------------------------------------------------------------------- 1 | redo-ifchange static.in 2 | echo $$ >>static.log 3 | -------------------------------------------------------------------------------- /test.do: -------------------------------------------------------------------------------- 1 | redo-ifchange bin/all 2 | redo minimal/test docs/test t/all all 3 | -------------------------------------------------------------------------------- /docs/default.1.do: -------------------------------------------------------------------------------- 1 | redo-ifchange md-to-man $2.md.tmp 2 | . ./md-to-man $1 $2 $3 3 | -------------------------------------------------------------------------------- /redo/version/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ *.pyc _version.py vars gitvars 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/121-defaults-nested/a/default.x.y.z.do: -------------------------------------------------------------------------------- 1 | echo default.x.y.z $2 ${1#$2} 2 | 3 | -------------------------------------------------------------------------------- /t/200-shell/clean.do: -------------------------------------------------------------------------------- 1 | rm -f broken nonshelltest shellfile chicken.vartest *~ .*~ 2 | -------------------------------------------------------------------------------- /t/250-makedir/makedir.do: -------------------------------------------------------------------------------- 1 | rm -rf "$1" 2 | mkdir $1 3 | echo $$ >>makedir.log 4 | -------------------------------------------------------------------------------- /t/360-symlinks/b.do: -------------------------------------------------------------------------------- 1 | printf x >>b.ran 2 | redo-ifchange a 3 | cat a >$3 || : 4 | -------------------------------------------------------------------------------- /t/950-curse/.gitignore: -------------------------------------------------------------------------------- 1 | *.n1 2 | *.n2 3 | *.count 4 | *.countall 5 | countall 6 | -------------------------------------------------------------------------------- /docs/cookbook/latex/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *.eps *.dvi *.ps *.pdf *~ .*~ 2 | rm -rf *.tmp 3 | -------------------------------------------------------------------------------- /t/010-jobserver/.gitignore: -------------------------------------------------------------------------------- 1 | *.end 2 | *.start 3 | *.sub 4 | *.spin 5 | *.log 6 | *.x 7 | -------------------------------------------------------------------------------- /t/110-compile/hello.do: -------------------------------------------------------------------------------- 1 | redo-ifchange LD hello.o 2 | ../sleep 1 3 | ./LD "$3" hello.o 4 | -------------------------------------------------------------------------------- /t/111-example/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | 3 | %: FORCE 4 | +redo $@ 5 | 6 | .PHONY: FORCE 7 | -------------------------------------------------------------------------------- /t/120-defaults-flat/.gitignore: -------------------------------------------------------------------------------- 1 | c 2 | c.c 3 | c.c.c 4 | c.c.c.b 5 | c.c.c.b.b 6 | d 7 | -------------------------------------------------------------------------------- /t/120-defaults-flat/clean.do: -------------------------------------------------------------------------------- 1 | rm -f c c.c c.c.c c.c.c.b c.c.c.b.b d \ 2 | *~ .*~ 3 | -------------------------------------------------------------------------------- /t/202-del/deltest2.do: -------------------------------------------------------------------------------- 1 | # delete a non-empty output file 2 | echo hello 3 | rm -f $3 4 | -------------------------------------------------------------------------------- /t/250-makedir/autosubdir/default.txt.do: -------------------------------------------------------------------------------- 1 | mkdir -p $(dirname $1) 2 | echo "hello" >$3 3 | -------------------------------------------------------------------------------- /t/350-deps/basic/default.out.do: -------------------------------------------------------------------------------- 1 | redo-ifchange $2.in 2 | echo $$ 3 | echo $$ >>$2.log 4 | -------------------------------------------------------------------------------- /t/370-logs/y.do: -------------------------------------------------------------------------------- 1 | read pid &2 4 | -------------------------------------------------------------------------------- /t/640-always/always1.do: -------------------------------------------------------------------------------- 1 | echo $$ >>always1.log 2 | echo $$ 3 | cd .. 4 | redo-always 5 | -------------------------------------------------------------------------------- /t/950-curse/default.n0.do: -------------------------------------------------------------------------------- 1 | DEPS=$(./seq 10 | sed 's/$/.n1/') 2 | redo-ifchange $DEPS 3 | -------------------------------------------------------------------------------- /t/sleep: -------------------------------------------------------------------------------- 1 | PATH=/bin:/usr/bin 2 | if [ -n "$SLEEP" ]; then 3 | exec sleep "$@" 4 | fi 5 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/date.do: -------------------------------------------------------------------------------- 1 | date +'%Y-%m-%d' >$3 2 | redo-always 3 | redo-stamp <$3 4 | -------------------------------------------------------------------------------- /docs/cookbook/latex/.gitignore: -------------------------------------------------------------------------------- 1 | *.eps 2 | *.dvi 3 | *.ps 4 | *.pdf 5 | *.tmp 6 | *~ 7 | .*~ -------------------------------------------------------------------------------- /docs/cookbook/latex/default.dvi.do: -------------------------------------------------------------------------------- 1 | redo-ifchange "$2.runtex" 2 | ln "$2.tmp/$2.dvi" "$3" 3 | -------------------------------------------------------------------------------- /t/110-compile/bellow.do: -------------------------------------------------------------------------------- 1 | redo-ifchange LD yellow.o 2 | ./LD "$3" yellow.o 3 | ../sleep 2 4 | -------------------------------------------------------------------------------- /t/110-compile/yellow.do: -------------------------------------------------------------------------------- 1 | redo-ifchange LD yellow.o 2 | ../sleep 1.5 3 | ./LD "$3" yellow.o 4 | -------------------------------------------------------------------------------- /t/110-compile/yellow.o.do: -------------------------------------------------------------------------------- 1 | redo-ifchange CC hello.c 2 | ../sleep 2 3 | cc -o $3 -c hello.c 4 | -------------------------------------------------------------------------------- /t/111-example/mystr.c: -------------------------------------------------------------------------------- 1 | 2 | #include "mystr.h" 3 | 4 | char *mystr = "Hello, world!"; 5 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ dir1/*~ dir1/.*~ dir1/stinky dir1/log log 2 | -------------------------------------------------------------------------------- /t/360-symlinks/.gitignore: -------------------------------------------------------------------------------- 1 | *.ran 2 | *.extra 3 | *.final 4 | a 5 | b 6 | *.[123] 7 | dir 8 | -------------------------------------------------------------------------------- /t/s60-stamp/usestamp.do: -------------------------------------------------------------------------------- 1 | redo-ifchange stampy 2 | echo $$ >>usestamp.log 3 | cat stampy 4 | -------------------------------------------------------------------------------- /docs/cookbook/c/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | S="$(dirname "$0")" 3 | . "$S/redoconf/configure.sh" 4 | -------------------------------------------------------------------------------- /t/010-jobserver/parallel2.do: -------------------------------------------------------------------------------- 1 | rm -f $1.start $1.end 2 | : >$1.start 3 | sleep 2 4 | : >$1.end 5 | -------------------------------------------------------------------------------- /t/111-example/hello.do: -------------------------------------------------------------------------------- 1 | DEPS="main.o 2 | mystr.o" 3 | redo-ifchange $DEPS 4 | cc -o $3 $DEPS 5 | -------------------------------------------------------------------------------- /t/200-shell/nonshelltest.do: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | $a="perly"; 3 | print "hello $a world\n"; 4 | -------------------------------------------------------------------------------- /t/350-deps/override/b.do: -------------------------------------------------------------------------------- 1 | redo-ifchange a 2 | printf '%s-%s-b\n' "$(cat a)" "$(cat stamp)" >$3 3 | -------------------------------------------------------------------------------- /t/351-deps-forget/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ want bork bork.log sub sub.log sub.warn silent.out 2 | -------------------------------------------------------------------------------- /t/950-curse/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ *.n0 *.n1 *.n2 *.tmp *.count countall *.countall 2 | 3 | 4 | -------------------------------------------------------------------------------- /t/s60-stamp/ab.do: -------------------------------------------------------------------------------- 1 | redo-ifchange a b 2 | echo "doing ab" >&2 3 | echo ab >$3 4 | touch doing_ab 5 | -------------------------------------------------------------------------------- /t/s60-stamp/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *.log usestamp usestamp2 stampy inp bob *~ .*~ a b ab abc doing_ab 2 | -------------------------------------------------------------------------------- /t/s60-stamp/usestamp2.do: -------------------------------------------------------------------------------- 1 | redo-ifchange stampy 2 | echo 2 $$ >>usestamp2.log 3 | cat stampy 4 | -------------------------------------------------------------------------------- /docs/cookbook/container/debootstrap.options: -------------------------------------------------------------------------------- 1 | --variant=minbase 2 | --include=busybox 3 | stretch 4 | -------------------------------------------------------------------------------- /docs/cookbook/container/xclean.do: -------------------------------------------------------------------------------- 1 | redo clean 2 | rm -rf debootstrap debdownload *.fakeroot 3 | 4 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange test.txt version.py \ 2 | test.py include/version.h 3 | -------------------------------------------------------------------------------- /docs/cookbook/latex/default.pdf.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange "$2.dvi" 3 | dvipdf "$2.dvi" "$3" 4 | -------------------------------------------------------------------------------- /docs/cookbook/latex/default.ps.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange "$2.dvi" 3 | dvips -o "$3" "$2.dvi" 4 | -------------------------------------------------------------------------------- /t/100-args/all.do: -------------------------------------------------------------------------------- 1 | redo test.args test2.args passfailtest noargs/run 2 | . ../skip-if-minimal-do.sh 3 | -------------------------------------------------------------------------------- /t/100-args/default.args.do: -------------------------------------------------------------------------------- 1 | [ "$1" = "test.args" ] 2 | [ "$2" = "test" ] 3 | [ "$3" != "test.args" ] 4 | -------------------------------------------------------------------------------- /t/120-defaults-flat/default.c.do: -------------------------------------------------------------------------------- 1 | redo-ifchange $1.c 2 | echo c-to-c 3 | cat $1.c 4 | ../sleep 1.3 5 | -------------------------------------------------------------------------------- /t/120-defaults-flat/default.do: -------------------------------------------------------------------------------- 1 | redo-ifchange c 2 | echo default-rule 3 | cat c 4 | ../sleep 1.4 5 | -------------------------------------------------------------------------------- /t/351-deps-forget/sub.do: -------------------------------------------------------------------------------- 1 | redo-ifchange bork 2 | echo sub 3 | echo sub >&2 4 | printf y >>$1.log 5 | -------------------------------------------------------------------------------- /t/360-symlinks/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ a b *.extra *.final *.ran dir/*.[123] *.[123] 2 | rm -rf dir 3 | -------------------------------------------------------------------------------- /t/950-curse/default.n1.do: -------------------------------------------------------------------------------- 1 | DEPS=$(./seq 100 | sed 's/$/.n2/') 2 | redo-ifchange $DEPS 3 | echo n1-$2 4 | -------------------------------------------------------------------------------- /t/s60-stamp/abc.do: -------------------------------------------------------------------------------- 1 | redo-ifchange ab c 2 | echo "doing abc" >&2 3 | echo abc >$3 4 | touch doing_abc 5 | -------------------------------------------------------------------------------- /docs/cookbook/c/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | /when.c 3 | /allconfig 4 | /arches 5 | /out 6 | /out.* 7 | /sources 8 | -------------------------------------------------------------------------------- /docs/cookbook/c/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf out out.* 2 | rm -f *~ .*~ */*~ */.*~ sources arches allconfig when.c 3 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/.gitignore: -------------------------------------------------------------------------------- 1 | date 2 | version 3 | include/version.h 4 | version.py 5 | test.txt 6 | -------------------------------------------------------------------------------- /t/100-args/passfail.do: -------------------------------------------------------------------------------- 1 | echo $$ 2 | if [ -e pleasefail ]; then 3 | exit 1 4 | else 5 | exit 0 6 | fi 7 | -------------------------------------------------------------------------------- /t/110-compile/CC.do: -------------------------------------------------------------------------------- 1 | exec >$3 2 | cat <<-EOF 3 | cc -Wall -o /dev/fd/1 -c "\$1" 4 | EOF 5 | chmod a+x $3 6 | -------------------------------------------------------------------------------- /t/120-defaults-flat/default.c.c.do: -------------------------------------------------------------------------------- 1 | redo-ifchange $1.b 2 | echo b-to-cc 3 | cat $1.b 4 | ../sleep 1.2 5 | -------------------------------------------------------------------------------- /t/122-defaults-parent/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ */*~ */.*~ *.tmp */*.tmp x/shouldfail *.log */*.log 2 | 3 | -------------------------------------------------------------------------------- /t/350-deps/overwrite1.do: -------------------------------------------------------------------------------- 1 | # this shouldn't be allowed; we're supposed to write to $3, not $1 2 | echo >$1 3 | -------------------------------------------------------------------------------- /t/351-deps-forget/.gitignore: -------------------------------------------------------------------------------- 1 | bork 2 | bork.log 3 | sub 4 | sub.log 5 | sub.warn 6 | silent.out 7 | want 8 | -------------------------------------------------------------------------------- /t/999-installer/all.do: -------------------------------------------------------------------------------- 1 | rm -rf test.tmp 2 | DESTDIR="$PWD/test.tmp" redo ../../install >install.log 2>&1 3 | -------------------------------------------------------------------------------- /docs/cookbook/c/all.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | -------------------------------------------------------------------------------- /docs/cookbook/c/rc/extra.rc.od: -------------------------------------------------------------------------------- 1 | rc_include 2 | 3 | rc_appendln CPPFLAGS "-DEXTRA_RC_INCLUDED=1" 4 | rc_save 5 | -------------------------------------------------------------------------------- /docs/cookbook/clean.do: -------------------------------------------------------------------------------- 1 | rm -f *~ .*~ 2 | for d in */clean.do; do 3 | echo "${d%.do}" 4 | done | xargs redo 5 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/clean.do: -------------------------------------------------------------------------------- 1 | rm -f date version include/version.h \ 2 | version.py test.txt *~ .*~ 3 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | S="$(dirname "$0")" 3 | . "$S/redoconf/configure.sh" 4 | -------------------------------------------------------------------------------- /t/100-args/test2.args.do: -------------------------------------------------------------------------------- 1 | [ "$1" = "test2.args" ] 2 | [ "$2" = "test2.args" ] 3 | [ "$3" != "test2.args" ] 4 | -------------------------------------------------------------------------------- /t/111-example/mystr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MYSTR_H 2 | #define __MYSTR_H 3 | 4 | extern char *mystr; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /t/370-logs/x.do: -------------------------------------------------------------------------------- 1 | read pid &2 4 | rm -f y 5 | redo y 6 | -------------------------------------------------------------------------------- /t/950-curse/seq: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | i=0 3 | while [ "$i" -lt "$1" ]; do 4 | i=$(($i + 1)) 5 | echo $i 6 | done 7 | -------------------------------------------------------------------------------- /bin/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange ../redo/version/all ../redo/py ../redo/sh list 3 | xargs redo-ifchange &2 2 | echo SUSPICIOUS 3 | -------------------------------------------------------------------------------- /t/250-makedir/clean.do: -------------------------------------------------------------------------------- 1 | redo dirtest/clean autosubdir/clean 2 | rm -rf makedir 3 | rm -f *~ .*~ makedir.log 4 | 5 | -------------------------------------------------------------------------------- /t/350-deps/all.do: -------------------------------------------------------------------------------- 1 | redo test1 test2 ifchange-fail overwrite gentest doublestatic \ 2 | basic/test override/all 3 | -------------------------------------------------------------------------------- /t/203-make/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | 3 | x: 4 | +redo x1.out x2.out 5 | 6 | y: 7 | +redo x 8 | +redo y1.out y2.out 9 | -------------------------------------------------------------------------------- /t/350-deps/.gitignore: -------------------------------------------------------------------------------- 1 | t1a 2 | t2.count 3 | overwrite 4 | overwrite[123] 5 | genfile2 6 | genfile.log 7 | static.log 8 | -------------------------------------------------------------------------------- /t/950-curse/check-1.sh: -------------------------------------------------------------------------------- 1 | rm -f in.countall out.countall *.count 2 | touch in.countall out.countall 3 | echo x >x.count 4 | -------------------------------------------------------------------------------- /docs/cookbook/c/all.h: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "libhello/hello.h" 3 | #include "monotime.h" 4 | #include 5 | -------------------------------------------------------------------------------- /docs/cookbook/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("Hello, world!\n"); 5 | return 0; 6 | } -------------------------------------------------------------------------------- /t/122-defaults-parent/inner2/default.do: -------------------------------------------------------------------------------- 1 | echo "inner/default.do: PWD=$PWD '$1' '$2' '$3'" >&2 2 | # output file is left empty 3 | -------------------------------------------------------------------------------- /t/s60-stamp/stampy.do: -------------------------------------------------------------------------------- 1 | echo $$ >>stampy.log 2 | redo-ifchange inp bob 3 | cat inp 4 | cd .. 5 | redo-stamp $3 2 | cat <<-EOF 3 | OUT="\$1" 4 | shift 5 | cc -Wall -o "\$OUT" "\$@" 6 | EOF 7 | chmod a+x $3 8 | -------------------------------------------------------------------------------- /t/110-compile/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("hello, world!\n"); 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /t/200-shell/vartest.do: -------------------------------------------------------------------------------- 1 | PREFIX=/a/b/c/d/e redo chicken.vartest 2 | read x main, tag: redo-0.42d) 3 | 2021-07-27 20:48:36 -0700 4 | -------------------------------------------------------------------------------- /t/dotparams.od: -------------------------------------------------------------------------------- 1 | # call this as ". ./dotparams.od a b" from shelltest.od 2 | [ "$1" = a ] && [ "$2" = b ] && [ "$#" = 2 ] || warn 115 3 | -------------------------------------------------------------------------------- /docs/cookbook/c/libhello/hello.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | #include 3 | 4 | void hello(void) { 5 | printf("Hello, world!\n"); 6 | } -------------------------------------------------------------------------------- /t/010-jobserver/default.spin.do: -------------------------------------------------------------------------------- 1 | for d in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19; do 2 | redo $2.$d.x 3 | done 4 | echo hello 5 | -------------------------------------------------------------------------------- /t/205-readonly/clean.do: -------------------------------------------------------------------------------- 1 | [ -e rodir ] && chmod u+w rodir 2 | [ -e rodir/rwdir ] && chmod u+w rodir/rwdir 3 | rm -rf rodir 4 | rm -f *~ .*~ 5 | -------------------------------------------------------------------------------- /t/550-chdir/chdir2.do: -------------------------------------------------------------------------------- 1 | # make sure redo-ifchange records the dependency correctly if we chdir 2 | cd .. 3 | redo-ifchange 550-chdir/chdir1 4 | -------------------------------------------------------------------------------- /t/550-chdir/chdir3.do: -------------------------------------------------------------------------------- 1 | # make sure redo-ifchange records the dependency correctly if we chdir 2 | cd .. 3 | redo-ifchange 550-chdir/chdir2 4 | -------------------------------------------------------------------------------- /t/nothing.od: -------------------------------------------------------------------------------- 1 | # this shell script contains no commands. 2 | # it's used for testing the return value of '. ./nothing.od' in shelltest.od. 3 | -------------------------------------------------------------------------------- /t/skip-if-minimal-do.sh: -------------------------------------------------------------------------------- 1 | if [ -n "$DO_BUILT" ]; then 2 | echo "$REDO_TARGET: skipping: not supported in minimal/do." >&2 3 | exit 0 4 | fi 5 | -------------------------------------------------------------------------------- /docs/cookbook/c/monotime.h: -------------------------------------------------------------------------------- 1 | #ifndef __MONOTIME_H 2 | #define __MONOTIME_H 3 | 4 | long long monotime(void); 5 | 6 | #endif /* __MONOTIME_H */ 7 | -------------------------------------------------------------------------------- /redo/py.do: -------------------------------------------------------------------------------- 1 | redo-ifchange whichpython 2 | read py $3 <<-EOF 4 | #!/bin/sh 5 | exec $py "\$@" 6 | EOF 7 | chmod a+x $3 8 | -------------------------------------------------------------------------------- /redo/version/__init__.py: -------------------------------------------------------------------------------- 1 | """A module which provides current redo version information from git.""" 2 | from ._version import COMMIT, TAG, DATE 3 | -------------------------------------------------------------------------------- /t/000-set-minus-e/fatal.do: -------------------------------------------------------------------------------- 1 | rm -f log 2 | echo ok >>log 3 | this-should-cause-a-fatal-error 4 | echo fail >>log # this line should never run 5 | -------------------------------------------------------------------------------- /t/100-args/noargs/run.do: -------------------------------------------------------------------------------- 1 | rm -f all 2 | redo-ifchange # should not default to 'all' since not running from top level 3 | [ ! -e all ] || exit 11 4 | -------------------------------------------------------------------------------- /t/111-example/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mystr.h" 3 | 4 | int main() 5 | { 6 | printf("%s\n", mystr); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /t/350-deps/clean.do: -------------------------------------------------------------------------------- 1 | redo basic/clean override/clean 2 | rm -f *~ .*~ *.count t1a overwrite overwrite[123] \ 3 | genfile2 genfile.log static.log 4 | -------------------------------------------------------------------------------- /t/000-set-minus-e/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange ../../redo/sh 2 | rm -f log 3 | redo fatal >/dev/null 2>&1 || true 4 | 5 | [ "$(cat log)" = "ok" ] || exit 5 6 | -------------------------------------------------------------------------------- /t/350-deps/ifchange-fail.do: -------------------------------------------------------------------------------- 1 | if redo-ifchange broken 2>/dev/null; then 2 | echo "expected broken.do to fail, but it didn't" >&2 3 | exit 44 4 | fi 5 | -------------------------------------------------------------------------------- /docs/cookbook/container/rdinit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | busybox mount -t devtmpfs none /dev 3 | /init >/dev/ttyS1 4 | echo $? >/dev/ttyS2 5 | busybox poweroff -f 6 | -------------------------------------------------------------------------------- /redoconf/rc/Wall.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | rc_appendln CPPFLAGS "-Wall" 4 | if rc_compile cc nolink; then 5 | rc_save 6 | else 7 | rc_undo 8 | fi 9 | -------------------------------------------------------------------------------- /t/flush-cache.do: -------------------------------------------------------------------------------- 1 | redo-ifchange ../redo/whichpython $1.in 2 | read py <../redo/whichpython 3 | ( 4 | echo "#!$py" 5 | cat $1.in 6 | ) >$3 7 | chmod a+x $3 8 | -------------------------------------------------------------------------------- /docs/cookbook/c/when.c.do: -------------------------------------------------------------------------------- 1 | cat >$3 <<-EOF 2 | const char *stamp_time(void) { 3 | return "$(date +%Y-%m-%d)"; 4 | } 5 | EOF 6 | redo-always 7 | redo-stamp <$3 8 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/all.od: -------------------------------------------------------------------------------- 1 | # This script gets called from inside the out/ 2 | # directory when someone runs "redo" or "redo all". 3 | redo-ifchange hello 4 | -------------------------------------------------------------------------------- /redoconf/rc/Wextra.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/Wall.rc 2 | 3 | rc_appendln CPPFLAGS "-Wextra" 4 | if rc_compile cc nolink; then 5 | rc_save 6 | else 7 | rc_undo 8 | fi 9 | -------------------------------------------------------------------------------- /t/010-jobserver/serialtest.do: -------------------------------------------------------------------------------- 1 | # Test that -j1 really serializes all sub-redo processes. 2 | rm -f *.sub *.spin *.x first second *.start *.end 3 | redo first second 4 | -------------------------------------------------------------------------------- /t/101-atime/tick.py: -------------------------------------------------------------------------------- 1 | import time 2 | t2 = int(time.time()) + 1.0 3 | while 1: 4 | t = time.time() 5 | if t >= t2: break 6 | time.sleep(t2 - t + 0.01) 7 | -------------------------------------------------------------------------------- /t/s60-stamp/.gitignore: -------------------------------------------------------------------------------- 1 | /*.log 2 | /usestamp 3 | /stampy 4 | /inp 5 | /bob 6 | /usestamp2 7 | /a 8 | /b 9 | /ab 10 | /doing_ab 11 | /abc 12 | /doing_abc 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.redo 2 | /.do_built 3 | /.do_built.dir 4 | /minimal/.do_built 5 | /minimal/.do_built.dir 6 | /minimal/y 7 | *~ 8 | *.tmp 9 | *.did 10 | /docs.out 11 | -------------------------------------------------------------------------------- /t/.gitignore: -------------------------------------------------------------------------------- 1 | /broken 2 | /shellfile 3 | /shellfail 4 | /shelltest.warned 5 | /shelltest.failed 6 | /shlink 7 | /stress.log 8 | /symlink path 9 | /flush-cache 10 | -------------------------------------------------------------------------------- /t/220-ifcreate/ifcreate1.do: -------------------------------------------------------------------------------- 1 | if [ -e ifcreate1.dep ]; then 2 | redo-ifchange ifcreate1.dep 3 | else 4 | redo-ifcreate ifcreate1.dep 5 | fi 6 | echo $$ >>ifcreate1.log 7 | -------------------------------------------------------------------------------- /t/350-deps/overwrite.do: -------------------------------------------------------------------------------- 1 | . ../skip-if-minimal-do.sh 2 | redo overwrite1 2>&1 && exit 55 3 | redo overwrite2 2>&1 && exit 56 4 | redo overwrite3 2>&1 && exit 57 5 | exit 0 6 | -------------------------------------------------------------------------------- /docs/cookbook/latex/mpg.R: -------------------------------------------------------------------------------- 1 | library(ggplot2) 2 | 3 | qplot(mpg, wt, data = mtcars) + facet_wrap(~cyl) + theme_bw() 4 | ggsave("mpg.new.eps", width=4, height=2, units='in') 5 | -------------------------------------------------------------------------------- /redo/version/_version.py.do: -------------------------------------------------------------------------------- 1 | redo-ifchange vars 2 | echo '"""Auto-generated file with git version information."""' 3 | echo "# pylint: disable=bad-whitespace" 4 | cat vars 5 | -------------------------------------------------------------------------------- /docs/cookbook/c/clean.od: -------------------------------------------------------------------------------- 1 | # runs from the output directory 2 | rm -f *~ .*~ *.rc *.log *.gch *.stamp \ 3 | *.[oa] *.deps \ 4 | *.so *.so.* *.ver \ 5 | *.exe *.list \ 6 | hello 7 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.rundocker.do: -------------------------------------------------------------------------------- 1 | redo-ifchange "$2.load" "$2.list.sha256" 2 | ./need.sh docker 3 | read container_id <$2.list.sha256 4 | docker run "$container_id" 5 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/test.do: -------------------------------------------------------------------------------- 1 | # This is run as part of building the examples inside 2 | # the redo source tree. See all.do for details. 3 | . ./skip-if-no-cxx.sh 4 | redo out/test 5 | -------------------------------------------------------------------------------- /redoconf/rc/_init.rc.od: -------------------------------------------------------------------------------- 1 | if [ -e _flags ]; then 2 | redo-ifchange _flags 3 | cat _flags >$3 4 | redo-stamp <_flags 5 | else 6 | redo-ifcreate _flags 7 | redo-stamp /dev/null 2>&1; then 2 | redo-ifchange hello 3 | else 4 | echo "$0: No C compiler installed; skipping this test." >&2 5 | redo-ifcreate /usr/bin/cc 6 | fi 7 | -------------------------------------------------------------------------------- /docs/cookbook/latex/mpg.eps.do: -------------------------------------------------------------------------------- 1 | redo-ifchange mpg.R 2 | Rscript mpg.R >&2 3 | mv mpg.new.eps $3 4 | 5 | # Some buggy ggplot2 versions produce this 6 | # junk file; throw it away. 7 | rm -f Rplots.pdf 8 | -------------------------------------------------------------------------------- /t/130-mode/all.do: -------------------------------------------------------------------------------- 1 | umask 0022 2 | redo mode1 3 | MODE=$(../../redo/py -c \ 4 | 'import os; print(oct(os.stat("mode1").st_mode & 0o7777))') 5 | [ "$MODE" = "0644" -o "$MODE" = "0o644" ] || exit 78 6 | -------------------------------------------------------------------------------- /t/200-shell/shelltest.do: -------------------------------------------------------------------------------- 1 | set +e 2 | export SHELLTEST_QUIET=1 3 | cd .. 4 | ( . ./shelltest.od ) 5 | RV=$? 6 | case $RV in 7 | 40) exit 0 ;; 8 | 42) exit 0 ;; 9 | *) exit 1 ;; 10 | esac 11 | -------------------------------------------------------------------------------- /t/250-makedir/makedir2.do: -------------------------------------------------------------------------------- 1 | rm -f makedir.log 2 | redo makedir 3 | touch makedir/outfile 4 | ../flush-cache 5 | redo-ifchange makedir 6 | COUNT=$(wc -l >a.ran 2 | rm -f dir/$2.1 $2.2 $2.3 $2.final 3 | echo foo >$2.final 4 | ln -s $2.final $2.3 5 | ln -s "$PWD/$2.3" $2.2 6 | ln -s ../$2.2 dir/$2.1 7 | ln -s dir/$2.1 $3 8 | -------------------------------------------------------------------------------- /docs/default.md.tmp.do: -------------------------------------------------------------------------------- 1 | redo-ifchange ../redo/version/vars $2.md 2 | . ../redo/version/vars 3 | cat - $2.md <<-EOF 4 | % $2(1) Redo $TAG 5 | % Avery Pennarun 6 | % $DATE 7 | EOF 8 | -------------------------------------------------------------------------------- /docs/git-import.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | if git show-ref refs/heads/man >/dev/null; then 3 | (cd .. && git archive man) | tar -xvf - 4 | else 5 | (cd .. && git archive origin/man) | tar -xvf - 6 | fi 7 | 8 | 9 | -------------------------------------------------------------------------------- /t/110-compile/all.do: -------------------------------------------------------------------------------- 1 | if type cc >/dev/null 2>&1; then 2 | redo-ifchange hello yellow bellow 3 | else 4 | echo "$0: No C compiler installed; skipping this test." >&2 5 | redo-ifcreate /usr/bin/cc 6 | fi 7 | -------------------------------------------------------------------------------- /t/350-deps/test2.do: -------------------------------------------------------------------------------- 1 | rm -f t2.count 2 | redo t2 3 | redo t2 4 | OUT=$(cat t2.count | wc -l) 5 | . ../skip-if-minimal-do.sh 6 | if [ "$OUT" -ne 2 ]; then 7 | echo "t2: expected 2" 8 | exit 43 9 | fi 10 | -------------------------------------------------------------------------------- /t/950-curse/all.do: -------------------------------------------------------------------------------- 1 | rm -f *.n[012] countall 2 | 3 | . ./check-1.sh 4 | redo-ifchange 1.n0 2.n0 3.n0 5 | DEPS=$(./seq 10 | sed 's/$/.n1/') 6 | redo-ifchange $DEPS 7 | . ../skip-if-minimal-do.sh 8 | . ./check-2.sh 9 | -------------------------------------------------------------------------------- /docs/cookbook/container/need.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | fail=0 3 | for d in "$@"; do 4 | if ! type "$d" >/dev/null 2>/dev/null; then 5 | echo " -- missing tool: $d" >&2 6 | fail=1 7 | fi 8 | done 9 | exit "$fail" 10 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Test program for auto-generated version.py""" 3 | import version 4 | 5 | print('Version %r has build date %r' 6 | % (version.VERSION, version.DATE)) 7 | -------------------------------------------------------------------------------- /t/355-deps-cyclic/all.do: -------------------------------------------------------------------------------- 1 | # minimal/do doesn't need to "support" cyclic dependencies, because 2 | # they're always a bug in the .do scripts :) 3 | . ../skip-if-minimal-do.sh 4 | 5 | ! redo a >/dev/null 2>&1 || exit 204 6 | -------------------------------------------------------------------------------- /t/350-deps/overwrite2.do: -------------------------------------------------------------------------------- 1 | # this shouldn't be allowed; stdout is connected to $3 already, so if we 2 | # replace it *and* write to stdout, we're probably confused. 3 | echo hello world 4 | rm -f $3 5 | echo goodbye world >$3 6 | -------------------------------------------------------------------------------- /t/220-ifcreate/ifcreate2.do: -------------------------------------------------------------------------------- 1 | cd .. 2 | if [ -e 220-ifcreate/ifcreate2.dep ]; then 3 | redo-ifchange 220-ifcreate/ifcreate2.dep 4 | else 5 | redo-ifcreate 220-ifcreate/ifcreate2.dep 6 | fi 7 | echo $$ >>220-ifcreate/ifcreate2.log 8 | -------------------------------------------------------------------------------- /t/351-deps-forget/bork.do: -------------------------------------------------------------------------------- 1 | printf x >>$1.log 2 | redo-always 3 | 4 | read want >$3; exit 0 ;; 10 | *) exit 80 ;; 11 | esac 12 | -------------------------------------------------------------------------------- /docs/cookbook/container/clean.do: -------------------------------------------------------------------------------- 1 | rm -rf *~ .*~ simple libs debian \ 2 | *.fs debian.fakeroot *.gz \ 3 | *.code *.dockjson *.image *.image.gz *.initrd \ 4 | *.out *.layer *.list \ 5 | *.runkvm *.runlocal *.rundocker \ 6 | *.sha256 7 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.layer.do: -------------------------------------------------------------------------------- 1 | d=$PWD 2 | redo-ifchange "$2.fs" "$2.list" 3 | 4 | sed -e 's/ [^ ]*$//' <$2.list | 5 | ( 6 | cd "$2" 7 | "$d/try_fakeroot.sh" "$d/$2.fakeroot" \ 8 | cpio -Hustar -o 9 | ) >$3 10 | -------------------------------------------------------------------------------- /docs/test.do: -------------------------------------------------------------------------------- 1 | # We don't normally build the cookbook examples, because they're 2 | # not really part of redo itself. But build them when testing, 3 | # as a basic check that redo (and the examples) are valid. 4 | redo cookbook/all 5 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/include/version.h.in: -------------------------------------------------------------------------------- 1 | // C/C++ header file identifying the current version 2 | #ifndef __VERSION_H 3 | #define __VERSION_H 4 | 5 | #define VERSION "%VERSION%" 6 | #define DATE "%DATE%" 7 | 8 | #endif // __VERSION_H 9 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/version.do: -------------------------------------------------------------------------------- 1 | # Try to get a version number from git, if possible. 2 | if ! git describe >$3; then 3 | echo "$0: Falling back to static version." >&2 4 | echo 'UNKNOWN' >$3 5 | fi 6 | redo-always 7 | redo-stamp <$3 8 | -------------------------------------------------------------------------------- /redo/atoi.py: -------------------------------------------------------------------------------- 1 | """Simple integer conversion helper.""" 2 | 3 | def atoi(v): 4 | """Convert v to an integer, or return 0 on error, like C's atoi().""" 5 | try: 6 | return int(v or 0) 7 | except ValueError: 8 | return 0 9 | -------------------------------------------------------------------------------- /redoconf/rc/zdefs.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | x="-Wl,-z,defs" 4 | rc_appendln LDFLAGS "$x" 5 | if rc_compile cc link; then 6 | rc_save 7 | else 8 | echo "'$x' doesn't work on this platform; skipped." >&2 9 | rc_undo 10 | fi 11 | -------------------------------------------------------------------------------- /t/010-jobserver/second.do: -------------------------------------------------------------------------------- 1 | rm -f $1.start $1.end 2 | echo 'second start' >&2 3 | : >$1.start 4 | redo 2.x 5 | echo 'second sleep' >&2 6 | redo-ifchange first # wait until 'first' finishes, if it's running 7 | echo 'second end' >&2 8 | : >$1.end 9 | -------------------------------------------------------------------------------- /t/120-defaults-flat/default.b.do: -------------------------------------------------------------------------------- 1 | if [ -e "$1.a" -o -e "default${1#$2}.a" ]; then 2 | redo-ifchange "$1.a" 3 | echo a-to-b 4 | cat "$1.a" 5 | else 6 | redo-ifchange "$1.b" 7 | echo b-to-b 8 | cat "$1.b" 9 | fi 10 | ../sleep 1.1 11 | -------------------------------------------------------------------------------- /t/101-atime/atime2.do: -------------------------------------------------------------------------------- 1 | # make sure redo doesn't think merely *reading* the old file counts as 2 | # modifying it in-place. 3 | cat $1 >/dev/null 2>/dev/null || true 4 | ../../redo/py tick.py 5 | cat $1 >/dev/null 2>/dev/null || true 6 | echo hello 7 | -------------------------------------------------------------------------------- /t/clean.do: -------------------------------------------------------------------------------- 1 | /bin/ls [0-9s][0-9][0-9]*/clean.do | 2 | sed 's/\.do$//' | 3 | xargs redo 4 | 5 | rm -f broken shellfile shellfail shelltest.warned shelltest.failed shlink \ 6 | *~ .*~ stress.log flush-cache 'symlink path' 7 | rm -rf 'space home dir' 8 | -------------------------------------------------------------------------------- /docs/cookbook/latex/all.do: -------------------------------------------------------------------------------- 1 | for d in latex dvips dvipdf Rscript; do 2 | if ! type "$d" >/dev/null 2>/dev/null; then 3 | echo "$0: skipping: $d not installed." >&2 4 | exit 0 5 | fi 6 | done 7 | 8 | redo-ifchange paper.pdf paper.ps 9 | -------------------------------------------------------------------------------- /t/010-jobserver/parallel.do: -------------------------------------------------------------------------------- 1 | # We should be running in parallel with a jobserver shared with second.do. 2 | # Give second.do some time to start but not finish. 3 | sleep 1 4 | 5 | [ -e parallel2.start ] || exit 31 6 | ! [ -e parallel2.end ] || exit 32 7 | -------------------------------------------------------------------------------- /docs/cookbook/c/slow.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "main.h" 6 | 7 | int cpp_test() { 8 | std::string a = "hello ", b = "world"; 9 | return a.length() + b.length(); 10 | } 11 | -------------------------------------------------------------------------------- /redoconf/rc/libgl.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | int x = GL_VERSION_1_1; 6 | void f() { glPopMatrix(); } 7 | ' 8 | 9 | rc_pkg_detect LIBGL "gl" \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /redoconf/rc/libsdl.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | int x = SDL_INIT_TIMER; 6 | void f() { SDL_Init(0); } 7 | ' 8 | 9 | rc_pkg_detect LIBSDL "sdl" \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /t/370-logs/a/b/xlog.do: -------------------------------------------------------------------------------- 1 | read pid <../../pid 2 | 3 | # Test that log retrieval works correctly when run from a different base dir. 4 | redo-log -ru ../../x | grep -q "^$pid x stderr" || exit 45 5 | redo-log -ru ../../x | grep -q "^$pid y stderr" || exit 46 6 | -------------------------------------------------------------------------------- /redoconf/rc/libssl.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=" 4 | #include 5 | 6 | void f() { SSL_library_init(); } 7 | " 8 | 9 | rc_pkg_detect LIBSSL "libssl libcrypto" \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /redoconf/rc/libx11.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | int x = XYBitmap; 6 | void f() { XCreateRegion(); } 7 | ' 8 | 9 | rc_pkg_detect LIBX11 "x11" \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /t/350-deps/doublestatic.do: -------------------------------------------------------------------------------- 1 | rm -f static.log 2 | 3 | redo static1 static2 4 | 5 | touch static.in 6 | ../flush-cache 7 | redo-ifchange static1 static2 8 | 9 | COUNT=$(wc -l $3 10 | -------------------------------------------------------------------------------- /t/121-defaults-nested/clean.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | find . -name '*~' -exec rm -f {} \; 3 | rm -f a/b/file a/b/file.x.y.z a/b/file.y.z a/b/file.z \ 4 | a/d/file a/d/file.x.y.z a/d/file.y.z a/d/file.z \ 5 | a/file a/file.x.y.z a/file.y.z a/file.z \ 6 | file.x.y.z file.z file 7 | -------------------------------------------------------------------------------- /all.do: -------------------------------------------------------------------------------- 1 | if [ "$1,$2" != "all,all" ]; then 2 | echo "ERROR: old-style redo args detected: don't use --old-args." >&2 3 | exit 1 4 | fi 5 | 6 | # Do this first, to ensure we're using a good shell 7 | redo-ifchange redo/sh 8 | 9 | redo-ifchange bin/all docs/all 10 | -------------------------------------------------------------------------------- /docs/cookbook/c/flagtest.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | 4 | #ifdef EXTRA_RC_INCLUDED 5 | #error "rc/extra.rc should not be included when compiling flagtest.c" 6 | #endif 7 | 8 | void flag_test(void) { 9 | printf("flagtest included\n"); 10 | } 11 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/ssltest.h: -------------------------------------------------------------------------------- 1 | #ifndef __SSLTEST_H 2 | #define __SSLTEST_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | unsigned long libssl_version(); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif // __SSLTEST_H 15 | -------------------------------------------------------------------------------- /bin/list.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | 3 | redo-always 4 | ( 5 | cd ../redo 6 | for d in cmd_*.py; do 7 | d=${d#cmd_} 8 | d=${d%.py} 9 | if [ "$d" = "redo" ]; then 10 | echo redo 11 | else 12 | echo "redo-${d%.py}" 13 | fi 14 | done 15 | ) >$3 16 | redo-stamp <$3 17 | -------------------------------------------------------------------------------- /t/111-example/CC.do: -------------------------------------------------------------------------------- 1 | redo-ifchange config.sh 2 | . ./config.sh 3 | exec >$3 4 | cat <<-EOF 5 | redo-ifchange \$2.c 6 | cc $CFLAGS -MD -MF \$3.deps -o \$3 -c \$2.c 7 | read DEPS <\$3.deps 8 | rm -f \$3.deps 9 | redo-ifchange \${DEPS#*:} 10 | EOF 11 | chmod +x $3 12 | -------------------------------------------------------------------------------- /t/121-defaults-nested/.gitignore: -------------------------------------------------------------------------------- 1 | /a/b/file 2 | /a/b/file.x.y.z 3 | /a/b/file.y.z 4 | /a/b/file.z 5 | /a/d/file 6 | /a/d/file.x.y.z 7 | /a/d/file.y.z 8 | /a/d/file.z 9 | /a/file 10 | /a/file.x.y.z 11 | /a/file.y.z 12 | /a/file.z 13 | /file.x.y.z 14 | /file.z 15 | /file 16 | -------------------------------------------------------------------------------- /docs/cookbook/container/.gitignore: -------------------------------------------------------------------------------- 1 | debdownload 2 | debootstrap 3 | debian 4 | libs 5 | simple 6 | *.code 7 | *.dockjson 8 | *.fakeroot 9 | *.fs 10 | *.gz 11 | *.image 12 | *.initrd 13 | *.layer 14 | *.list 15 | *.out 16 | *.runkvm 17 | *.runlocal 18 | *.rundocker 19 | *.sha256 20 | -------------------------------------------------------------------------------- /redoconf/rc/default.required.rc.od: -------------------------------------------------------------------------------- 1 | base=${1%.required.rc} 2 | name=${base#*/} 3 | NAME=$(echo "$name" | tr 'a-z.' 'A-Z_') 4 | 5 | rc_include "$base.rc" 6 | 7 | eval v="\$$NAME" 8 | if [ -z "$v" ]; then 9 | echo "$NAME is required in order to build." >&2 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /redoconf/rc/libpng.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | const char *x = PNG_LIBPNG_VER_STRING; 6 | void f() { png_access_version_number(); } 7 | ' 8 | 9 | rc_pkg_detect LIBPNG libpng \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /t/203-make/wipe-redo.sh: -------------------------------------------------------------------------------- 1 | vars=$( 2 | env | { 3 | IFS="=" 4 | while read key value; do 5 | if [ "$key" != "${key#REDO}" ] || 6 | [ "$key" != "${key#MAKE}" ]; then 7 | echo "$key" 8 | fi 9 | done 10 | } 11 | ) 12 | echo "Wiping vars:" $vars >&2 13 | unset $vars 14 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/hello.cc: -------------------------------------------------------------------------------- 1 | #include "all.hpp" 2 | #include "ssltest.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | cout << "Hello, world!" 8 | << endl 9 | << "libssl version " 10 | << hex << libssl_version() 11 | << endl; 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/all.hpp: -------------------------------------------------------------------------------- 1 | // Precompiled header. 2 | // 3 | // Include your most commonly used, but least 4 | // frequently changing, header files here, to 5 | // speed up compilation. 6 | #ifndef __ALL_HPP 7 | 8 | #include 9 | #include 10 | 11 | #endif // __ALL_HPP 12 | -------------------------------------------------------------------------------- /redoconf/rc/libgtk2.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | int x = GTK_MAJOR_VERSION; 6 | void f() { gtk_widget_child_focus(0, 0); } 7 | ' 8 | 9 | rc_pkg_detect LIBGTK2 "gtk+-2.0 gio-2.0 gdk-2.0 gdk-pixbuf-2.0" \ 10 | rc_compile cc link "$prog" 11 | rc_save 12 | -------------------------------------------------------------------------------- /redo/whichpython.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | for py in intentionally-missing python python3 python2 python2.7; do 3 | echo "Trying: $py" 4 | cmd=$(command -v "$py" || true) 5 | out=$($cmd -c 'print("success")' 2>/dev/null) || true 6 | if [ "$out" = "success" ]; then 7 | echo $cmd >$3 8 | exit 0 9 | fi 10 | done 11 | exit 10 12 | -------------------------------------------------------------------------------- /docs/cookbook/c/default.each.do: -------------------------------------------------------------------------------- 1 | # redo $2 in each of the registered output dirs. 2 | # This way you can run commands or depend on targets like: 3 | # redo clean.each.do 4 | # redo all.each.do 5 | # etc. 6 | redo-ifchange allconfig 7 | 8 | for dir in $(cat allconfig); do 9 | echo "$dir/$2" 10 | done | xargs redo-ifchange 11 | -------------------------------------------------------------------------------- /docs/cookbook/container/memcalc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os, sys 3 | st = os.stat(sys.argv[1]) 4 | megabytes = st.st_size // 1024 // 1024 5 | # initrd size is limited to 50% of available RAM. To be safe, we'll 6 | # request at least 3x initrd size, and no less than 64M. 7 | need = megabytes * 3 + 64 8 | print("%dM" % need) 9 | -------------------------------------------------------------------------------- /docs/cookbook/c/flagtest.o.od: -------------------------------------------------------------------------------- 1 | # Demonstrate how to compile .o files using nonstandard 2 | # compiler flags. You could also do this for a whole 3 | # directory using default.o.od. 4 | rc_include all.rc 5 | 6 | src="$S/${1%.o}.c" 7 | redo-ifchange "_compile" "$src" 8 | CC="$CC" CPPFLAGS="-DFLAGTEST_SET=42" ./_compile "$3" "$1.deps" "$src" 9 | -------------------------------------------------------------------------------- /docs/cookbook/container/try_fakeroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | frfile=$1 3 | shift 4 | broken= 5 | fakeroot true 2>/dev/null || broken=1 6 | if [ -z "$broken" ] && [ -e "$frfile" ]; then 7 | redo-ifchange "$frfile" 8 | exec fakeroot -i "$frfile" "$@" 9 | elif [ -z "$broken" ]; then 10 | exec fakeroot "$@" 11 | else 12 | exec "$@" 13 | fi 14 | -------------------------------------------------------------------------------- /redoconf/rc/libqt4.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CXX.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | ' 6 | 7 | rc_pkg_detect LIBQT4 QtGui \ 8 | rc_compile cxx link "$prog" 9 | 10 | for d in "$MOC" moc-qt4 moc; do 11 | if type "$d" >/dev/null 2>&1; then 12 | rc_replaceln MOC "$d" 13 | break 14 | fi 15 | done 16 | 17 | rc_save 18 | -------------------------------------------------------------------------------- /t/203-make/whichmake.do: -------------------------------------------------------------------------------- 1 | if type gmake >/dev/null 2>/dev/null; then 2 | make=gmake 3 | elif type make >/dev/null 2>/dev/null; then 4 | make=make 5 | else 6 | # No make installed? That's okay, this test 7 | # isn't *that* important. 8 | make=: 9 | fi 10 | 11 | cat >$3 <<-EOF 12 | #!/bin/sh 13 | $make "\$@" 14 | EOF 15 | chmod a+x $3 16 | 17 | -------------------------------------------------------------------------------- /t/550-chdir/all.do: -------------------------------------------------------------------------------- 1 | . ../skip-if-minimal-do.sh 2 | 3 | rm -f chdir1 4 | redo chdir2 5 | redo chdir3 6 | 7 | ../flush-cache 8 | redo-ifchange chdir3 9 | 10 | rm -f chdir1 11 | ../flush-cache 12 | redo-ifchange chdir3 13 | [ -e chdir1 ] || exit 77 14 | 15 | rm -f chdir1 16 | ../flush-cache 17 | redo-ifchange chdir3 18 | [ -e chdir1 ] || exit 78 19 | -------------------------------------------------------------------------------- /redoconf/rc/default.h.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | base="${1#*/}" 4 | h1="${base%.rc}" 5 | h=$(echo "$h1" | sed -e 's,__,/,g') # x__y_z.h.rc.od -> 6 | H=$(echo "$h1" | tr 'a-z.' 'A-Z_') 7 | 8 | if rc_compile cc nolink "#include <$h>"; then 9 | rc_replaceln "HAVE_$H" 1 10 | else 11 | rc_replaceln "HAVE_$H" "" 12 | fi 13 | rc_save 14 | -------------------------------------------------------------------------------- /docs/cookbook/c/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H 2 | #define __MAIN_H 3 | 4 | #ifdef __cplusplus 5 | #define CDEF extern "C" 6 | #else 7 | #define CDEF 8 | #endif 9 | 10 | /* when.c */ 11 | CDEF const char *stamp_time(void); 12 | 13 | /* slow.cc */ 14 | CDEF int cpp_test(void); 15 | 16 | /* flagtest.c */ 17 | CDEF void flag_test(void); 18 | 19 | #endif /* __MAIN_H */ -------------------------------------------------------------------------------- /docs/cookbook/hello/test.do: -------------------------------------------------------------------------------- 1 | # Make sure everything has been built before we start 2 | redo-ifchange all 3 | 4 | # Ensure that the hello program, when run, says 5 | # hello like we expect. 6 | if ./hello | grep -i 'hello' >/dev/null; then 7 | echo "success" >&2 8 | exit 0 9 | else 10 | echo "missing 'hello' message!" >&2 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /t/250-makedir/autosubdir/all.do: -------------------------------------------------------------------------------- 1 | rm -rf sub.tmp sub2.tmp sub3.tmp 2 | 3 | redo-ifchange sub.tmp/test.txt 4 | [ -e sub.tmp/test.txt ] || exit 96 5 | 6 | redo-ifchange sub2.tmp/a/b/c/test.txt 7 | [ -e sub2.tmp/a/b/c/test.txt ] || exit 97 8 | 9 | mkdir -p sub3.tmp/a 10 | redo-ifchange sub3.tmp/a/b/c/test.txt 11 | [ -e sub2.tmp/a/b/c/test.txt ] || exit 98 12 | -------------------------------------------------------------------------------- /docs/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange doc.list 2 | sed 's/\.md/.1/' /dev/null 2>&1; then 6 | rc_replaceln PKG_CONFIG "$d" 7 | rc_replaceln HAVE_PKG_CONFIG 1 8 | rc_save 9 | exit 0 10 | fi 11 | done 12 | 13 | # Failed 14 | rc_replaceln HAVE_PKG_CONFIG "" 15 | rc_replaceln PKG_CONFIG "" 16 | rc_save 17 | -------------------------------------------------------------------------------- /redoconf/run.od: -------------------------------------------------------------------------------- 1 | rc_include rc/run.rc 2 | 3 | if [ -n "$CAN_RUN" ]; then 4 | cat >$3 <<-EOF 5 | #!/bin/sh -e 6 | # Run the given program, possibly under an emulator. 7 | [ -n "\$1" ] 8 | unset DISPLAY 9 | exec $RUN "\$@" 10 | EOF 11 | chmod a+x "$3" 12 | redo-stamp <$3 13 | else 14 | echo "Cannot run programs; not creating run script." >&2 15 | fi 16 | -------------------------------------------------------------------------------- /docs/cookbook/c/arches.do: -------------------------------------------------------------------------------- 1 | ( 2 | echo native 3 | echo fake-always-fails 4 | if [ -z "$NO_SLOW_TESTS" ]; then 5 | IFS=: 6 | for dir in $PATH; do 7 | for d in "$dir"/*-cc "$dir"/*-gcc; do 8 | base=${d##*/} 9 | arch=${base%-*} 10 | if [ -x "$d" ]; then echo "$arch"; fi 11 | done 12 | done 13 | fi 14 | ) >$3 15 | redo-always 16 | redo-stamp <$3 17 | -------------------------------------------------------------------------------- /docs/md-to-man.do: -------------------------------------------------------------------------------- 1 | redo-ifchange md2man.py ../redo/py 2 | if ../redo/py ./md2man.py /dev/null /dev/null >/dev/null; then 3 | echo '../redo/py ./md2man.py $2.md.tmp $2.html' 4 | else 5 | echo "Warning: md2man.py missing modules; can't generate manpages." >&2 6 | echo "Warning: try this: sudo easy_install markdown BeautifulSoup" >&2 7 | echo 'echo Skipping: $2.1 >&2' 8 | fi 9 | -------------------------------------------------------------------------------- /t/102-empty/silencetest.do: -------------------------------------------------------------------------------- 1 | # This may have been leftover from a previous run, when switching 2 | # between "real" redo and minimal/do, so clean it up. 3 | rm -f silence 4 | 5 | echo 'echo hello' >silence.do 6 | redo silence 7 | [ -e silence ] || exit 55 8 | echo 'true' >silence.do 9 | redo silence 10 | . ../skip-if-minimal-do.sh 11 | [ ! -e silence ] || exit 66 12 | rm -f silence.do 13 | -------------------------------------------------------------------------------- /docs/cookbook/c/rc/posix.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | prog=' 4 | #include 5 | 6 | struct timespec x; 7 | ' 8 | 9 | x= 10 | rc_replaceln HAVE_POSIX 1 11 | if ! rc_compile cc link "$prog"; then 12 | x="-D_XOPEN_SOURCE=500" 13 | rc_appendln CPPFLAGS "$x" 14 | if ! rc_compile cc link "$prog"; then 15 | rc_undo 16 | rc_replaceln HAVE_POSIX "" 17 | fi 18 | fi 19 | rc_save 20 | -------------------------------------------------------------------------------- /t/260-whichdo/defaults.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | 3 | a=$(cd fakesub2 && redo-whichdo d/snork) 4 | # if sh doesn't abort after the above, then it found a .do file as expected 5 | 6 | b=$(cat <$1.log 3 | 4 | # This test twiddles the same files over and over, and seems to trigger race conditions 5 | # in redo if run repeatedly with a large redo -j. 6 | for d in $(seq 25); do 7 | echo "stress test: cycle $d" >&2 8 | ./flush-cache 2>&1 9 | redo 950-curse/all 2>&1 || { rv=$?; echo "stress test: log is $1.log" >&2; exit $rv; } 10 | done 11 | -------------------------------------------------------------------------------- /docs/cookbook/latex/paper.latex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{graphicx} 3 | 4 | \title{A very brief note on relativity} 5 | \author{The Redo Contributors} 6 | 7 | \begin{document} 8 | \maketitle 9 | \tableofcontents 10 | 11 | \newpage 12 | \section{Amazing Discovery} 13 | \input{discovery.txt} 14 | 15 | \section{Irrelevant Chart} 16 | \includegraphics{mpg.eps} 17 | \end{document} 18 | -------------------------------------------------------------------------------- /docs/cookbook/c/rc/clock_gettime.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/rt.autolib.rc rc/posix.rc 2 | 3 | prog=" 4 | #include 5 | 6 | void test() { clock_gettime(CLOCK_MONOTONIC, NULL); } 7 | " 8 | 9 | rc_appendln LIBS "$LIBRT" 10 | if rc_compile cc link "$prog"; then 11 | rc_replaceln "HAVE_CLOCK_GETTIME" 1 12 | else 13 | rc_undo 14 | rc_replaceln "HAVE_CLOCK_GETTIME" "" 15 | fi 16 | rc_save 17 | -------------------------------------------------------------------------------- /redoconf/rc/default.autolib.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | base="${1#*/}" 4 | lib="${base%.autolib.rc}" 5 | LIB=$(echo "$lib" | tr 'a-z.' 'A-Z_') 6 | 7 | x="-l$lib" 8 | rc_appendln "LIB$LIB" "$x" 9 | appendln LIBS "$x" 10 | if rc_compile cc link ""; then 11 | rc_replaceln "HAVE_$LIB" 1 12 | else 13 | rc_undo 14 | rc_replaceln "HAVE_$LIB" "" 15 | rc_replaceln "LIB$LIB" "" 16 | fi 17 | rc_save 18 | -------------------------------------------------------------------------------- /t/250-makedir/dirtest/all.do: -------------------------------------------------------------------------------- 1 | rm -f log dir1/log dir1/stinky 2 | touch t1.do 3 | ../../flush-cache 4 | redo t1 5 | touch t1.do 6 | ../../flush-cache 7 | redo t1 8 | ../../flush-cache 9 | redo-ifchange t1 10 | C1="$(wc -l t1, c1=$C1, c2=$C2" >&2 15 | exit 55 16 | fi 17 | -------------------------------------------------------------------------------- /t/350-deps/basic/test.do: -------------------------------------------------------------------------------- 1 | rm -f *.out *.log 2 | 3 | ../../flush-cache 4 | redo-ifchange 1.out 2.out 5 | [ "$(cat 1.log | wc -l)" -eq 1 ] || exit 55 6 | [ "$(cat 2.log | wc -l)" -eq 1 ] || exit 56 7 | ../../flush-cache 8 | touch 1.in 9 | redo-ifchange 1.out 2.out 10 | [ "$(cat 2.log | wc -l)" -eq 1 ] || exit 58 11 | . ../../skip-if-minimal-do.sh 12 | [ "$(cat 1.log | wc -l)" -eq 2 ] || exit 57 13 | 14 | -------------------------------------------------------------------------------- /t/141-keep-going/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | . ../skip-if-minimal-do.sh 3 | 4 | rm -f out.log sort.log err.log 5 | redo --keep-going 1.ok 2.fail 3.fail 4.ok 5.ok 6.fail 7.ok >err.log 2>&1 && 6 | exit 11 # expect it to return nonzero due to failures 7 | sort out.log >sort.log 8 | 9 | expect="1 10 | 2 fail 11 | 3 fail 12 | 4 13 | 5 14 | 6 fail 15 | 7" 16 | 17 | [ "$(cat sort.log)" = "$expect" ] || exit 22 18 | -------------------------------------------------------------------------------- /docs/cookbook/c/sources.do: -------------------------------------------------------------------------------- 1 | # This file changes when the list of source files changes. 2 | # If you depend on it, you can make a target that gets 3 | # rebuilt only when it might need to reconsider the 4 | # list of available source files. 5 | find . -name '*.[ch]' -o \ 6 | -name '*.cc' -o \ 7 | -name '*.od' -o \ 8 | -name '*.list' | 9 | grep -v '^\./out\.' | 10 | sort >$3 11 | redo-always 12 | redo-stamp <$3 13 | -------------------------------------------------------------------------------- /t/350-deps/overwrite3.do: -------------------------------------------------------------------------------- 1 | # we don't delete $3 here, we just truncate and overwrite it. But redo 2 | # can detect this by checking the current file position of our stdout when 3 | # we exit, and making sure it equals either 0 or the file size. 4 | # 5 | # If it doesn't, then we accidentally wrote to *both* stdout and a separate 6 | # file, and we should get warned about it. 7 | echo hello world 8 | echo goodbye world >$3 9 | -------------------------------------------------------------------------------- /docs/cookbook/c/test.od: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-always 3 | redo-ifchange all run 4 | if [ -x ./run ]; then 5 | echo "Running: ./run ./hello\\ world" 6 | ./run './hello world' >"$1.out" 2>&1 7 | cat "$1.out" 8 | if grep -F -q 'Hello, world!' "$1.out"; then 9 | echo "-- Test successful." 10 | else 11 | echo "-- Test failed." 12 | exit 1 13 | fi 14 | else 15 | echo "Non-native platform: test skipped." 16 | fi 17 | -------------------------------------------------------------------------------- /t/110-compile/hello.o.do: -------------------------------------------------------------------------------- 1 | # This test is meant to confirm some basic redo functionality 2 | # related to static files not in the build tree. But if your 3 | # system doesn't happen to have stdio.h in the usual location, 4 | # let's not explode just for that. 5 | stdio=/usr/include/stdio.h 6 | [ -e "$stdio" ] || stdio= 7 | 8 | redo-ifchange CC hello.c $stdio 9 | redo-ifcreate stdio.h 10 | ../sleep 3 11 | ./CC hello.c 12 | -------------------------------------------------------------------------------- /docs/cookbook/c/rc/printf_lld.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/windows.h.rc rc/Wall.rc 2 | 3 | appendln CPPFLAGS "-Werror" # abort if any warnings 4 | prog=' 5 | #include 6 | void test() { printf("%lld", (long long)1); } 7 | ' 8 | 9 | x= 10 | if ! rc_compile cc link "$prog"; then 11 | x="-D__USE_MINGW_ANSI_STDIO=1" 12 | rc_appendln CPPFLAGS "$x" 13 | rc_compile cc link "$prog" 14 | fi 15 | rc_save 16 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/skip-if-no-cxx.sh: -------------------------------------------------------------------------------- 1 | # Make sure there is an out/ directory and 2 | # the configure script was run. 3 | redo-ifchange configured 4 | 5 | # Abort if we can't find a C++ compiler for 6 | # this platform. 7 | if ! (cd out && 8 | . ./redoconf.rc && 9 | rc_include rc/CXX.rc && 10 | [ -n "$HAVE_CXX" ]); then 11 | echo "$1: No C++ compiler: skipping." >&2 12 | exit 0 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /t/100-args/passfailtest.do: -------------------------------------------------------------------------------- 1 | . ../skip-if-minimal-do.sh 2 | 3 | rm -f pleasefail 4 | redo passfail 5 | [ -e passfail ] || exit 42 6 | PF1=$(cat passfail) 7 | touch pleasefail 8 | redo passfail 2>/dev/null && exit 43 9 | [ -e passfail ] || exit 44 10 | PF2=$(cat passfail) 11 | [ "$PF1" = "$PF2" ] || exit 45 12 | rm -f pleasefail 13 | redo passfail || exit 46 14 | PF3=$(cat passfail) 15 | [ "$PF1" != "$PF3" ] || exit 47 16 | -------------------------------------------------------------------------------- /redoconf/_compile.od: -------------------------------------------------------------------------------- 1 | # See compile.od for more explanation. 2 | cat >$3 <<-EOF 3 | #!/bin/sh -e 4 | # Run the C/C++ compiler. 5 | # Assumes config variables (CFLAGS, etc) are already set. 6 | t="\$1" d="\$2" i="\$3" 7 | IFS="$NL" 8 | set -f 9 | \$CC -o "\$t" \\ 10 | -MMD -MF "\$d" \\ 11 | \$CPPFLAGS \$CFLAGS \$CXXFLAGS \$FLAGS_PCH \$xCFLAGS \$OPTFLAGS \\ 12 | -c "\$i" 13 | EOF 14 | chmod a+x "$3" 15 | redo-stamp <$3 16 | -------------------------------------------------------------------------------- /t/950-curse/default.n2.do: -------------------------------------------------------------------------------- 1 | echo n2-$2 2 | echo $2 >>$2.count 3 | echo $2 >>in.countall 4 | 5 | # we deliberately use 'redo' here instead of redo-ifchange, because this *heavily* 6 | # stresses redo's locking when building in parallel. We end up with 100 7 | # different targets that all not only depend on this file, but absolutely must 8 | # acquire the lock on this file, build it atomically, and release the lock. 9 | redo countall 10 | -------------------------------------------------------------------------------- /docs/cookbook/container/debdownload.fs.do: -------------------------------------------------------------------------------- 1 | fs=${1%.fs} 2 | 3 | # let's *not* delete this directory; it's okay if previously-downloaded 4 | # excess packages hang around in case we need them later. 5 | #rm -rf "$fs" 6 | mkdir -p "$fs" 7 | redo-ifchange debootstrap.options 8 | debootstrap \ 9 | --download-only \ 10 | --keep-debootstrap-dir \ 11 | $(cat debootstrap.options) \ 12 | "$fs" >&2 13 | redo-ifchange "$fs/debootstrap/debootstrap.log" 14 | -------------------------------------------------------------------------------- /docs/cookbook/container/libs.fs.do: -------------------------------------------------------------------------------- 1 | fs=${1%.fs} 2 | redo-ifchange simple.fs 3 | 4 | rm -rf "$fs" 5 | cp -a simple/. "$fs" 6 | 7 | for full in "$fs"/bin/*; do 8 | if [ -x "$full" ]; then 9 | ldd "$full" | while read a b c junk; do 10 | [ "$b" = "=>" ] && a=$c 11 | if [ -e "$a" ]; then 12 | mkdir -p "$fs/lib" "$fs/$(dirname "$a")" 13 | cp -f "$a" "$fs/$a" 14 | fi 15 | done 16 | fi 17 | done 18 | 19 | redo-ifchange "$fs/bin/sh" 20 | -------------------------------------------------------------------------------- /redoconf/link.od: -------------------------------------------------------------------------------- 1 | rc_include _all.rc 2 | 3 | # Tricky quoting: see _compile.od for details. 4 | cat >$3 <<-EOF 5 | #!/bin/sh -e 6 | LINK=$(shquote "$LINK") 7 | LDFLAGS=$(shquote "$LDFLAGS") 8 | OPTFLAGS=$(shquote "$OPTFLAGS") 9 | LIBS=$(shquote "$LIBS") 10 | o="\$1" 11 | shift 12 | IFS="$NL" 13 | set -f 14 | \$LINK -o "\$o" \\ 15 | \$LDFLAGS \$OPTFLAGS \\ 16 | "\$@" \\ 17 | \$xLIBS \$LIBS 18 | EOF 19 | chmod a+x "$3" 20 | redo-stamp <$3 21 | -------------------------------------------------------------------------------- /t/202-del/deltest4.do: -------------------------------------------------------------------------------- 1 | rm -rf x 2 | redo x/a.spam2 3 | [ "$(cat x/a.spam2)" = "redir" ] || exit 11 4 | redo x/a.spam2 5 | [ "$(cat x/a.spam2)" = "redir" ] || exit 12 6 | redo x/b.spam2 7 | [ "$(cat x/b.spam2)" = "redir" ] || exit 13 8 | 9 | rm -rf x 10 | redo x/a.spam1 11 | [ "$(cat x/a.spam1)" = "stdout" ] || exit 21 12 | redo x/a.spam1 13 | [ "$(cat x/a.spam1)" = "stdout" ] || exit 22 14 | redo x/b.spam1 15 | [ "$(cat x/b.spam1)" = "stdout" ] || exit 23 16 | -------------------------------------------------------------------------------- /t/950-curse/check-2.sh: -------------------------------------------------------------------------------- 1 | COUNT_IN=$(ls *.count | wc -l) 2 | COUNT_OUT=$(cat *.count | wc -l) 3 | if [ "$COUNT_IN" -ne "$COUNT_OUT" ]; then 4 | echo "expected $COUNT_IN individual writes, got $COUNT_OUT" >&2 5 | exit 42 6 | fi 7 | COUNTALL_IN=$(cat in.countall | wc -l) 8 | COUNTALL_OUT=$(cat out.countall | wc -l) 9 | if [ "$COUNTALL_IN" -ne "$COUNTALL_OUT" ]; then 10 | echo "expected $COUNTALL_IN allwrites, got $COUNTALL_OUT" >&2 11 | exit 43 12 | fi 13 | -------------------------------------------------------------------------------- /clean.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | rm -rf t/.redo redo/sh 3 | if [ -e .do_built ]; then 4 | while read x; do 5 | [ -d "$x" ] || rm -f "$x" 6 | done <.do_built 7 | fi 8 | [ -z "$DO_BUILT" ] && rm -rf .do_built .do_built.dir 9 | rm -rf minimal/.do_built minimal/.do_built.dir minimal/y docs.out 10 | redo t/clean docs/clean redo/clean 11 | rm -f *~ .*~ */*~ */.*~ *.pyc install.wrapper 12 | find . -name '*.tmp' -exec rm -f {} \; 13 | find . -name '*.did' -exec rm -f {} \; 14 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.sha256.do: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Calculate the sha256 digest of a given file.""" 3 | import hashlib, os, subprocess, sys 4 | 5 | subprocess.check_call([ 6 | 'redo-ifchange', 7 | sys.argv[2], 8 | ], close_fds=False) 9 | 10 | h = hashlib.sha256() 11 | f = open(sys.argv[2], 'rb') 12 | while 1: 13 | b = f.read(65536) 14 | if not b: break 15 | h.update(b) 16 | open(sys.argv[3], 'w').write(h.hexdigest() + '\n') 17 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/configured.do: -------------------------------------------------------------------------------- 1 | # Ensure that an out/ directory exists and that 2 | # it has been configured (ie. ../configure has been run). 3 | [ -d out ] || (mkdir out && cd out && ../configure) 4 | 5 | # By declaring a dependency on this file *after* running 6 | # configure, we can tell redo that reconfiguration is 7 | # needed if this file ever disappears (for example, if 8 | # the whole out/ directory disappears). 9 | redo-ifchange out/default.do 10 | -------------------------------------------------------------------------------- /t/010-jobserver/paralleltest.do: -------------------------------------------------------------------------------- 1 | # Test that -j2 really gives us parallel builds with their own tokens. 2 | # (It's hard to test for sure that we have our own tokens, but if we're 3 | # sharing with other tests, we can't be sure that parallel2 will run while 4 | # parallel is running, and the race condition will make this test at least 5 | # be flakey instead of pass, which means there's a bug.) 6 | rm -f *.sub *.spin *.x parallel *.start *.end 7 | redo parallel parallel2 8 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.gz.do: -------------------------------------------------------------------------------- 1 | redo-ifchange "$2" 2 | 3 | # On freebsd, 'gzip --rsyncable' fails but returns 0. 4 | # We have to detect lack of --rsyncable some other way. 5 | gzt=$(gzip --rsyncable -c /dev/null | wc -c) 6 | if [ "$gzt" -gt 0 ]; then 7 | # when available, --rsyncable makes compressed 8 | # files much more efficient to rsync when they 9 | # change slightly. 10 | gzip --rsyncable -c <$2 >$3 11 | else 12 | gzip -c <$2 >$3 13 | fi 14 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/hello.list.od: -------------------------------------------------------------------------------- 1 | rc_include all.rc 2 | 3 | # We include $LIBM here just as example of how to 4 | # specify an auto-detected library as part of the 5 | # linker settings for a binary. We don't actually 6 | # use it for anything. Note that $LIBM was detected 7 | # up above in the rc_include, because all.rc depends 8 | # on rc/libm.rc. If the library is not available, 9 | # $LIBM will be blank. 10 | cat <<-EOF 11 | hello.cc 12 | ssltest.c 13 | $LIBM 14 | EOF 15 | -------------------------------------------------------------------------------- /t/204-makeflags/closefds.py: -------------------------------------------------------------------------------- 1 | import subprocess, sys, os 2 | 3 | # subprocess.call(close_fds=True) is unfortunately not a good idea, 4 | # because some versions (Debian's python version?) try to close inordinately 5 | # many file descriptors, like 0..1000000, which takes a very long time. 6 | # 7 | # We happen to know that redo doesn't need such huge fd values, so we'll 8 | # just cheat and use a smaller range. 9 | os.closerange(3, 1024) 10 | rv = subprocess.call(sys.argv[1:]) 11 | sys.exit(rv) 12 | 13 | -------------------------------------------------------------------------------- /t/350-deps/test1.do: -------------------------------------------------------------------------------- 1 | # This may have been leftover from a previous run, when switching 2 | # between "real" redo and minimal/do, so clean it up. 3 | rm -f t1a 4 | 5 | # force-rebuild t1dep 6 | redo t1dep 7 | 8 | if [ -e t1a ]; then 9 | BEFORE="$(cat t1a)" 10 | else 11 | BEFORE= 12 | fi 13 | ../flush-cache 14 | redo-ifchange t1a # it definitely had to rebuild because t1dep changed 15 | AFTER="$(cat t1a)" 16 | if [ "$BEFORE" = "$AFTER" ]; then 17 | echo "t1a was not rebuilt!" >&2 18 | exit 43 19 | fi 20 | -------------------------------------------------------------------------------- /t/203-make/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange whichmake 3 | 4 | run() { 5 | rm -f *.out 6 | ./whichmake y 7 | 8 | rm -f *.out 9 | ./whichmake -j10 y 10 | 11 | rm -f *.out 12 | redo y 13 | 14 | rm -f *.out 15 | # Capture output to y.log because we know this intentionally generates 16 | # a scary-looking redo warning (overriding the jobserver). 17 | if ! redo -j10 y 2>y.log; then 18 | cat y.log 19 | exit 99 20 | fi 21 | } 22 | 23 | run 24 | . ./wipe-redo.sh 25 | run 26 | -------------------------------------------------------------------------------- /docs/cookbook/c/all.rc.od: -------------------------------------------------------------------------------- 1 | rc_include \ 2 | rc/CC.required.rc \ 3 | rc/CXX.rc \ 4 | rc/shlib.rc \ 5 | rc/libqt4.rc \ 6 | rc/libgtk2.rc \ 7 | rc/Wextra.rc \ 8 | rc/Wall.rc \ 9 | rc/libm.rc \ 10 | rc/rt.autolib.rc \ 11 | rc/libpng.rc \ 12 | rc/clock_gettime.rc \ 13 | rc/mach__mach_time.h.rc \ 14 | rc/windows.h.rc \ 15 | rc/posix.rc \ 16 | rc/printf_lld.rc \ 17 | rc/extra.rc \ 18 | rc/all.h.precompiled.rc \ 19 | rc/all.hpp.precompiled.rc 20 | 21 | rc_appendln LIBS "$LIBRT" 22 | rc_appendln LIBS "$LIBM" 23 | rc_save 24 | -------------------------------------------------------------------------------- /redoconf/rc/libm.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/pkg-config.rc 2 | 3 | prog=' 4 | #include 5 | int x = FP_NORMAL; 6 | volatile float y; 7 | void f() { y = sin(y); } 8 | ' 9 | 10 | rc_pkg_detect LIBM libm \ 11 | rc_compile cc link "$prog" 12 | if [ -z "$HAVE_LIBM" ]; then 13 | rc_undo 14 | rc_replaceln HAVE_LIBM 1 15 | rc_appendln LIBM "-lm" 16 | appendln LIBS "$LIBM" 17 | if ! rc_compile cc link "$prog"; then 18 | rc_undo 19 | rc_replaceln HAVE_LIBM "" 20 | rc_replaceln LIBM "" 21 | fi 22 | fi 23 | 24 | rc_save 25 | -------------------------------------------------------------------------------- /docs/cookbook/c/main.c: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "libhello/hello.h" 3 | #include "monotime.h" 4 | #include "redoconf.h" 5 | #include 6 | 7 | #if EXTRA_RC_INCLUDED != 1 8 | #error "EXTRA_RC was not included!" 9 | #endif 10 | 11 | int main() { 12 | hello(); 13 | printf("Timestamp: %s\n", stamp_time()); 14 | printf("Monotime: %lld\n", monotime()); 15 | #ifdef CXX 16 | printf("Length of 'hello world': %d\n", cpp_test()); 17 | #else 18 | printf("No C++ compiler found.\n"); 19 | #endif 20 | flag_test(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.runlocal.do: -------------------------------------------------------------------------------- 1 | redo-ifchange "$2.fs" 2 | 3 | ./need.sh unshare 4 | 5 | set +e 6 | unshare -r chroot "$2" /init >$3 7 | rv=$? 8 | if [ "$rv" != 0 ]; then 9 | f=/proc/sys/kernel/unprivileged_userns_clone 10 | if [ -e "$f" ]; then 11 | read v <$f 12 | if [ "$v" -eq 0 ]; then 13 | echo "Try: echo 1 >$f" >&2 14 | fi 15 | fi 16 | 17 | f=/proc/sys/kernel/userns_restrict 18 | if [ -e "$f" ]; then 19 | read v <$f 20 | if [ "$v" -ne 0 ]; then 21 | echo "Try: echo 0 >$f" >&2 22 | fi 23 | fi 24 | fi 25 | exit "$rv" 26 | -------------------------------------------------------------------------------- /t/140-shuffle/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | . ../skip-if-minimal-do.sh 3 | 4 | # Need to repeat this several times, on the off chance that shuffling the 5 | # input happens to give us the same output (probability 1/factorial(9)) 6 | x=0 7 | while [ "$x" -lt 10 ]; do 8 | x=$(($x + 1)) 9 | rm -f out.log 10 | redo --shuffle 1.x 2.x 3.x 4.x 5.x 6.x 7.x 8.x 9.x 11 | sort out.log >sort.log 12 | if ! diff -q out.log sort.log >/dev/null; then 13 | exit 0 14 | fi 15 | echo "retry: #$x" 16 | done 17 | 18 | # still not shuffled? 19 | exit 22 20 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.list.do: -------------------------------------------------------------------------------- 1 | d=$PWD 2 | redo-ifchange "$2.fs" 3 | 4 | if [ -e "$2.diffbase" ]; then 5 | redo-ifchange "$2.diffbase" 6 | read diffbase <$2.diffbase 7 | diffbase=$diffbase.list 8 | redo-ifchange "$diffbase" 9 | else 10 | diffbase=/dev/null 11 | redo-ifcreate "$2.diffbase" 12 | fi 13 | 14 | ( 15 | cd "$2" && 16 | find . -print | sort | "$d/try_fakeroot.sh" "$d/$2.fakeroot" "$d/fileids.py" 17 | ) >$1.tmp 18 | 19 | comm -1 -3 "$diffbase" "$1.tmp" >$3 20 | rm -f "$1.tmp" 21 | 22 | # Sanity check 23 | nbytes=$(wc -c <"$3") 24 | test $nbytes -gt 0 25 | -------------------------------------------------------------------------------- /docs/cookbook/hello/hello.do: -------------------------------------------------------------------------------- 1 | # If hello.c changes, this script needs to be 2 | # re-run. 3 | redo-ifchange hello.c 4 | 5 | # Compile hello.c into the 'hello' binary. 6 | # 7 | # $3 is the redo variable that represents the 8 | # output filename. We want to build a file 9 | # called "hello", but if we write that directly, 10 | # then an interruption could result in a 11 | # partially-written file. Instead, write it to 12 | # $3, and redo will move our output into its 13 | # final location, only if this script completes 14 | # successfully. 15 | # 16 | cc -o $3 hello.c -Wall 17 | -------------------------------------------------------------------------------- /redoconf/rc/run.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc rc/windows.h.rc 2 | 3 | consider() { 4 | echo "Considering RUN=$(shquote "$1")" >&2 5 | if [ -z "$1" ] || type "$1" >/dev/null 2>&1; then 6 | rc_undo 7 | rc_replaceln RUN "$1" 8 | if RUN="$RUN" rc_compile cc run ""; then 9 | rc_replaceln CAN_RUN 1 10 | rc_save 11 | exit 0 12 | fi 13 | fi 14 | } 15 | 16 | consider "" 17 | if [ -n "$HAVE_WINDOWS_H" ]; then 18 | consider "wine64" 19 | consider "wine" 20 | consider "wine32" 21 | fi 22 | 23 | rc_undo 24 | rc_replaceln RUN "" 25 | rc_replaceln CAN_RUN "" 26 | rc_save 27 | -------------------------------------------------------------------------------- /docs/cookbook/container/debootstrap.fs.do: -------------------------------------------------------------------------------- 1 | fs=${1%.fs} 2 | rm -rf "$fs" "$fs.fakeroot" 3 | 4 | redo-ifchange debdownload.fs debootstrap.options 5 | cp -a debdownload/. "$fs" 6 | eatmydata \ 7 | fakechroot \ 8 | fakeroot -s "$fs.fakeroot" \ 9 | debootstrap $(cat debootstrap.options) "$fs" >&2 10 | 11 | # Clean up installed package files 12 | rm -f "$fs"/var/cache/apt/archives/*.deb \ 13 | "$fs"/var/cache/apt/*.bin \ 14 | "$fs"/var/lib/apt/lists/*Packages \ 15 | "$fs"/var/lib/apt/lists/*Sources \ 16 | "$fs"/var/lib/apt/lists/debootstrap* 17 | 18 | redo-ifchange "$fs/bin/sh" 19 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/all.do: -------------------------------------------------------------------------------- 1 | # Run from the source dir. 2 | # 3 | # We'll make sure the out/ dir exists and that 4 | # a C++ compiler is available, then redo out/all, 5 | # which is implemented in the file all.od. 6 | # 7 | # Note that a "normal" project might not have an all.do 8 | # at all; the end user would be expected to make an 9 | # output dir, run ../configure, and then redo from there. 10 | # But we want this file to build as part of the redo 11 | # examples, so there needs to be a toplevel all.do in 12 | # each example. 13 | # 14 | . ./skip-if-no-cxx.sh 15 | redo-ifchange out/all 16 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/ssltest.c: -------------------------------------------------------------------------------- 1 | // An example of how to change code behaviour based on 2 | // redoconf autodetection. 3 | #include "redoconf.h" 4 | 5 | #if HAVE_LIBSSL 6 | 7 | #if HAVE_OPENSSL__SSL_H 8 | #include 9 | #endif 10 | 11 | #if HAVE_OPENSSL__OPENSSLV_H 12 | #include 13 | #endif 14 | 15 | unsigned long libssl_version() { 16 | SSL_library_init(); 17 | return OPENSSL_VERSION_NUMBER; 18 | } 19 | 20 | #else // HAVE_LIBSSL 21 | 22 | unsigned long libssl_version() { 23 | // Library not present 24 | return 0; 25 | } 26 | 27 | #endif // HAVE_LIBSSL 28 | 29 | -------------------------------------------------------------------------------- /docs/git-export.do: -------------------------------------------------------------------------------- 1 | # update the local 'man' branch with pregenerated output files, for people 2 | # who don't have pandoc (and maybe to aid in google searches or something) 3 | redo-ifchange all 4 | git update-ref refs/heads/man origin/man '' 2>/dev/null || true 5 | 6 | export GIT_INDEX_FILE=gitindex.tmp 7 | rm -f $GIT_INDEX_FILE 8 | git add -f *.1 9 | 10 | MSG="Autogenerated man pages for $(git describe)" 11 | TREE=$(git write-tree --prefix=docs) 12 | git show-ref refs/heads/man >/dev/null && PARENT="-p refs/heads/man" 13 | COMMITID=$(echo "$MSG" | git commit-tree $TREE $PARENT) 14 | 15 | git update-ref refs/heads/man $COMMITID 16 | -------------------------------------------------------------------------------- /redo/title.py: -------------------------------------------------------------------------------- 1 | """Code for manipulating the Unix process title.""" 2 | import os, sys 3 | 4 | # FIXME: setproctitle module is only usable if *not* using python -S, 5 | # and without -S, python startup time is annoyingly longer 6 | try: 7 | from setproctitle import setproctitle 8 | except ImportError: 9 | def setproctitle(name): 10 | pass 11 | 12 | 13 | def auto(): 14 | """Automatically clean up the title as seen by 'ps', based on argv.""" 15 | exe = sys.argv[0] 16 | exename, ext = os.path.splitext(os.path.basename(sys.argv[0])) 17 | title = ' '.join([exename] + sys.argv[1:]) 18 | setproctitle(title) 19 | -------------------------------------------------------------------------------- /docs/cookbook/container/simple.fs.do: -------------------------------------------------------------------------------- 1 | # We can pull in the 'hello' binary built in an earlier 2 | # example. Notice that it's safe to have dependencies 3 | # that cross directory boundaries, even when we're building 4 | # both of those directories in parallel. 5 | FILES=" 6 | /bin/sh 7 | ../hello/hello 8 | " 9 | if [ -x /bin/busybox ]; then 10 | # Optional, except for runkvm 11 | FILES="$FILES /bin/busybox" 12 | else 13 | redo-ifcreate /bin/busybox 14 | fi 15 | redo-ifchange $FILES 16 | 17 | fs=${1%.fs} 18 | rm -rf "$fs" 19 | mkdir -p "$fs/bin" 20 | cp $FILES "$fs/bin/" 21 | ln -s bin/hello "$fs/init" 22 | 23 | redo-ifchange "$fs/bin/sh" 24 | -------------------------------------------------------------------------------- /redo/cycles.py: -------------------------------------------------------------------------------- 1 | """Code for detecting and aborting on cyclic dependency loops.""" 2 | import os 3 | 4 | 5 | class CyclicDependencyError(Exception): 6 | pass 7 | 8 | 9 | def _get(): 10 | """Get the list of held cycle items.""" 11 | return os.environ.get('REDO_CYCLES', '').split(':') 12 | 13 | 14 | def add(fid): 15 | """Add a lock to the list of held cycle items.""" 16 | items = set(_get()) 17 | items.add(str(fid)) 18 | os.environ['REDO_CYCLES'] = ':'.join(list(items)) 19 | 20 | 21 | def check(fid): 22 | if str(fid) in _get(): 23 | # Lock already held by parent: cyclic dependency 24 | raise CyclicDependencyError() 25 | -------------------------------------------------------------------------------- /t/010-jobserver/all.do: -------------------------------------------------------------------------------- 1 | # We put the -j options at this toplevel to detect an earlier bug 2 | # where the sub-jobserver wasn't inherited by sub-sub-processes, which 3 | # accidentally reverted to the parent jobserver instead. 4 | 5 | redo -j1 serialtest 6 | 7 | # Capture log output to parallel.log to hide the (intentional since we're 8 | # testing it) scary warning from redo about overriding the jobserver. 9 | if [ -n "$REDO_LOCKS_BROKEN" ]; then 10 | echo "Locks are broken on this OS; skipping parallel tests." >&2 11 | exit 0 12 | fi 13 | 14 | echo 'parallel test...' >&2 15 | if ! redo -j10 paralleltest 2>parallel.log; then 16 | cat parallel.log >&2 17 | exit 99 18 | fi 19 | -------------------------------------------------------------------------------- /t/350-deps/gentest.do: -------------------------------------------------------------------------------- 1 | rm -f genfile2 genfile2.do genfile.log 2 | 3 | echo echo hello >genfile2.do 4 | ../flush-cache 5 | redo genfile1 6 | 7 | # this will cause a rebuild: 8 | # genfile1 depends on genfile2 depends on genfile2.do 9 | rm -f genfile2.do 10 | ../flush-cache 11 | redo-ifchange genfile1 12 | 13 | # but genfile2.do was gone last time, so genfile2 no longer depends on it. 14 | # thus, it can be considered up-to-date. Prior versions of redo had a bug 15 | # where the dependency on genfile2.do was never dropped. 16 | ../flush-cache 17 | redo-ifchange genfile1 18 | 19 | COUNT=$(wc -l /dev/null && exit 91 5 | rm exists 6 | redo-ifcreate exists || exit 92 7 | 8 | for d in 1 2; do 9 | redo ifcreate$d 10 | [ "$(wc -l $3 25 | redo-stamp <$3 26 | -------------------------------------------------------------------------------- /redo/cmd_sources.py: -------------------------------------------------------------------------------- 1 | """redo-sources: list the known source (not target) files.""" 2 | from __future__ import print_function 3 | import sys, os 4 | from . import env, logs, state 5 | 6 | 7 | def main(): 8 | if len(sys.argv[1:]) != 0: 9 | sys.stderr.write('%s: no arguments expected.\n' % sys.argv[0]) 10 | sys.exit(1) 11 | 12 | state.init([]) 13 | logs.setup( 14 | tty=sys.stderr, parent_logs=env.v.LOG, 15 | pretty=env.v.PRETTY, color=env.v.COLOR) 16 | 17 | cwd = os.getcwd() 18 | for f in state.files(): 19 | if f.is_source(): 20 | print(state.relpath(os.path.join(env.v.BASE, f.name), cwd)) 21 | 22 | 23 | if __name__ == '__main__': 24 | main() 25 | -------------------------------------------------------------------------------- /docs/cookbook/container/dockjson.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Generate a docker 1.0-style manifest for a docker image.""" 3 | import json, os, sys, time 4 | 5 | j = json.load(open('template.json')) 6 | layerid = open(sys.argv[1] + '.list.sha256').read().strip() 7 | j['id'] = layerid 8 | 9 | if len(sys.argv) > 2 and sys.argv[2]: 10 | parentid = open(sys.argv[2] + '.list.sha256').read().strip() 11 | j['parent'] = parentid 12 | 13 | t = time.time() 14 | gt = time.gmtime(t) 15 | nsec = int(t * 1e9) % 1000000000 16 | j['created'] = time.strftime('%Y-%m-%dT%H:%M:%S', gt) + ('.%09dZ' % nsec) 17 | 18 | nbytes = os.stat(sys.argv[1] + '.layer').st_size 19 | j['Size'] = nbytes 20 | 21 | json.dump(j, sys.stdout, indent=2) 22 | -------------------------------------------------------------------------------- /docs/cookbook/container/fileids.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import hashlib, os, stat, sys 3 | 4 | for name in sys.stdin: 5 | name = name[:-1] # skip terminating newline 6 | st = os.lstat(name) 7 | if stat.S_ISREG(st.st_mode): 8 | h = hashlib.sha256() 9 | f = open(name, 'rb') 10 | while 1: 11 | b = f.read(65536) 12 | if not b: break 13 | h.update(b) 14 | digest = h.hexdigest() 15 | elif stat.S_ISLNK(st.st_mode): 16 | digest = hashlib.sha256(os.readlink(name).encode('utf8')).hexdigest() 17 | else: 18 | digest = '0' 19 | print('%s %07o-%s-%s-%s' % ( 20 | name, 21 | st.st_mode, st.st_uid, st.st_gid, digest)) 22 | -------------------------------------------------------------------------------- /docs/cookbook/c/hello world.list.od: -------------------------------------------------------------------------------- 1 | # This script is run from the output dir. 2 | # The source dir is at $S. 3 | rc_include all.rc 4 | redo-ifchange "$S/sources" 5 | 6 | ( 7 | cd "$S" 8 | echo "main.c" 9 | echo "monotime.c" 10 | echo "when.c" # auto-generated source 11 | echo "flagtest.c" # source with different compiler flags 12 | 13 | if [ -n "$CXX" ]; then 14 | echo "slow.cc" 15 | fi 16 | 17 | # This is unnecessarily fancy. 18 | # We're just using it as an example of 19 | # how to dynamically generate a .list 20 | # file. 21 | for d in lib*/*.list lib*/*.list.od; do 22 | [ -e "$d" ] && echo "${d%%.*}.so" 23 | done | uniq 24 | 25 | printf '%s\n' "$LIBGTK2" "$LIBQT4" 26 | ) >"$3" 27 | 28 | redo-stamp <"$3" 29 | -------------------------------------------------------------------------------- /t/103-unicode/unicode.do: -------------------------------------------------------------------------------- 1 | # Test that redo can handle a script whose path contains non-ASCII characters. 2 | # Note: the test directory is intentionally *not* a normalized unicode 3 | # string, ie. filesystems like macOS will convert it to a different string 4 | # at creation time. This tests weird normalization edge cases. 5 | # 6 | # Unfortunately, on macOS with APFS, it may helpfully normalize the path at 7 | # *create* time, but not on future *open* attempts. Thus, we let the shell 8 | # figure out what directory name actually got created, then pass that to redo. 9 | # Hence the weird wildcard expansion loop. 10 | rm -rf test-uni*.tmp 11 | mkdir "test-uniçøðë.tmp" 12 | for p in test-uni*.tmp; do 13 | : >$p/test1.do 14 | redo "$p/test1" 15 | done 16 | 17 | -------------------------------------------------------------------------------- /t/640-always/all.do: -------------------------------------------------------------------------------- 1 | rm -f always1 always1.log 2 | 3 | cd .. 4 | redo 640-always/always1 5 | cd 640-always 6 | [ "$(wc -l destruct1.do <<-EOF 5 | rm -f *.tmp 6 | echo 'redir' >\$3 7 | EOF 8 | cat >destruct2.do <<-EOF 9 | rm -f *.tmp 10 | echo 'stdout' 11 | EOF 12 | 13 | # deleting unused stdout file is a warning at most 14 | redo destruct1 2>destruct1.log || exit 11 15 | [ "$(cat destruct1)" = "redir" ] || exit 12 16 | 17 | # deleting *used* stdout file may be a fatal mistake, 18 | # but we won't enforce that, since some redo variants 19 | # might be more accepting or use different tmp file 20 | # algorithms. So either the file should be correct, 21 | # or it should be missing. 22 | redo destruct2 2>destruct2.log || : 23 | if [ -e "destruct2" ]; then 24 | [ "$(cat destruct2)" = "stdout" ] || exit 22 25 | fi 26 | -------------------------------------------------------------------------------- /t/205-readonly/all.do: -------------------------------------------------------------------------------- 1 | [ -e rodir ] && chmod u+w rodir 2 | [ -e rodir/rwdir ] && chmod u+w rodir/rwdir 3 | rm -rf rodir 4 | mkdir rodir rodir/rwdir 5 | 6 | cd rodir 7 | cat >default.ro1.do <<-EOF 8 | chmod u+w "\$(dirname "\$1")" 9 | echo 'redir' >\$3 10 | EOF 11 | cat >default.ro2.do <<-EOF 12 | chmod u+w "\$(dirname "\$1")" 13 | echo 'stdout' 14 | EOF 15 | 16 | # Check that: 17 | # - redo works when the .do file is in a read-only directory. 18 | # - redo works when the target is in a read-only directory that becomes 19 | # writable only *after* launching the .do script. (For example, the .do 20 | # might mount a new read-write filesystem in an otherwise read-only 21 | # tree.) 22 | chmod a-w . rwdir 23 | redo rwdir/a.ro1 24 | chmod a-w . rwdir 25 | redo rwdir/a.ro2 26 | -------------------------------------------------------------------------------- /docs/mkdocs.do: -------------------------------------------------------------------------------- 1 | redo-ifchange doc.list 2 | xargs redo-ifchange ../mkdocs.yml /dev/null | cut -d' ' -f3) 7 | check=' 8 | import sys 9 | ok = sys.argv[1].split(".") >= ["1", "0", "4"] 10 | exit(not ok) 11 | ' 12 | 13 | if ! type mkdocs >/dev/null 2>/dev/null; then 14 | echo "Warning: mkdocs is missing; can't generate website." >&2 15 | redo-ifcreate /usr/bin/mkdocs 16 | elif ! python -c "$check" "$ver"; then 17 | echo "Warning: mkdocs is too old ($ver); need at least 1.0.4." >&2 18 | mkd=$(which mkdocs 2>/dev/null || :) 19 | [ -x "$mkd" ] && redo-ifchange "$mkd" 20 | else 21 | (cd .. && mkdocs build --strict --clean) 22 | fi 23 | -------------------------------------------------------------------------------- /t/260-whichdo/exists.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | 3 | a=$(cd fakesub && redo-whichdo ../a/b/x.y.z) 4 | # if sh doesn't abort after the above, then it found a .do file as expected 5 | 6 | # Note: we expect redo-whichdo to return paths relative to $PWD at the time 7 | # it's run, which in this case is fakesub. 8 | # Likely bugs would be to return paths relative to the start dir, the .redo 9 | # dir, the current target dir, the requested target dir, etc. 10 | b=$(cat </dev/null 2>&1 16 | } 17 | 18 | ( 19 | echo "/* Automatically generated by redoconf.h.od */" 20 | IFS="$NL" 21 | for k in $RC_KEYS; do 22 | [ "$k" != "RC_KEYS" ] || continue 23 | [ "$k" != "RC_INCLUDES" ] || continue 24 | eval v=\$$k 25 | if [ -z "$v" ]; then 26 | echo "#undef $k" 27 | elif is_number "$v"; then 28 | echo "#define $k $v" 29 | else 30 | echo "#define $k $(cquote "$v")" 31 | fi 32 | done 33 | ) >$3 34 | redo-stamp <$3 35 | -------------------------------------------------------------------------------- /t/122-defaults-parent/all.do: -------------------------------------------------------------------------------- 1 | rm -f x/shouldfail 2 | 3 | log=$PWD/$1.log 4 | 5 | expect_fail() { 6 | local rv=$1 7 | shift 8 | if ("$@") >>$log 2>&1; then 9 | cat "$log" >&2 10 | echo "unexpected success:" "$@" >&2 11 | return $rv 12 | else 13 | return 0 14 | fi 15 | } 16 | 17 | # These should all fail because there is no matching .do file. 18 | # In previous versions of redo, it would accidentally try to use 19 | # $PWD/default.do even for ../path/file, which is incorrect. That 20 | # could cause it to return success accidentally. 21 | 22 | rm -f "$log" 23 | cd inner 24 | expect_fail 11 redo ../x/shouldfail 25 | expect_fail 12 redo-ifchange ../x/shouldfail 26 | 27 | rm -f "$log" 28 | cd ../inner2 29 | expect_fail 21 redo ../x/shouldfail2 30 | expect_fail 22 redo-ifchange ../x/shouldfail2 31 | 32 | exit 0 33 | -------------------------------------------------------------------------------- /t/204-makeflags/all.do: -------------------------------------------------------------------------------- 1 | # Make sure we can survive if a process closes all file descriptors, 2 | # including any jobserver file descriptors, as long as they also 3 | # unset MAKEFLAGS. 4 | redo-ifchange ../../redo/py 5 | 6 | # If we leave MAKEFLAGS set, then it's fair game to complain that the 7 | # advertised file descriptors are gone, because GNU make also complains. 8 | # (Although they only warn while we abort. They can't abort so that 9 | # they don't break backward compat, but we have no such constraint, because 10 | # redo has always failed for that case.) 11 | # 12 | # On the other hand, we shouldn't have to unset REDO_CHEATFDS, both for 13 | # backward compatibility, and because REDO_CHEATFDS is undocumented. 14 | # redo should recover silently from that problem. 15 | unset MAKEFLAGS 16 | ../../redo/py ./closefds.py redo noflags 17 | -------------------------------------------------------------------------------- /redo/cmd_always.py: -------------------------------------------------------------------------------- 1 | """redo-always: tell redo that the current target is always out of date.""" 2 | import sys, os 3 | from . import env, logs, state 4 | 5 | 6 | def main(): 7 | try: 8 | env.inherit() 9 | logs.setup( 10 | tty=sys.stderr, parent_logs=env.v.LOG, 11 | pretty=env.v.PRETTY, color=env.v.COLOR) 12 | 13 | me = os.path.join(env.v.STARTDIR, 14 | os.path.join(env.v.PWD, env.v.TARGET)) 15 | f = state.File(name=me) 16 | f.add_dep('m', state.ALWAYS) 17 | always = state.File(name=state.ALWAYS) 18 | always.stamp = state.STAMP_MISSING 19 | always.set_changed() 20 | always.save() 21 | state.commit() 22 | except KeyboardInterrupt: 23 | sys.exit(200) 24 | 25 | 26 | if __name__ == '__main__': 27 | main() 28 | -------------------------------------------------------------------------------- /docs/cookbook/container/debian.fs.do: -------------------------------------------------------------------------------- 1 | fs=${1%.fs} 2 | rm -rf "$fs" "$fs.fakeroot" 3 | 4 | redo-ifchange debootstrap.fs 5 | fakeroot -i debootstrap.fakeroot -s "$fs.fakeroot" \ 6 | cp -a debootstrap/. "$fs" >&2 7 | 8 | # Work around bug (in fakechroot?) where /lib64 symlink ends up pointing 9 | # at an absolute path including $PWD, rather than inside the chroot. 10 | # Rather than fix the symlink, we'll just make sure $PWD is a link to /, 11 | # so that the "wrong" symlinks correctly resolve. 12 | pwdir=$(dirname "$PWD/bootstrap/") 13 | mkdir -p "$fs/$pwdir/debootstrap" 14 | dots=$(echo "$pwdir/" | sed -e 's,[^/]*/,../,g') 15 | ln -s "${dots}lib" "$fs/$pwdir/debootstrap/lib" 16 | 17 | # /init script is what we run in 'docker run' 18 | cat >"$fs/init" <<-EOF 19 | #!/bin/sh 20 | dpkg -l | wc -l 21 | EOF 22 | chmod a+x "$fs/init" 23 | 24 | redo-ifchange "$fs/bin/sh" 25 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/configure.help: -------------------------------------------------------------------------------- 1 | # Automatically generated by redoconf/_all.rc.od - do not edit 2 | ARCH Architecture prefix for output (eg. i686-w64-mingw32-) 3 | CC C compiler name (cc) 4 | CPPFLAGS Extra C preprocessor flags (eg. -I... -D...) 5 | CFLAGS Extra C compiler flags (eg. -O2 -g) 6 | OPTFLAGS C/C++ compiler flag overrides (eg. -g0) 7 | LINK Linker name (cc) 8 | LDFLAGS Extra linker options (eg. -s -static) 9 | LIBS Extra libraries to always link against (eg. -lsocket) 10 | STATIC Link libraries and binaries statically 11 | LIBSSL Extra linker options for 'libssl libcrypto' 12 | LIBM Extra linker options for 'libm' 13 | CXX C++ compiler name (c++) 14 | CXXFLAGS Extra C++ compiler flags (eg. -O2 -g) 15 | PREFIX Change installation prefix (usually /usr/local) 16 | -------------------------------------------------------------------------------- /t/105-sympath/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange ../flush-cache 2 | rm -f src 3 | : >src 4 | 5 | for iter in 10 20; do 6 | rm -rf y 7 | rm -f x *.dyn static 8 | mkdir y 9 | : >y/static 10 | ln -s . y/x 11 | ../flush-cache 12 | 13 | ( 14 | cd y/x/x/x/x/x 15 | IFS=$(printf '\n') 16 | redo-ifchange static x/x/x/static $PWD/static \ 17 | $(/bin/pwd)/static /etc/passwd 18 | redo-ifchange $PWD/../static 2>/dev/null && exit 35 19 | redo-ifchange 1.dyn x/x/x/2.dyn $PWD/3.dyn \ 20 | $PWD/../4.dyn $(/bin/pwd)/5.dyn 21 | ) 22 | [ -e y/1.dyn ] || exit $((iter + 1)) 23 | [ -e y/2.dyn ] || exit $((iter + 2)) 24 | [ -e y/3.dyn ] || exit $((iter + 3)) 25 | [ -e 4.dyn ] || exit $((iter + 4)) 26 | [ -e y/5.dyn ] || exit $((iter + 5)) 27 | 28 | # Second iteration won't work in minimal/do since it only ever 29 | # builds things once. 30 | . ../skip-if-minimal-do.sh 31 | done 32 | -------------------------------------------------------------------------------- /t/010-jobserver/first.do: -------------------------------------------------------------------------------- 1 | # in case we're (erroneously) running in parallel, give second.do some 2 | # time to start but not finish. 3 | echo 'first sleep' >&2 4 | sleep 1 5 | 6 | # Because of --shuffle, we can't be sure if first or second ran first, but 7 | # because all.do uses -j1, we *should* expect that if second ran first, it 8 | # at least ran to completion before we ran at all. 9 | if [ -e second.start ]; then 10 | echo 'first: second already started before we did...' >&2 11 | [ -e second.end ] || exit 21 12 | echo 'first: ...and it finished as it should.' >&2 13 | # no sense continuing the test; can't test anything if second already 14 | # ran. 15 | exit 0 16 | fi 17 | echo 'first: second has not started yet, good.' >&2 18 | 19 | echo 'first spin' >&2 20 | redo 1.a.spin 21 | [ -e 1.a.spin ] || exit 11 22 | echo 'first spin complete' >&2 23 | 24 | ! [ -e second.start ] || exit 22 25 | -------------------------------------------------------------------------------- /docs/cookbook/defaults/default.do: -------------------------------------------------------------------------------- 1 | # $1 is the target name, eg. test.txt 2 | # $2 in the same as $1. We'll talk about 3 | # that in a later example. 4 | # $3 is the temporary output file we should 5 | # create. If this script is successful, 6 | # redo will atomically replace $1 with $3. 7 | 8 | if [ -e "$1.in" ]; then 9 | # if a .in file exists, then do some 10 | # text substitution. 11 | # 12 | # Remember, the user asks redo to build 13 | # a particular *target* name. It's the .do 14 | # file's job to figure out what source file(s) 15 | # to use to generate the target. 16 | redo-ifchange "$1.in" version date 17 | read VERSION $3 22 | else 23 | echo "$0: Fatal: don't know how to build '$1'" >&2 24 | exit 99 25 | fi 26 | -------------------------------------------------------------------------------- /redo/version/vars.do: -------------------------------------------------------------------------------- 1 | redo-ifchange gitvars prodname 2 | 3 | read PROD &2) 40 | done >$3 41 | 42 | wait 43 | -------------------------------------------------------------------------------- /redo/version/gitvars.do: -------------------------------------------------------------------------------- 1 | redo-ifchange gitvars.pre prodname 2 | 3 | read PROD $3 5 | 6 | # Fix each line from gitvars.pre where git may or may not have already 7 | # substituted the variables. If someone generated a tarball with 'git archive', 8 | # then the data will have been substituted already. If we're in a checkout of 9 | # the git repo, then it won't, but we can just ask git to do the substitutions 10 | # right now. 11 | while read line; do 12 | # Lines *may* be of the form: $Format: ... $ 13 | x=${line#\$Format:} # remove prefix 14 | if [ "$x" != "$line" ]; then 15 | # git didn't substitute it 16 | redo-always # git this from the git repo 17 | x=${x%\$} # remove trailing $ 18 | if [ "$x" = "%d" ]; then 19 | tag=$(git describe --match="$PROD-*") 20 | x="(tag: $tag)" 21 | else 22 | x=$(git log -1 --pretty=format:"$x") 23 | fi 24 | fi 25 | echo "$x" 26 | done &2 28 | rc_undo 29 | fi 30 | -------------------------------------------------------------------------------- /redoconf/rc/CXX.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | rc_helpmsg CXX "C++ compiler name (c++)" 4 | rc_helpmsg CXXFLAGS "Extra C++ compiler flags (eg. -O2 -g)" 5 | 6 | if [ -n "$CXX" ]; then 7 | set -- "$CXX" 8 | else 9 | # Note: $ARCH has already been set correctly by CC.rc 10 | set -- \ 11 | "${ARCH}c++" "${ARCH}g++" \ 12 | "${ARCH}clang++" "/usr/bin/${ARCH}clang++"-[0-9]* 13 | fi 14 | 15 | for d in "$@"; do 16 | [ -n "$d" ] || continue 17 | echo "Trying C++ compiler: '$d'" >&2 18 | if CC="" CXX="$d" LINK="$d" rc_compile cxx link 'class A {};'; then 19 | rc_replaceln CXX "$d" 20 | # If the project activates CXX.rc, then we 21 | # replace the C linker with C++. This causes 22 | # it to include -lstdc++, etc. 23 | # A future .rc could override this again. 24 | rc_replaceln LINK "$d" 25 | rc_replaceln HAVE_CXX 1 26 | rc_save 27 | exit 0 28 | fi 29 | done 30 | 31 | echo "Warning: Can't find a working C++ compiler." >&2 32 | rc_undo 33 | rc_replaceln CXX "" 34 | rc_save 35 | -------------------------------------------------------------------------------- /bin/default.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | 3 | case $1 in 4 | redo-sh) 5 | redo-ifchange ../redo/sh 6 | cat >$3 <<-EOF 7 | #!/bin/sh 8 | d=\$(dirname "\$0")/.. 9 | [ -x \$d/lib/redo/sh ] && exec \$d/lib/redo/sh "\$@" 10 | [ -x \$d/redo/sh ] && exec \$d/redo/sh "\$@" 11 | echo "\$0: fatal: can't find \$d/lib/redo/sh or \$d/redo/sh" >&2 12 | exit 98 13 | EOF 14 | chmod a+x "$3" 15 | ;; 16 | redo|redo-*) 17 | redo-ifchange ../redo/whichpython 18 | read py <../redo/whichpython 19 | cmd=${1#redo-} 20 | cat >$3 <<-EOF 21 | #!$py 22 | import sys, os; 23 | exe = os.path.realpath(os.path.abspath(sys.argv[0])) 24 | exedir = os.path.dirname(exe) 25 | sys.path.insert(0, os.path.join(exedir, '../lib')) 26 | sys.path.insert(0, os.path.join(exedir, '..')) 27 | import redo.title 28 | import redo.cmd_$cmd 29 | redo.title.auto() 30 | redo.cmd_$cmd.main() 31 | EOF 32 | chmod a+x "$3" 33 | ;; 34 | *) echo "$0: don't know how to build '$1'" >&2; exit 99 ;; 35 | esac 36 | -------------------------------------------------------------------------------- /redoconf/default.precompile.od: -------------------------------------------------------------------------------- 1 | # Run the extra steps necessary before compiling 2 | # C/C++ programs of the specified type. 3 | # 4 | # Notably, we have to precompile any precompiled 5 | # headers. We also generate redoconf.h in case 6 | # programs want to include it. 7 | rc_include _all.rc 8 | 9 | case ${1%.precompile} in 10 | cc) pch_files="$PRE_CC_TARGETS" ;; 11 | cc-fpic) pch_files="$PRE_CC_TARGETS_FPIC" ;; 12 | cxx) pch_files="$PRE_CXX_TARGETS" ;; 13 | cxx-fpic) pch_files="$PRE_CXX_TARGETS_FPIC" ;; 14 | *) exit 42 ;; 15 | esac 16 | 17 | IFS="$NL" 18 | set -f 19 | redo-ifchange "redoconf.h" $pch_files 20 | 21 | # Subtle: 22 | # Don't consider this target to have changed unless 23 | # the precompiled header's stamp has changed. 24 | # We generate redoconf.h, in case 25 | # a C program wants to include it, but we 26 | # don't care if it has changed, because the C program 27 | # will have its own dependency on that file. 28 | for d in $t; do 29 | cat "$d.stamp" 30 | done | redo-stamp 31 | -------------------------------------------------------------------------------- /redoconf/rc/default.hpp.precompiled.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CXX.rc 2 | 3 | base="${1#rc/}" 4 | src="${base%.hpp.precompiled.rc}" 5 | 6 | # Check whether the compiler supports forcing 7 | # the language type. Some versions of gcc 8 | # need this in order to precompile headers 9 | # named *.hpp. 10 | x="-x${NL}c++-header" 11 | if (appendln CXXFLAGS "$x" && rc_compile cxx nolink); then 12 | rc_appendln CXXFLAGS_PCH_LANG "$x" 13 | fi 14 | 15 | # The existence of the specific gcc warning about 16 | # precompiled headers is a pretty good indicator 17 | # that they are supported in the way we expect. 18 | rc_appendln CXXFLAGS "-Winvalid-pch" 19 | if rc_compile cxx nolink; then 20 | rc_appendln CXXFLAGS_PCH "-include$NL$src.hpp" 21 | rc_appendln CXXFLAGS_PCH_FPIC "-include$NL$src.hpp.fpic" 22 | 23 | rc_appendln PRE_CXX_TARGETS "$src.hpp.gch" 24 | rc_appendln PRE_CXX_TARGETS_FPIC "$src.hpp.fpic.gch" 25 | rc_save 26 | else 27 | echo "Precompiled C++ headers not supported." >&2 28 | rc_undo 29 | fi 30 | -------------------------------------------------------------------------------- /redo/cmd_ifcreate.py: -------------------------------------------------------------------------------- 1 | """redo-ifcreate: build the current target if these targets are created.""" 2 | import sys, os 3 | from . import env, logs, state 4 | from .logs import err 5 | 6 | 7 | def main(): 8 | try: 9 | env.inherit() 10 | logs.setup( 11 | tty=sys.stderr, parent_logs=env.v.LOG, 12 | pretty=env.v.PRETTY, color=env.v.COLOR) 13 | 14 | me = os.path.join(env.v.STARTDIR, 15 | os.path.join(env.v.PWD, env.v.TARGET)) 16 | f = state.File(name=me) 17 | for t in sys.argv[1:]: 18 | if not t: 19 | err('cannot build the empty target ("").\n') 20 | sys.exit(204) 21 | if os.path.exists(t): 22 | err('redo-ifcreate: error: %r already exists\n' % t) 23 | sys.exit(1) 24 | else: 25 | f.add_dep('c', t) 26 | state.commit() 27 | except KeyboardInterrupt: 28 | sys.exit(200) 29 | 30 | 31 | if __name__ == '__main__': 32 | main() 33 | -------------------------------------------------------------------------------- /redo/helpers.py: -------------------------------------------------------------------------------- 1 | """Some helper functions that don't fit anywhere else.""" 2 | import os, errno, fcntl 3 | 4 | 5 | class ImmediateReturn(Exception): 6 | def __init__(self, rv): 7 | Exception.__init__(self, "immediate return with exit code %d" % rv) 8 | self.rv = rv 9 | 10 | 11 | def unlink(f): 12 | """Delete a file at path 'f' if it currently exists. 13 | 14 | Unlike os.unlink(), does not throw an exception if the file didn't already 15 | exist. 16 | """ 17 | try: 18 | os.unlink(f) 19 | except OSError as e: 20 | if e.errno == errno.ENOENT: 21 | pass # it doesn't exist, that's what you asked for 22 | 23 | 24 | def close_on_exec(fd, yes): 25 | fl = fcntl.fcntl(fd, fcntl.F_GETFD) 26 | fl &= ~fcntl.FD_CLOEXEC 27 | if yes: 28 | fl |= fcntl.FD_CLOEXEC 29 | fcntl.fcntl(fd, fcntl.F_SETFD, fl) 30 | 31 | 32 | def fd_exists(fd): 33 | try: 34 | fcntl.fcntl(fd, fcntl.F_GETFD) 35 | except IOError: 36 | return False 37 | return True 38 | -------------------------------------------------------------------------------- /t/121-defaults-nested/test.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange \ 3 | file.x.y.z file.z file \ 4 | a/b/file.x.y.z a/b/file.y.z a/b/file.z a/b/file \ 5 | a/d/file.x.y.z a/d/file.y.z a/d/file.z a/d/file 6 | 7 | (cd a/b && redo-ifchange ../file.x.y.z ../file.y.z ../file.z ../file) 8 | 9 | check() 10 | { 11 | if [ "$(cat $1)" != "$2" ]; then 12 | echo "$1 should contain '$2'" 13 | echo " ...got '$(cat $1)'" 14 | exit 44 15 | fi 16 | } 17 | 18 | check file.x.y.z "root file.x.y.z ." 19 | check file.z "root file.z ." 20 | check file "root file ." 21 | 22 | check a/file.x.y.z "default.x.y.z file .x.y.z" 23 | check a/file.y.z "default.z file.y .z" 24 | check a/file.z "default.z file .z" 25 | check a/file "root a/file a" 26 | 27 | check a/b/file.x.y.z "file file.x.y.z" 28 | check a/b/file.y.z "default.y.z file .y.z" 29 | check a/b/file.z "default.z b/file .z" 30 | check a/b/file "root a/b/file a/b" 31 | 32 | check a/d/file.x.y.z "default file.x.y.z" 33 | check a/d/file.y.z "default file.y.z" 34 | check a/d/file.z "default file.z" 35 | check a/d/file "default file" 36 | 37 | -------------------------------------------------------------------------------- /t/201-fail/all.do: -------------------------------------------------------------------------------- 1 | rm -f this-doesnt-exist 2 | ! redo this-doesnt-exist >/dev/null 2>&1 || exit 32 # expected to fail 3 | ! redo-ifchange this-doesnt-exist >/dev/null 2>&1 || exit 33 # expected to fail 4 | redo-ifcreate this-doesnt-exist >/dev/null 2>&1 || exit 34 # expected to pass 5 | 6 | 7 | rm -f fail 8 | ! redo-ifchange fail >/dev/null 2>&1 || exit 44 # expected to fail 9 | 10 | touch fail 11 | ../flush-cache 12 | # since we created this file by hand, fail.do won't run, so it won't fail. 13 | redo-ifchange fail >/dev/null 2>&1 || exit 55 # expected to pass 14 | 15 | # Make sure we don't leave this lying around for future runs, or redo 16 | # might mark it as "manually modified" (since we did!) 17 | rm -f fail 18 | 19 | rm -f maybe-fail 20 | : >want-fail 21 | ! redo-ifchange maybe-fail >/dev/null 2>&1 || exit 66 22 | rm -f want-fail 23 | ../flush-cache 24 | redo-ifchange maybe-fail || exit 67 # failed last time, must retry 25 | : >want-fail 26 | ../flush-cache 27 | redo-ifchange maybe-fail || exit 68 # passed last time, no dep, no redo 28 | rm -f want-fail 29 | -------------------------------------------------------------------------------- /contrib/bash_completion.d/redo: -------------------------------------------------------------------------------- 1 | __find_redo_targets() 2 | { 3 | local IFS=$'\n:' 4 | for d in . ../.. $PATH; do 5 | if [ -x "$d/redo-targets" ]; then 6 | ( cd "$d" && echo "$PWD/redo-targets" ) 7 | break 8 | fi 9 | done 10 | } 11 | __redo_targets=$(__find_redo_targets) 12 | 13 | 14 | __redo_completions() 15 | { 16 | local cur="${COMP_WORDS[COMP_CWORD]}" 17 | local IFS=$'\n' 18 | local targets=$( 19 | # targets already known to redo 20 | [ -x "$__redo_targets" ] && 21 | "$__redo_targets" | 22 | while read name; do 23 | rest=${name#$cur} 24 | [ "$cur$rest" != "$name" ] && continue 25 | name2="$cur${rest%%/*}" 26 | [ -d "$name2/." ] || echo "$name2" 27 | done 28 | 29 | # targets named explicitly by .do files 30 | compgen -o default "$cur" | 31 | while read name; do 32 | local don=${name%.do} def=${name#default.} 33 | [ "$don" = "$name" -o "$def" != "$name" ] && continue 34 | echo "${name%.do}" 35 | done 36 | ) 37 | COMPREPLY=($(compgen -W "$targets" "$cur")) 38 | } 39 | 40 | complete -F __redo_completions -o plusdirs -o filenames redo do 41 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.runkvm.do: -------------------------------------------------------------------------------- 1 | ./need.sh python kvm busybox 2 | 3 | redo-ifchange "$2.initrd" memcalc.py 4 | rm -f "$1.out" "$1.code" 5 | 6 | # Linux only allows an initrd of size < 50% of RAM, 7 | # so set a RAM amount based on the initrd size. 8 | mem=$(./memcalc.py "$2.initrd") 9 | echo "$2: kvm memory required: $mem" >&2 10 | 11 | kvm \ 12 | -m "$mem" \ 13 | -kernel /boot/vmlinuz-$(uname -r) \ 14 | -initrd "$2.initrd" \ 15 | -append 'rdinit=/rdinit panic=1 console=ttyS0 loglevel=4' \ 16 | -no-reboot \ 17 | -display none \ 18 | -chardev stdio,mux=on,id=char0 \ 19 | -chardev file,id=char1,path="$1.out" \ 20 | -chardev file,id=char2,path="$1.code" \ 21 | -serial chardev:char0 \ 22 | -serial chardev:char1 \ 23 | -serial chardev:char2 >&2 24 | fix_cr() { 25 | # serial devices use crlf (\r\n) as line 26 | # endings instead of just lf (\n). 27 | sed -e 's/\r//g' 28 | } 29 | rv=$(fix_cr <"$1.code") 30 | [ -n "$rv" ] || exit 99 31 | if [ "$rv" -eq 0 ]; then 32 | fix_cr <"$1.out" >$3 33 | echo "ok." >&2 34 | else 35 | echo "kvm program returned error: $rv" >&2 36 | fi 37 | exit "$rv" 38 | -------------------------------------------------------------------------------- /t/all.do: -------------------------------------------------------------------------------- 1 | redo-ifchange flush-cache 2 | 3 | # tests that "set -e" works (.do scripts always run with -e set by default) 4 | rm -f 000-set-minus-e/log 5 | redo 000-set-minus-e/all 6 | if [ "$(cat 000-set-minus-e/log)" != "ok" ]; then 7 | echo "FATAL! .do file not run with 'set -e' in effect!" >&2 8 | exit 5 9 | fi 10 | 11 | # builds 1xx*/all to test for basic/dangerous functionality. 12 | # We don't want to run more advanced tests if the basics don't work. 13 | /bin/ls 1[0-9][0-9]*/all.do | 14 | sed 's/\.do$//' | 15 | xargs redo 16 | 110-compile/hello >&2 17 | 18 | # builds most of the rest in parallel 19 | /bin/ls [2-9][0-9][0-9]*/all.do | 20 | sed 's/\.do$//' | 21 | xargs redo 22 | 23 | # builds the tests that require non-parallel execution. 24 | # If tests are written carefully, this should only be things that 25 | # are checking for unnecessary extra rebuilds of some targets, which 26 | # might happen after flush-cache. 27 | # FIXME: a better solution might be to make flush-cache less destructive! 28 | /bin/ls [s][0-9][0-9]*/all.do | 29 | sed 's/\.do$//' | { 30 | while read d; do 31 | redo "$d" 32 | done 33 | } 34 | -------------------------------------------------------------------------------- /redo/cmd_whichdo.py: -------------------------------------------------------------------------------- 1 | """redo-whichdo: list the set of .do files considered to build a target.""" 2 | import sys, os 3 | from . import env, logs, paths 4 | from .logs import err 5 | 6 | 7 | def main(): 8 | if len(sys.argv[1:]) != 1: 9 | sys.stderr.write('%s: exactly one argument expected.\n' % sys.argv[0]) 10 | sys.exit(1) 11 | 12 | env.init_no_state() 13 | logs.setup( 14 | tty=sys.stderr, parent_logs=env.v.LOG, 15 | pretty=env.v.PRETTY, color=env.v.COLOR) 16 | 17 | want = sys.argv[1] 18 | if not want: 19 | err('cannot build the empty target ("").\n') 20 | sys.exit(204) 21 | 22 | abswant = os.path.abspath(want) 23 | pdf = paths.possible_do_files(abswant) 24 | for dodir, dofile, basedir, basename, ext in pdf: 25 | dopath = os.path.join('/', dodir, dofile) 26 | relpath = os.path.relpath(dopath, '.') 27 | exists = os.path.exists(dopath) 28 | assert '\n' not in relpath 29 | print(relpath) 30 | if exists: 31 | sys.exit(0) 32 | sys.exit(1) # no appropriate dofile found 33 | 34 | 35 | if __name__ == '__main__': 36 | main() 37 | -------------------------------------------------------------------------------- /docs/cookbook/container/default.image.do: -------------------------------------------------------------------------------- 1 | redo-ifchange template.json "$1.layers" 2 | layers=$(cat "$1.layers") 3 | 4 | dir=$3.tmp 5 | rm -rf "$dir" 6 | mkdir -p "$dir" 7 | 8 | # Build all layers in parallel 9 | for layer in $layers; do 10 | echo "$layer.list.sha256" 11 | echo "$layer.layer" 12 | done | xargs redo-ifchange 13 | 14 | ids= 15 | parent= 16 | for layer in $layers; do 17 | read cid <$layer.list.sha256 18 | echo "layer: $cid $layer" >&2 19 | 20 | # docker seems to order its image tarballs latest-first, 21 | # so the base layer is last. We'll create in order from 22 | # base layer to final layer, but create a tarball in the 23 | # opposite order. 24 | ids="$cid $ids" # prepend 25 | 26 | mkdir "$dir/$cid" 27 | echo "1.0" >$dir/$cid/VERSION 28 | ./dockjson.py "$layer" "$parent" >$dir/$cid/json 29 | ln "$layer.layer" "$dir/$cid/layer.tar" 30 | parent=$layer 31 | done <$1.layers 32 | last_cid=$cid 33 | 34 | # The seemingly-redundant "repositories" file seems to be needed by newer 35 | # docker versions. 36 | cat >"$dir/repositories" <<-EOF 37 | { 38 | "$2":{ 39 | "latest":"$last_cid" 40 | } 41 | } 42 | EOF 43 | 44 | tar -C "$dir" -cf - $ids repositories >$3 45 | rm -rf "$dir" 46 | -------------------------------------------------------------------------------- /docs/cookbook/redoconf-simple/all.rc.od: -------------------------------------------------------------------------------- 1 | # Specify which redoconf modules to use when building 2 | # our program. 3 | # 4 | # The rc_include function is available in every *.od 5 | # script in a redoconf project. 6 | rc_include \ 7 | rc/CXX.required.rc \ 8 | rc/Wextra.rc \ 9 | rc/all.hpp.precompiled.rc \ 10 | rc/openssl__ssl.h.rc \ 11 | rc/openssl__opensslv.h.rc \ 12 | rc/libssl.rc \ 13 | rc/libm.rc 14 | 15 | # We'll link *all* our binaries with the detected 16 | # $LIBSSL by default. We rc_included rc/libssl.rc 17 | # instead of rc/libssl.required.rc, so if it's 18 | # not available, this line won't add any 19 | # libraries. It'll be up to the program to check 20 | # for HAVE_LIBSSL before trying to call it. 21 | # 22 | # If we wanted to only link $LIBSSL into certain 23 | # binaries, we would include $LIBSSL explicitly in 24 | # the .list.od file for those binaries. Since we're 25 | # putting it here, it doesn't have to be in the .list 26 | # file. 27 | rc_appendln LIBS "$LIBSSL" 28 | 29 | # Combine all the redoconf settings we've collected 30 | # above, and write them to $3 (all.rc). all.rc is 31 | # a special .rc file that is used when generating 32 | # the automatic ./compile and ./link scripts, among 33 | # others. 34 | rc_save 35 | -------------------------------------------------------------------------------- /t/350-deps/override/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | rm -f a b *.log stamp 3 | 4 | echo 1 >stamp 5 | redo b 6 | [ "$(cat b)" = "hello-a-1-b" ] || exit 11 7 | 8 | ../../flush-cache 9 | echo 2 >stamp 10 | redo-ifchange b 11 | [ "$(cat b)" = "hello-a-1-b" ] || exit 21 # a unchanged; b not redone 12 | 13 | . ../../skip-if-minimal-do.sh 14 | 15 | # Unfortunately the test below depends on the specific wording of the 16 | # "override" warning message, of the form: 17 | # redo: a - you modified it; skipping 18 | # That's because this is specifically a test that the warning message 19 | # gets generated. I added that test because (of course) when we didn't 20 | # test it, the warning message accidentally got broken. Oops. If you 21 | # rephrase the message, you'll have to also change the test. 22 | 23 | ../../flush-cache 24 | echo 3 >stamp 25 | echo over-a >a 26 | redo-ifchange b >$1.log 2>&1 27 | [ "$(cat b)" = "over-a-3-b" ] || exit 31 # a overwritten, b redone 28 | grep "a - " "$1.log" >/dev/null || exit 32 # expected a warning msg 29 | 30 | ../../flush-cache 31 | echo 4 >stamp 32 | redo-ifchange b >$1.log 2>&1 33 | [ "$(cat b)" = "over-a-3-b" ] || exit 41 # a not changed, b not redone 34 | grep "a - " "$1.log" >/dev/null || exit 42 # still expect a warning msg 35 | -------------------------------------------------------------------------------- /redo/cmd_ood.py: -------------------------------------------------------------------------------- 1 | """redo-ood: list out-of-date (ood) targets.""" 2 | from __future__ import print_function 3 | import sys, os 4 | from . import deps, env, logs, state 5 | 6 | cache = {} 7 | 8 | 9 | def is_checked(f): 10 | return cache.get(f.id, 0) 11 | 12 | 13 | def set_checked(f): 14 | cache[f.id] = 1 15 | 16 | 17 | def log_override(name): 18 | pass 19 | 20 | 21 | def main(): 22 | if len(sys.argv[1:]) != 0: 23 | sys.stderr.write('%s: no arguments expected.\n' % sys.argv[0]) 24 | sys.exit(1) 25 | 26 | state.init([]) 27 | logs.setup( 28 | tty=sys.stderr, parent_logs=env.v.LOG, 29 | pretty=env.v.PRETTY, color=env.v.COLOR) 30 | cwd = os.getcwd() 31 | for f in state.files(): 32 | if f.is_target(): 33 | if deps.isdirty(f, 34 | depth='', 35 | max_changed=env.v.RUNID, 36 | already_checked=[], 37 | is_checked=is_checked, 38 | set_checked=set_checked, 39 | log_override=log_override): 40 | print(state.relpath(os.path.join(env.v.BASE, f.name), cwd)) 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /docs/redo-ifcreate.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | redo-ifcreate - rebuild the current target if source files are created 4 | 5 | # SYNOPSIS 6 | 7 | redo-ifcreate [sources...] 8 | 9 | 10 | # DESCRIPTION 11 | 12 | Normally redo-ifcreate is run from a .do file that has been 13 | executed by `redo`(1). See `redo`(1) for more details. 14 | 15 | redo-ifcreate takes a list of nonexistent files (*sources*) 16 | and adds them as dependencies to the current target (the 17 | one calling redo-ifcreate). If any of those files are 18 | created in the future, the target will be marked as needing 19 | to be rebuilt. 20 | 21 | If one of the given files exists at the time redo-ifcreate 22 | is called, it will return a nonzero exit code. 23 | 24 | If you want to declare dependencies on files that already 25 | exist, use `redo-ifchange`(1) instead. 26 | 27 | 28 | # REDO 29 | 30 | Part of the `redo`(1) suite. 31 | 32 | # CREDITS 33 | 34 | The original concept for `redo` was created by D. J. 35 | Bernstein and documented on his web site 36 | (http://cr.yp.to/redo.html). This independent implementation 37 | was created by Avery Pennarun and you can find its source 38 | code at http://github.com/apenwarr/redo. 39 | 40 | 41 | # SEE ALSO 42 | 43 | `redo`(1), `redo-ifchange`(1), `redo-always`(1), `redo-stamp`(1) 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # redo - a recursive build system 2 | 3 | Smaller, easier, more powerful, and more reliable than `make`. 4 | 5 | This is an implementation of [Daniel J. Bernstein's redo 6 | build system](http://cr.yp.to/redo.html). He never released his 7 | version, so other people have implemented different variants based on his 8 | published specification. 9 | 10 | This version, sometimes called apenwarr/redo, is probably the most advanced 11 | one, including parallel builds, improved logging, extensive automated tests, 12 | and helpful debugging features. 13 | 14 | To build and test redo, run: 15 | ```sh 16 | ./do -j10 test 17 | ``` 18 | 19 | To install it, run something like this: 20 | ```sh 21 | DESTDIR= PREFIX=/usr/local ./do -j10 install 22 | ``` 23 | 24 | --- 25 | 26 | - View the [documentation](https://redo.rtfd.io) via readthedocs.org 27 | - Visit the [source code](https://github.com/apenwarr/redo) on github 28 | - Discussions and support via the 29 | mailing list ([archives](https://groups.google.com/group/redo-list)). 30 | You can subscribe by sending any email message to 31 | `redo-list+subscribe@googlegroups.com` (note the plus sign). You can 32 | send questions or feedback (with or without subscribing) by sending 33 | messages to `redo-list@googlegroups.com`. 34 | -------------------------------------------------------------------------------- /install.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | 3 | : ${INSTALL:=install} 4 | : ${DESTDIR=NONE} 5 | : ${PREFIX:=/usr} 6 | : ${MANDIR:=$DESTDIR$PREFIX/share/man} 7 | : ${DOCDIR:=$DESTDIR$PREFIX/share/doc/redo} 8 | : ${BINDIR:=$DESTDIR$PREFIX/bin} 9 | : ${LIBDIR:=$DESTDIR$PREFIX/lib/redo} 10 | 11 | if [ "$DESTDIR" = "NONE" ]; then 12 | echo "$0: fatal: set DESTDIR before trying to install." 13 | exit 99 14 | fi 15 | 16 | redo-ifchange all redo/whichpython 17 | read py &2 2 | 3 | # Testing the search path for non-existent do files is a little tricky. 4 | # We can't be sure where our current directory is, so we don't know how 5 | # far up the stack redo will need to search. 6 | # 7 | # To dodge the problem, let's "cd /" first so that we're testing a target 8 | # relative to a known location (the root directory). 9 | 10 | if [ -e '/default.do' -o \ 11 | -e '/default.z.do' -o \ 12 | -e '/default.y.z.do' ]; then 13 | echo "Weird: /default.*.do exists; can't run this test." 14 | exit 99 15 | fi 16 | 17 | # redo-whichdo *should* fail here, so don't abort the script for that. 18 | set +e 19 | a=$(cd / && redo-whichdo __nonexist/a/x.y.z) 20 | rv=$? 21 | set -e 22 | 23 | if [ "$rv" -eq 0 ]; then 24 | echo "redo-whichdo should return nonzero for a missing .do file." 25 | exit 10 26 | fi 27 | 28 | b=$(cat <&2 27 | if ! grep "^Hello" "$3" >/dev/null; then 28 | echo "Hello program did not say hello!" >&2 29 | exit 10 30 | fi 31 | else 32 | echo "Non-native platform: test skipped." >&2 33 | fi 34 | -------------------------------------------------------------------------------- /redoconf/rc/shlib.rc.od: -------------------------------------------------------------------------------- 1 | rc_include rc/CC.rc 2 | 3 | prog=' 4 | #include 5 | void f() { atoi(""); } 6 | ' 7 | 8 | try_unix_style() { 9 | ( 10 | appendln CFLAGS "-fPIC" 11 | appendln LDFLAGS "-shared" 12 | appendln LDFLAGS "-Wl,-soname,x.so" 13 | RCC_NO_MAIN=1 rc_compile cc link "$prog" 14 | ) 15 | } 16 | 17 | try_macos_style() { 18 | ( 19 | appendln CFLAGS "-fPIC" 20 | appendln LDFLAGS "-dynamiclib" 21 | appendln LDFLAGS "-current_version" 22 | appendln LDFLAGS "1.0" 23 | RCC_NO_MAIN=1 rc_compile cc link "$prog" 24 | ) 25 | } 26 | 27 | if [ -n "$STATIC" ]; then 28 | echo "--enable-static specified; not building shared libraries." >&2 29 | rc_replaceln HAVE_SHLIB "STATIC" 30 | elif [ -n "$NOSHARED" ]; then 31 | echo "--disable-shared specified; not building shared libraries." >&2 32 | rc_replaceln HAVE_SHLIB "STATIC" 33 | elif try_unix_style; then 34 | rc_replaceln HAVE_SHLIB UNIX 35 | elif try_macos_style; then 36 | rc_replaceln HAVE_SHLIB MACOS 37 | else 38 | echo "Not building shared libraries on this platform." >&2 39 | rc_replaceln HAVE_SHLIB "STATIC" 40 | fi 41 | 42 | if [ "$HAVE_SHLIB" != "STATIC" ]; then 43 | x='-Wl,-z,origin' 44 | if (appendln LDFLAGS "$x" && rc_compile cc link); then 45 | rc_appendln LDFLAGS "$x" 46 | fi 47 | 48 | x='-Wl,-rpath,$ORIGIN' 49 | if (appendln LDFLAGS "$x" && rc_compile cc link); then 50 | rc_appendln LDFLAGS "$x" 51 | fi 52 | fi 53 | 54 | rc_save 55 | -------------------------------------------------------------------------------- /t/102-empty/touchtest.do: -------------------------------------------------------------------------------- 1 | # This may have been leftover from a previous run, when switching 2 | # between "real" redo and minimal/do, so clean it up. 3 | rm -f touch1 4 | 5 | # simply create touch1 6 | echo 'echo hello' >touch1.do 7 | redo touch1 8 | [ -e touch1 ] || exit 55 9 | [ "$(cat touch1)" = "hello" ] || exit 56 10 | 11 | # ensure that 'redo touch1' always re-runs touch1.do even if we have 12 | # already built touch1 in this session, and even if touch1 already exists. 13 | echo 'echo hello2' >touch1.do 14 | redo touch1 15 | [ "$(cat touch1)" = "hello2" ] || exit 57 16 | 17 | # ensure that touch1 is rebuilt even if it got deleted after the last redo 18 | # inside the same session. Also ensure that we can produce a zero-byte 19 | # output file explicitly. 20 | rm -f touch1 21 | echo 'touch $3' >touch1.do 22 | redo touch1 23 | [ -e touch1 ] || exit 66 24 | [ -z "$(cat touch1)" ] || exit 67 25 | 26 | # Also test that zero bytes of output does not create the file at all, as 27 | # opposed to creating a zero-byte file. 28 | rm -f touch1 29 | echo 'touch touch1-ran' >touch1.do 30 | redo touch1 31 | [ -e touch1 ] && exit 75 32 | [ -e touch1-ran ] || exit 76 33 | rm -f touch1-ran 34 | 35 | # Make sure that redo-ifchange *won't* rebuild touch1 if we have already 36 | # built it, even if building it did not produce an output file. 37 | redo-ifchange touch1 38 | [ -e touch1 ] && exit 77 39 | [ -e touch1-ran ] && exit 78 40 | 41 | rm -f touch1.do 42 | -------------------------------------------------------------------------------- /docs/redo-sources.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | redo-sources - print the list of all known redo sources 4 | 5 | # SYNOPSIS 6 | 7 | redo-sources 8 | 9 | 10 | # DESCRIPTION 11 | 12 | redo-sources prints a list of all redo *source* files that 13 | still exist. 14 | 15 | A source file is any file that has been listed as a 16 | dependency (using `redo-ifchange`(1) or `redo-ifcreate`(1)) 17 | but is not itself a target. A target is a file that 18 | `redo`(1) can build using a .do script. 19 | 20 | Each filename is on a separate line. The filenames are not 21 | guaranteed to be in any particular order. 22 | 23 | All filenames are printed relative the current directory. 24 | The list is not filtered in any way; it contains *all* the 25 | source filenames from the entire project. Remember that 26 | the redo database may span more than just your project, so 27 | you might need to filter the list before using it. 28 | 29 | If you want a list of targets instead of sources, use 30 | `redo-targets`(1) or `redo-ood`(1). 31 | 32 | 33 | # REDO 34 | 35 | Part of the `redo`(1) suite. 36 | 37 | # CREDITS 38 | 39 | The original concept for `redo` was created by D. J. 40 | Bernstein and documented on his web site 41 | (http://cr.yp.to/redo.html). This independent implementation 42 | was created by Avery Pennarun and you can find its source 43 | code at http://github.com/apenwarr/redo. 44 | 45 | 46 | # SEE ALSO 47 | 48 | `redo`(1), `redo-targets`(1), `redo-ood`(1) 49 | -------------------------------------------------------------------------------- /redoconf/link-shlib.od: -------------------------------------------------------------------------------- 1 | rc_include _all.rc 2 | 3 | # Tricky quoting: see _compile.od for details. 4 | if [ "$HAVE_SHLIB" = UNIX ]; then 5 | cat >$3 <<-EOF 6 | #!/bin/sh -e 7 | LINK=$(shquote "$LINK") 8 | LDFLAGS=$(shquote "$LDFLAGS") 9 | OPTFLAGS=$(shquote "$OPTFLAGS") 10 | LIBS=$(shquote "$LIBS") 11 | o="\$1" 12 | ob="\${o#*/}" 13 | shift 14 | IFS="$NL" 15 | set -f 16 | \$LINK -shared -o "\$o" \\ 17 | -Wl,-soname,"\$ob" \\ 18 | \$LDFLAGS \$OPTFLAGS \\ 19 | "\$@" \\ 20 | \$xLIBS \$LIBS 21 | EOF 22 | elif [ "$HAVE_SHLIB" = MACOS ]; then 23 | cat >$3 <<-EOF 24 | #!/bin/sh -e 25 | LINK=$(shquote "$LINK") 26 | LDFLAGS=$(shquote "$LDFLAGS") 27 | OPTFLAGS=$(shquote "$OPTFLAGS") 28 | LIBS=$(shquote "$LIBS") 29 | LIBDIR=$(shquote "$LIBDIR") 30 | o="\$1" 31 | ob="\${o#*/}" 32 | shift 33 | IFS="$NL" 34 | set -f 35 | \$LINK -dynamiclib -o "\$o" \\ 36 | -install_name "\$ob" \\ 37 | \$LDFLAGS \$OPTFLAGS \\ 38 | "\$@" \\ 39 | \$xLIBS \$LIBS 40 | EOF 41 | else 42 | if [ -z "$HAVE_SHLIB" ]; then 43 | echo "link-shlib.od: fatal:" \ 44 | "must include rc/shlib.rc to use shared libraries." >&2 45 | exit 90 46 | fi 47 | 48 | # If no shared library support and we try to build one, 49 | # compensate by building a static library instead in the 50 | # same place. 51 | cat >$3 <<-EOF 52 | #!/bin/sh -e 53 | o="\$1" 54 | shift 55 | rm -f "\$o" 56 | ar q "\$o" "\$@" 57 | EOF 58 | fi 59 | chmod a+x "$3" 60 | redo-stamp <$3 61 | -------------------------------------------------------------------------------- /redoconf/_all.rc.od: -------------------------------------------------------------------------------- 1 | . ./redoconf.rc 2 | 3 | # replace the placeholder for this function with 4 | # one that will save help messages for later. 5 | HELP="configure.help.new" 6 | rm -f "$HELP" 7 | echo '# Automatically generated by redoconf/_all.rc.od - do not edit' >"$HELP" 8 | helpmsg() { 9 | printf '%-11s %s\n' "$1" "$2" >>"$HELP" 10 | rc_hook "$1" 11 | } 12 | 13 | # Remember initial set of keys provided by ./configure 14 | orig_keys="" 15 | rc_hook() { 16 | contains_line "$orig_keys" "$1" || orig_keys="$orig_keys$NL$1" 17 | } 18 | 19 | # Include the rest of the necessary .rc files 20 | keys="" 21 | rc_hook() { 22 | contains_line "$new_keys" "$1" || new_keys="$new_keys$NL$1" 23 | } 24 | allrc= 25 | if [ -e "$S/all.rc.od" ]; then 26 | allrc=all.rc 27 | else 28 | allrc= 29 | redo-ifcreate "$S/all.rc.od" 30 | fi 31 | rc_include rc/_init.rc rc/CC.rc rc/zdefs.rc $allrc 32 | 33 | rc_helpmsg PREFIX "Change installation prefix (usually /usr/local)" 34 | 35 | IFS="$NL" 36 | unused= 37 | for d in $orig_keys; do 38 | if ! contains_line "$new_keys" "$d"; then 39 | unused=1 40 | xecho "Error: '$d' was given to ./configure but not used." >&2 41 | fi 42 | done 43 | [ -z "$unused" ] || exit 1 44 | 45 | rc_save 46 | 47 | # Now that all the rc files have run, update $S/configure.help with the 48 | # newly-generated help text, so it's available to new users. 49 | # Even if multiple output dirs are building at once, this replaces the 50 | # file atomically, so it should be safe. 51 | mv "$HELP" "$S/configure.help" 52 | -------------------------------------------------------------------------------- /redo/cmd_unlocked.py: -------------------------------------------------------------------------------- 1 | """redo-unlocked: internal tool for building dependencies.""" 2 | import sys, os 3 | from . import env, logs, state 4 | 5 | 6 | def main(): 7 | if len(sys.argv[1:]) < 2: 8 | sys.stderr.write('%s: at least 2 arguments expected.\n' % sys.argv[0]) 9 | sys.exit(1) 10 | 11 | env.inherit() 12 | logs.setup( 13 | tty=sys.stderr, parent_logs=env.v.LOG, 14 | pretty=env.v.PRETTY, color=env.v.COLOR) 15 | 16 | target = sys.argv[1] 17 | deps = sys.argv[2:] 18 | 19 | for d in deps: 20 | assert d != target 21 | 22 | me = state.File(name=target) 23 | 24 | # Build the known dependencies of our primary target. This *does* require 25 | # grabbing locks. 26 | os.environ['REDO_NO_OOB'] = '1' 27 | argv = ['redo-ifchange'] + deps 28 | rv = os.spawnvp(os.P_WAIT, argv[0], argv) 29 | if rv: 30 | sys.exit(rv) 31 | 32 | # We know our caller already owns the lock on target, so we don't have to 33 | # acquire another one; tell redo-ifchange about that. Also, REDO_NO_OOB 34 | # persists from up above, because we don't want to do OOB now either. 35 | # (Actually it's most important for the primary target, since it's the one 36 | # who initiated the OOB in the first place.) 37 | os.environ['REDO_UNLOCKED'] = '1' 38 | argv = ['redo-ifchange', target] 39 | rv = os.spawnvp(os.P_WAIT, argv[0], argv) 40 | if rv: 41 | sys.exit(rv) 42 | 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /redoconf/trycompile: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | die() { 3 | echo "$0: trycompile: $*" >&2 4 | exit 99 5 | } 6 | 7 | ctype=$1 8 | linktype=$2 9 | code=$3 10 | case $ctype in 11 | cc) 12 | [ -n "$CC" ] || die 'must set $CC first.' 13 | useCC="$CC" 14 | useCF="$CFLAGS" 15 | useExt=".c" 16 | ;; 17 | cxx) 18 | [ -n "$CXX" ] || die 'must set $CXX first.' 19 | useCC="$CXX" 20 | useCF="$CXXFLAGS" 21 | useExt=".cc" 22 | ;; 23 | *) 24 | die "unknown compile type '$ctype'" 25 | ;; 26 | esac 27 | case $linktype in 28 | link|run) 29 | [ -n "$LINK" ] || die 'must set $LINK first.' 30 | ;; 31 | nolink) 32 | ;; 33 | *) 34 | die "unknown link type '$linktype'" 35 | ;; 36 | esac 37 | base="try.$$.tmp" 38 | out="$base.o" 39 | out2="$base.exe" 40 | src="$base$useExt" 41 | rm -f "$src" "$out" "$out2" 42 | set -x 43 | : "[trycompile]" "$@" 44 | main= 45 | [ -n "$RCC_NO_MAIN" ] || main="int main() { return 0; }" 46 | printf '%s' " 47 | $code 48 | 49 | $main 50 | " >"$src" 51 | NL=" 52 | " 53 | IFS="$NL" 54 | set +e 55 | set -f 56 | # We intentionally want to split the variables here, 57 | # splitting on $NL, so we don't quote them. 58 | # 'set -f' prevents interpreting wildcards, which 59 | # we don't want to treat as special. 60 | ( 61 | $useCC $CPPFLAGS $useCF -o "$out" -c "$src" || exit 62 | if [ "$linktype" = "link" -o "$linktype" = "run" ]; then 63 | $LINK $LDFLAGS -o "$out2" "$out" $LIBS || exit 64 | fi 65 | if [ "$linktype" = "run" ]; then 66 | $RUN "./$out2" || exit 67 | fi 68 | ) 69 | rv=$? 70 | rm -f "$src" "$out" "$out2" 71 | exit "$rv" 72 | -------------------------------------------------------------------------------- /redoconf/compile.od: -------------------------------------------------------------------------------- 1 | rc_include _all.rc 2 | redo-ifchange _compile 3 | 4 | # Subtle: 5 | # - un-backslashed $ expansions ($foo, $(cmd)) are 6 | # done *now*, while writing the script contents. 7 | # - backslashed $ expansions (\$foo) are written 8 | # verbatim into the script, to be interpreted at 9 | # the time the script is run. 10 | # 11 | # We want to insert the variable contents into the 12 | # script near the top, making sure they are not 13 | # split or interpreted at that point (hence the 14 | # $(shquote)). 15 | # 16 | # Further down, we want to disable wildcard expansion 17 | # (set -f) and split on $NL (so we change $IFS), 18 | # so we use backslash escapes but *not* quoting. 19 | 20 | cat >$3 <<-EOF 21 | #!/bin/sh -e 22 | # Run the C/++ compiler. 23 | t="\$1" d="\$2" i="\$3" 24 | CPPFLAGS=$(shquote "$CPPFLAGS") 25 | OPTFLAGS=$(shquote "$OPTFLAGS") 26 | case \$i in 27 | *.c|*.h) 28 | CC=$(shquote "$CC") 29 | CFLAGS=$(shquote "$CFLAGS") 30 | CXXFLAGS= 31 | PCH1=$(shquote "$CFLAGS_PCH") 32 | PCH2=$(shquote "$CFLAGS_PCH_FPIC") 33 | PCH3=$(shquote "$CFLAGS_PCH_LANG") 34 | ;; 35 | *) 36 | CC=$(shquote "$CXX") 37 | [ -n "\$CC" ] || (echo "No C++ compiler available." >&2; exit 1) 38 | CFLAGS= 39 | CXXFLAGS=$(shquote "$CXXFLAGS") 40 | PCH1=$(shquote "$CXXFLAGS_PCH") 41 | PCH2=$(shquote "$CXXFLAGS_PCH_FPIC") 42 | PCH3=$(shquote "$CXXFLAGS_PCH_LANG") 43 | ;; 44 | esac 45 | case \$PCH in 46 | 1) FLAGS_PCH=\$PCH1 ;; 47 | 2) FLAGS_PCH=\$PCH2 ;; 48 | 3) FLAGS_PCH=\$PCH3 ;; 49 | esac 50 | . ./_compile 51 | EOF 52 | chmod a+x "$3" 53 | redo-stamp <$3 54 | -------------------------------------------------------------------------------- /docs/redo-always.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | redo-always - mark the current target as always needing to be rebuilt 4 | 5 | # SYNOPSIS 6 | 7 | redo-always 8 | 9 | 10 | # DESCRIPTION 11 | 12 | Normally redo-always is run from a .do file that has been 13 | executed by `redo`(1). See `redo`(1) for more details. 14 | 15 | redo-always takes no parameters. It simply adds an 16 | 'impossible' dependency to the current target, which 17 | ensures that the target will always be rebuilt if anyone 18 | runs `redo-ifchange targetname`. 19 | 20 | Because of the way redo works, `redo-ifchange targetname` 21 | will only rebuild `targetname` once per session. So if 22 | multiple targets depend on *targetname* and *targetname* 23 | has called redo-always, only the first target will cause it 24 | to be rebuilt. If the build cycle completes and a new one 25 | begins, it will be rebuilt exactly one more time. 26 | 27 | Normally, any target that depends (directly or indirectly) 28 | on a sub-target that has called redo-always will also 29 | always need to rebuild, since one of its dependencies will 30 | always be out of date. To avoid this problem, redo-always is 31 | usually used along with `redo-stamp`(1). 32 | 33 | 34 | # REDO 35 | 36 | Part of the `redo`(1) suite. 37 | 38 | # CREDITS 39 | 40 | The original concept for `redo` was created by D. J. 41 | Bernstein and documented on his web site 42 | (http://cr.yp.to/redo.html). This independent implementation 43 | was created by Avery Pennarun and you can find its source 44 | code at http://github.com/apenwarr/redo. 45 | 46 | 47 | # SEE ALSO 48 | 49 | `redo`(1), `redo-ifcreate`(1), `redo-ifchange`(1), `redo-stamp`(1) 50 | -------------------------------------------------------------------------------- /docs/cookbook/c/monotime.c: -------------------------------------------------------------------------------- 1 | #define __GNU_SOURCE 2 | /* 3 | * Returns the kernel monotonic timestamp in microseconds. 4 | * This function never returns the value 0; it returns 1 instead, so that 5 | * 0 can be used as a magic value. 6 | */ 7 | #include "monotime.h" 8 | #include "redoconf.h" 9 | 10 | #if HAVE_CLOCK_GETTIME 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | long long monotime(void) { 17 | struct timespec ts; 18 | if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { 19 | perror("clock_gettime"); 20 | exit(98); /* really should never happen, so don't try to recover */ 21 | } 22 | long long result = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; 23 | return !result ? 1 : result; 24 | } 25 | 26 | #elif HAVE_MACH__MACH_TIME_H 27 | 28 | #include 29 | #include 30 | 31 | long long monotime(void) { 32 | static mach_timebase_info_data_t timebase; 33 | if (!timebase.denom) mach_timebase_info(&timebase); 34 | long long result = (mach_absolute_time() * timebase.numer / 35 | timebase.denom / 1000); 36 | return !result ? 1 : result; 37 | } 38 | 39 | #elif HAVE_WINDOWS_H 40 | 41 | #include 42 | 43 | /* WARNING: Not carefully tested. It might wrap around unexpectedly. 44 | * Based on suggestions from: 45 | * https://stackoverflow.com/questions/211257/windows-monotonic-clock 46 | */ 47 | long long monotime(void) { 48 | LARGE_INTEGER tps, t; 49 | QueryPerformanceFrequency(&tps); 50 | QueryPerformanceCounter(&t); 51 | return t.QuadPart * 1000000LL / tps.QuadPart; 52 | } 53 | 54 | #else 55 | 56 | #error "No monotonic time function is available" 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /docs/GettingStarted.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | Currently, this version of redo requires python2.7 and the python2.7 sqlite3 module. 4 | Optional, but recommended, is the 5 | [setproctitle](http://code.google.com/p/py-setproctitle/) module, which makes your 6 | `ps` output prettier. 7 | 8 | In modern versions of Debian, sqlite3 is already part of the python2.7 package. 9 | You can install the prerequisites like this: 10 | ```sh 11 | sudo apt-get install python2.7 python-setproctitle 12 | ``` 13 | (If you have install instructions for other OSes, please add them here :)) 14 | 15 | 16 | # Clone, compile, and test redo 17 | 18 | You can run redo without installing it, like this: 19 | ```sh 20 | git clone https://github.com/apenwarr/redo 21 | cd redo 22 | ./do -j10 test 23 | ``` 24 | 25 | If the tests pass, you can either add $PWD/redo/bin to your PATH, or install 26 | redo on your system. To install for all users, put it in /usr/local: 27 | 28 | ```sh 29 | DESTDIR= PREFIX=/usr/local sudo -E ./do install 30 | ``` 31 | 32 | Or to install it just for yourself (without needing root access), put it in 33 | your home directory: 34 | ```sh 35 | DESTDIR= PREFIX=$HOME ./do install 36 | ``` 37 | 38 | 39 | # Pre-compiled packages 40 | 41 | ## MacOS 42 | 43 | redo is available from the [Homebrew](https://brew.sh/) project: 44 | 45 | brew install redo 46 | 47 | ## Linux 48 | 49 | Various linux distributions include redo under different names. Most of the 50 | packages are unfortunately obsolete and don't contain the most recent bug 51 | fixes. At this time (late 2018), we recommend using the latest tagged 52 | version [from github](https://github.com/apenwarr/redo). 53 | -------------------------------------------------------------------------------- /docs/redo-ood.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | redo-ood - print the list of out-of-date redo targets 4 | 5 | # SYNOPSIS 6 | 7 | redo-ood 8 | 9 | 10 | # DESCRIPTION 11 | 12 | redo-ood prints a list of all redo *target* files that 13 | exist, but are out of date. 14 | 15 | Files that no longer exist might not be targets anymore; 16 | you'll have to redo them for them to end up back in this 17 | list. (For example, if you built a file and then removed 18 | the file and its .do file, you wouldn't want it to show up 19 | in this list.) 20 | 21 | If a .do script does not produce an output file (eg. 22 | all.do, clean.do), it also does not show up in this list. 23 | 24 | Each filename is on a separate line. The filenames are not 25 | guaranteed to be in any particular order. 26 | 27 | All filenames are printed relative the current directory. 28 | The list is not filtered in any way; it contains *all* the 29 | target filenames from the entire project. Remember that 30 | the redo database may span more than just your project, so 31 | you might need to filter the list before using it. (A 32 | useful heuristic might be to remove any line starting 33 | with '../' since it often refers to a target you don't care 34 | about.) 35 | 36 | If you want a list of all targets, not just out-of-date 37 | ones, use `redo-targets`(1). 38 | 39 | 40 | # REDO 41 | 42 | Part of the `redo`(1) suite. 43 | 44 | # CREDITS 45 | 46 | The original concept for `redo` was created by D. J. 47 | Bernstein and documented on his web site 48 | (http://cr.yp.to/redo.html). This independent implementation 49 | was created by Avery Pennarun and you can find its source 50 | code at http://github.com/apenwarr/redo. 51 | 52 | 53 | # SEE ALSO 54 | 55 | `redo`(1), `redo-targets`(1), `redo-sources`(1) 56 | -------------------------------------------------------------------------------- /docs/cookbook/container/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "architecture": "amd64", 3 | "comment": "Imported from -", 4 | "config": { 5 | "AttachStderr": false, 6 | "AttachStdin": false, 7 | "AttachStdout": false, 8 | "Cmd": [ 9 | "/init" 10 | ], 11 | "CpuShares": 0, 12 | "Cpuset": "", 13 | "Domainname": "", 14 | "Entrypoint": null, 15 | "Env": null, 16 | "ExposedPorts": null, 17 | "Hostname": "", 18 | "Image": "", 19 | "Labels": null, 20 | "MacAddress": "", 21 | "Memory": 0, 22 | "MemorySwap": 0, 23 | "NetworkDisabled": false, 24 | "OnBuild": null, 25 | "OpenStdin": false, 26 | "PortSpecs": null, 27 | "StdinOnce": false, 28 | "Tty": false, 29 | "User": "", 30 | "Volumes": null, 31 | "WorkingDir": "" 32 | }, 33 | "container_config": { 34 | "AttachStderr": false, 35 | "AttachStdin": false, 36 | "AttachStdout": false, 37 | "Cmd": null, 38 | "CpuShares": 0, 39 | "Cpuset": "", 40 | "Domainname": "", 41 | "Entrypoint": null, 42 | "Env": null, 43 | "ExposedPorts": null, 44 | "Hostname": "", 45 | "Image": "", 46 | "Labels": null, 47 | "MacAddress": "", 48 | "Memory": 0, 49 | "MemorySwap": 0, 50 | "NetworkDisabled": false, 51 | "OnBuild": null, 52 | "OpenStdin": false, 53 | "PortSpecs": null, 54 | "StdinOnce": false, 55 | "Tty": false, 56 | "User": "", 57 | "Volumes": null, 58 | "WorkingDir": "" 59 | }, 60 | "docker_version": "1.6.2", 61 | "os": "linux" 62 | } 63 | -------------------------------------------------------------------------------- /redoconf/utils.sh: -------------------------------------------------------------------------------- 1 | NL=" 2 | " 3 | 4 | # Like 'echo', but never processes backslash escapes. 5 | # (Some shells' builtin echo do, and some don't, so this 6 | # is safer.) 7 | xecho() { 8 | printf '%s\n' "$*" 9 | } 10 | 11 | # Returns true if string $1 contains the line $2. 12 | # Lines are delimited by $NL. 13 | contains_line() { 14 | case "$NL$1$NL" in 15 | *"$NL$2$NL"*) return 0 ;; 16 | *) return 1 ;; 17 | esac 18 | } 19 | 20 | # Split the first (up to) 20 words from $1, 21 | # returning a string where the words are separated 22 | # by $NL instead. 23 | # 24 | # To allow words including whitespace, you can backslash 25 | # escape the whitespace (eg. hello\ world). Backslashes 26 | # will be removed from the output string. 27 | # 28 | # We can use this to read pkg-config output, among other 29 | # things. 30 | # 31 | # TODO: find a POSIX sh way to eliminate the word limit. 32 | # I couldn't find an easy way to split on non-backslashed 33 | # whitespace without a fork-exec, which is too slow. 34 | # If we resorted to bashisms, we could use 'read -a', 35 | # but that's not portable. 36 | rc_splitwords() { 37 | xecho "$1" | ( 38 | read v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 \ 39 | v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 \ 40 | x 41 | if [ -n "$x" ]; then 42 | echo "rc_splitwords: too many words" >&2 43 | exit 97 44 | fi 45 | for d in "$v0" "$v1" "$v2" "$v3" "$v4" \ 46 | "$v5" "$v6" "$v7" "$v8" "$v9" \ 47 | "$v10" "$v11" "$v12" "$v13" "$v14" \ 48 | "$v15" "$v16" "$v17" "$v18" "$v19"; do 49 | [ -z "$d" ] || xecho "$d" 50 | done 51 | ) 52 | } 53 | 54 | # Escape single-quote characters so they can 55 | # be included as a sh-style single-quoted string. 56 | shquote() { 57 | printf "'%s'" "$(xecho "$1" | sed -e "s,','\\\\'',g")" 58 | } 59 | -------------------------------------------------------------------------------- /t/370-logs/all.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | rm -f x pid 3 | pid=$$ 4 | echo "$pid" >pid 5 | xout=$(redo x) 6 | 7 | [ "$(printf "$xout" | wc -l)" -eq 0 ] || exit 2 8 | 9 | if [ -n "$REDO_LOG" ]; then 10 | # redo has redo-log support enabled, so check that it saves logs. 11 | 12 | # recursive log dump should show both x and y stderr. 13 | redo-log -ru x | grep -q "^$pid x stderr" || exit 10 14 | redo-log -ru x | grep -q "^$pid y stderr" || exit 11 15 | 16 | # stdout captured by redo into the files x and y, *not* to log 17 | redo-log -ru x | grep -q "^$pid x stdout" && exit 20 18 | redo-log -ru x | grep -q "^$pid y stdout" && exit 21 19 | [ "$(cat x)" = "$pid x stdout" ] || exit 22 20 | [ "$(cat y)" = "$pid y stdout" ] || exit 23 21 | 22 | # non-recursive log dump of x should *not* include y 23 | redo-log x | grep -q "^$pid y stdout" && exit 30 24 | redo-log x | grep -q "^$pid y stderr" && exit 31 25 | 26 | redo a/b/xlog 27 | (cd a && redo b/xlog) 28 | 29 | # Test retrieval from a different $PWD. 30 | ( 31 | cd a/b || exit 40 32 | redo-log -ru ../../x | grep -q "^$pid x stderr" || exit 41 33 | redo-log -ru ../../x | grep -q "^$pid y stderr" || exit 42 34 | ) || exit 35 | fi 36 | 37 | # whether or not redo-log is available, redirecting stderr should work. 38 | pid=$$-bork 39 | rm -f x pid 40 | echo "$pid" >pid 41 | out=$(redo x 2>&1) 42 | 43 | # x's stderr should obviously go where we sent it 44 | echo "$out" | grep -q "^$pid x stderr" || exit 50 45 | 46 | # This one is actually tricky: with redo-log, x's call to 'redo y' would 47 | # normally implicitly redirect y's stderr to a new log. redo needs to 48 | # detect that we've already redirected it where we want, and not take it 49 | # away. 50 | echo "$out" | grep -q "^$pid y stderr" || exit 51 51 | 52 | exit 0 53 | -------------------------------------------------------------------------------- /docs/cookbook/latex/default.runtex.do: -------------------------------------------------------------------------------- 1 | # latex produces log output on stdout, which is 2 | # not really correct. Send it to stderr instead. 3 | exec >&2 4 | 5 | # We depend on both the .latex file and its .deps 6 | # file (which lists additional dependencies) 7 | redo-ifchange "$2.latex" "$2.deps" 8 | 9 | # Next, we have to depend on each dependency in 10 | # the .deps file. 11 | cat "$2.deps" | xargs redo-ifchange 12 | 13 | tmp="$2.tmp" 14 | rm -rf "$tmp" 15 | mkdir -p "$tmp" 16 | 17 | # latex generates eg. the table of contents by 18 | # using a list of references ($2.aux) generated 19 | # during its run. The first time, the table of 20 | # contents is empty, so we have to run again. 21 | # But then the table of contents is non-empty, 22 | # which might cause page numbers to change, and 23 | # so on. So we have to keep re-running until it 24 | # finally stops changing. 25 | touch "$tmp/$2.aux.old" 26 | ok= 27 | for i in $(seq 5); do 28 | latex --halt-on-error \ 29 | --output-directory="$tmp" \ 30 | --recorder \ 31 | "$2.latex" /dev/null; then 34 | # .aux file converged, so we're done 35 | ok=1 36 | break 37 | fi 38 | echo 39 | echo "$0: $2.aux changed: try again (try #$i)" 40 | echo 41 | cp "$tmp/$2.aux" "$tmp/$2.aux.old" 42 | done 43 | 44 | if [ "$ok" = "" ]; then 45 | echo "$0: fatal: $2.aux did not converge!" 46 | exit 10 47 | fi 48 | 49 | # If the newly produced .dvi disappears, we need 50 | # to redo. 51 | redo-ifchange "$tmp/$2.dvi" 52 | 53 | # With --recorder, latex produces a list of files 54 | # it used during its run. Let's depend on all of 55 | # them, so if they ever change, we'll redo. 56 | grep ^INPUT "$tmp/$2.fls" | 57 | cut -d' ' -f2 | 58 | xargs redo-ifchange 59 | -------------------------------------------------------------------------------- /docs/t/testitem.md: -------------------------------------------------------------------------------- 1 | % redo(1) Redo %VERSION% 2 | % Avery Pennarun 3 | % %DATE% 4 | 5 | # NAME 6 | 7 | redo-always - mark the current target as always needing to be rebuilt 8 | 9 | # SYNOPSIS 10 | 11 | redo-always 12 | 13 | 14 | # DESCRIPTION 15 | 16 | Normally redo-always is run from a .do file that has been 17 | executed by `redo`(1). See `redo`(1) for more details. 18 | 19 | This is a "quoted string." 20 | 21 | "entirely quoted" 22 | 23 | .starting with dot 24 | 25 | I'm a \big \\backslasher! 26 | 27 | This **line** has _multiple_ `formats`(interspersed) *with* each _other_ 28 | and *here is a multi 29 | line italic.* 30 | 31 | This line has an & and a < and a >. 32 | 33 | - "line starting with quoted" 34 | 35 | Here's some code 36 | with indentation 37 | yay! (a \backslash and ) 38 | "foo" 39 | 40 | skipped a line 41 | indented 42 | 43 | another skip 44 | 45 | - -starting with dash 46 | 47 | - .starting with dot 48 | 49 | chicken 50 | 51 | - list item 52 | with more text 53 | 54 | and even more 55 | 56 | - second list 57 | - third list 58 | 59 | wicken 60 | 61 | - list 1a 62 | - list 1b 63 | - list 2 64 | - list 3 65 | 66 | barf 67 | 68 | First line 69 | : definition list. 70 | with 71 | multiple 72 | lines! 73 | 74 | --item=*value* 75 | : a description. 76 | 77 | `-x` 78 | : more stuff. if you had a lot of text, this is what it 79 | would look like. It goes on and on and on. 80 | 81 | a line with *altogether* "too much" stuff on it to realistically *make* it in a definition list 82 | : and yet, here we are. 83 | 84 | 85 | # SEE ALSO 86 | 87 | `redo`(1), `redo-ifcreate`(1), `redo-ifchange`(1), `redo-stamp`(1) 88 | -------------------------------------------------------------------------------- /t/flush-cache.in: -------------------------------------------------------------------------------- 1 | import sys, os, sqlite3 2 | 3 | if "DO_BUILT" in os.environ: 4 | sys.exit(0) 5 | 6 | sys.stderr.write("Flushing redo cache...\n") 7 | 8 | db_file = os.path.join(os.environ["REDO_BASE"], ".redo/db.sqlite3") 9 | db = sqlite3.connect(db_file, timeout=5000) 10 | 11 | # This is very (overly) tricky. Every time we flush the cache, we run an 12 | # atomic transaction that subtracts 1 from all checked_runid and 13 | # changed_runid values across the entire system. Then when checking 14 | # dependencies, we can see if changed_runid for a given dependency is 15 | # greater than checked_runid for the target, and their *relative* values 16 | # will still be intact! So if a dependency had been built during the 17 | # current run, it will act as if a *previous* run built the dependency but 18 | # the current target was built even earlier. Meanwhile, checked_runid is 19 | # less than REDO_RUNID, so everything will still need to be rechecked. 20 | # 21 | # A second tricky point is that failed_runid is usually null (unless 22 | # building a given target really did fail last time). (null - 1) is still 23 | # null, so this transaction doesn't change failed_runid at all unless it 24 | # really did fail. 25 | # 26 | # Finally, an even more insane problem is that since we decrement these 27 | # values more than once per run, they end up decreasing fairly rapidly. 28 | # But 0 is special! Some code treats failed_runid==0 as if it were null, 29 | # so when we decrement all the way to zero, we get a spurious test failure. 30 | # To avoid this, we initialize the runid to a very large number at database 31 | # creation time. 32 | db.executescript("pragma synchronous = off;" 33 | "update Files set checked_runid=checked_runid-1, " 34 | " changed_runid=changed_runid-1, " 35 | " failed_runid=failed_runid-1;") 36 | db.commit() 37 | -------------------------------------------------------------------------------- /docs/redo-targets.md: -------------------------------------------------------------------------------- 1 | # NAME 2 | 3 | redo-targets - print the list of all known redo targets 4 | 5 | # SYNOPSIS 6 | 7 | redo-targets 8 | 9 | 10 | # DESCRIPTION 11 | 12 | redo-targets prints a list of all redo *target* files that 13 | still exist. 14 | 15 | Files that no longer exist might not be targets anymore; 16 | you'll have to redo them for them to end up back in this 17 | list. (For example, if you built a file and then removed 18 | the file and its .do file, you wouldn't want it to show up 19 | in this list.) 20 | 21 | If a .do script does not produce an output file (eg. 22 | all.do, clean.do), it also does not show up in this list. 23 | 24 | The output of redo-targets might be useful in a 25 | semi-automated `clean.do` target; you could delete all the 26 | known targets, thus forcing them to be rebuilt next time. 27 | 28 | Each filename is on a separate line. The filenames are not 29 | guaranteed to be in any particular order. 30 | 31 | All filenames are printed relative the current directory. 32 | The list is not filtered in any way; it contains *all* the 33 | target filenames from the entire project. Remember that 34 | the redo database may span more than just your project, so 35 | you might need to filter the list before using it. (A 36 | useful heuristic might be to remove any line starting with 37 | '../' since it often refers to a target you don't care 38 | about.) 39 | 40 | If you want a list of only out-of-date targets, use 41 | `redo-ood`(1). If you want a list of sources (dependencies 42 | that aren't targets), use `redo-sources`(1). 43 | 44 | 45 | # REDO 46 | 47 | Part of the `redo`(1) suite. 48 | 49 | # CREDITS 50 | 51 | The original concept for `redo` was created by D. J. 52 | Bernstein and documented on his web site 53 | (http://cr.yp.to/redo.html). This independent implementation 54 | was created by Avery Pennarun and you can find its source 55 | code at http://github.com/apenwarr/redo. 56 | 57 | 58 | # SEE ALSO 59 | 60 | `redo`(1), `redo-ood`(1), `redo-sources`(1) 61 | -------------------------------------------------------------------------------- /redo/sh.do: -------------------------------------------------------------------------------- 1 | exec >&2 2 | redo-ifchange ../t/shelltest.od 3 | 4 | rm -rf $1.new 5 | mkdir $1.new 6 | 7 | GOOD= 8 | WARN= 9 | 10 | # Note: list low-functionality, maximally POSIX-like shells before more 11 | # powerful ones. We want weaker shells to take precedence, as long as they 12 | # pass the tests, because weaker shells are more likely to point out when you 13 | # use some non-portable feature. 14 | for sh in dash /usr/xpg4/bin/sh ash posh \ 15 | lksh mksh ksh ksh88 ksh93 pdksh \ 16 | zsh bash busybox /bin/sh; do 17 | printf " %-22s" "$sh..." 18 | FOUND=`which $sh 2>/dev/null` || { echo "missing"; continue; } 19 | 20 | # It's important for the file to actually be named 'sh'. Some 21 | # shells (like bash and zsh) only go into POSIX-compatible mode if 22 | # they have that name. If they're not in POSIX-compatible mode, 23 | # they'll fail the test. 24 | rm -f $1.new/sh 25 | ln -s $FOUND $1.new/sh 26 | SH=$PWD/$1.new/sh 27 | 28 | set +e 29 | ( cd ../t && "$SH" shelltest.od ) >shelltest.tmp 2>&1 30 | RV=$? 31 | set -e 32 | 33 | msgs= 34 | crash= 35 | while read line; do 36 | #echo "line: '$line'" >&2 37 | stripw=${line#warning: } 38 | stripf=${line#failed: } 39 | strips=${line#skip: } 40 | crash=$line 41 | [ "$line" = "$stripw" ] || msgs="$msgs W$stripw" 42 | [ "$line" = "$stripf" ] || msgs="$msgs F$stripf" 43 | [ "$line" = "$strips" ] || msgs="$msgs s$strips" 44 | done 1: 9 | sys.stderr.write('%s: no arguments expected.\n' % sys.argv[0]) 10 | sys.exit(1) 11 | 12 | if os.isatty(0): 13 | sys.stderr.write('%s: you must provide the data to stamp on stdin\n' 14 | % sys.argv[0]) 15 | sys.exit(1) 16 | 17 | env.inherit() 18 | logs.setup( 19 | tty=sys.stderr, parent_logs=env.v.LOG, 20 | pretty=env.v.PRETTY, color=env.v.COLOR) 21 | 22 | # hashlib is only available in python 2.5 or higher, but the 'sha' 23 | # module produces a DeprecationWarning in python 2.6 or higher. We want 24 | # to support python 2.4 and above without any stupid warnings, so let's 25 | # try using hashlib first, and downgrade if it fails. 26 | try: 27 | import hashlib 28 | except ImportError: 29 | import sha 30 | sh = sha.sha() 31 | else: 32 | sh = hashlib.sha1() 33 | 34 | while 1: 35 | b = os.read(0, 4096) 36 | sh.update(b) 37 | if not b: 38 | break 39 | 40 | csum = sh.hexdigest() 41 | 42 | if not env.v.TARGET: 43 | sys.exit(0) 44 | 45 | me = os.path.join(env.v.STARTDIR, 46 | os.path.join(env.v.PWD, env.v.TARGET)) 47 | f = state.File(name=me) 48 | changed = (csum != f.csum) 49 | debug2('%s: old = %s\n' % (f.name, f.csum)) 50 | debug2('%s: sum = %s (%s)\n' % (f.name, csum, 51 | changed and 'changed' or 'unchanged')) 52 | f.is_generated = True 53 | f.is_override = False 54 | f.failed_runid = None 55 | if changed: 56 | f.set_changed() # update_stamp might skip this if mtime is identical 57 | f.csum = csum 58 | else: 59 | # unchanged 60 | f.set_checked() 61 | f.save() 62 | state.commit() 63 | 64 | 65 | if __name__ == '__main__': 66 | main() 67 | -------------------------------------------------------------------------------- /t/360-symlinks/all.do: -------------------------------------------------------------------------------- 1 | rm -f a a.ran a.final b b.ran *.[123] dir/*.[123] 2 | mkdir -p dir 3 | 4 | reads() { 5 | aold=$aval 6 | bold=$bval 7 | read aval >a.final 42 | ../flush-cache 43 | redo-ifchange b 44 | reads 45 | [ "$aold" != "$aval" ] || exit 14 46 | [ "$bold" != "$bval" ] || exit 114 47 | 48 | # We should also notice if a.final is removed. 49 | # Now a is a "dangling" symlink. 50 | rm -f a.final 51 | ../flush-cache 52 | redo-ifchange b 53 | reads 54 | [ "$aold" != "$aval" ] || exit 15 55 | [ "$bold" != "$bval" ] || exit 115 56 | 57 | # If the symlink becomes no-longer-dangling, that should be dirty too. 58 | echo "splash" >a.final 59 | ../flush-cache 60 | redo-ifchange b 61 | reads 62 | [ "$aold" != "$aval" ] || exit 16 63 | [ "$bold" != "$bval" ] || exit 116 64 | 65 | # We ought to know the difference between a, the symlink, and its target. 66 | # If a is replaced with a.final directly, that's a change. 67 | rm -f a 68 | mv a.final a 69 | ../flush-cache 70 | redo-ifchange b >/dev/null 2>&1 # hide "you changed it" message 71 | reads 72 | [ "$aold" = "$aval" ] || exit 17 # manual override prevented rebuild 73 | [ "$bold" != "$bval" ] || exit 117 74 | -------------------------------------------------------------------------------- /redo/paths.py: -------------------------------------------------------------------------------- 1 | """Code for manipulating file paths.""" 2 | import os 3 | from . import env 4 | from .logs import debug2 5 | 6 | 7 | def _default_do_files(filename): 8 | l = filename.split('.') 9 | for i in range(1, len(l)+1): 10 | basename = '.'.join(l[:i]) 11 | ext = '.'.join(l[i:]) 12 | if ext: 13 | ext = '.' + ext 14 | yield ("default%s.do" % ext), basename, ext 15 | 16 | 17 | def possible_do_files(t): 18 | """Yield a list of tuples describing the .do file needed to build t.""" 19 | dirname, filename = os.path.split(t) 20 | yield (os.path.join(env.v.BASE, dirname), "%s.do" % filename, 21 | '', filename, '') 22 | 23 | # It's important to try every possibility in a directory before resorting 24 | # to a parent directory. Think about nested projects: We don't want 25 | # ../../default.o.do to take precedence over ../default.do, because 26 | # the former one might just be an artifact of someone embedding my project 27 | # into theirs as a subdir. When they do, my rules should still be used 28 | # for building my project in *all* cases. 29 | t = os.path.normpath(os.path.join(env.v.BASE, t)) 30 | dirname, filename = os.path.split(t) 31 | dirbits = dirname.split('/') 32 | # since t is an absolute path, dirbits[0] is always '', so we don't 33 | # need to count all the way down to i=0. 34 | for i in range(len(dirbits), 0, -1): 35 | basedir = '/'.join(dirbits[:i]) or '/' 36 | subdir = '/'.join(dirbits[i:]) 37 | for dofile, basename, ext in _default_do_files(filename): 38 | yield (basedir, dofile, 39 | subdir, os.path.join(subdir, basename), ext) 40 | 41 | 42 | def find_do_file(f): 43 | for dodir, dofile, basedir, basename, ext in possible_do_files(f.name): 44 | dopath = os.path.join(dodir, dofile) 45 | debug2('%s: %s:%s ?\n' % (f.name, dodir, dofile)) 46 | if os.path.exists(dopath): 47 | f.add_dep('m', dopath) 48 | return dodir, dofile, basedir, basename, ext 49 | else: 50 | f.add_dep('c', dopath) 51 | return None, None, None, None, None 52 | -------------------------------------------------------------------------------- /docs/FAQInterop.md: -------------------------------------------------------------------------------- 1 | # Is redo compatible with autoconf? 2 | 3 | Yes. You don't have to do anything special, other than making sure you 4 | `redo-ifchange config.h` (where `config.h` is generated by autoconf) in 5 | whatever redo script you use to compile your object files. This 6 | is about the same as what you would have to do with make. 7 | 8 | 9 | # Is redo compatible with automake? 10 | 11 | Not exactly; there is no point in generating Makefiles if you aren't going 12 | to use make. However, we now include a similar project, 13 | [redoconf](/cookbook/redoconf-simple/), which provides a lot of the same 14 | features in a redo project that automake provides for a make project. 15 | 16 | 17 | # Is redo compatible with make? 18 | 19 | Yes. If you have an existing Makefile (for example, in one of your 20 | subprojects), you can just call make from a .do script to build that 21 | subproject. 22 | 23 | In a file called myproject.stamp.do: 24 | 25 | redo-ifchange $(find myproject -name '*.[ch]') 26 | make -C myproject all 27 | 28 | So, to amend our answer to the previous question, you *can* use 29 | automake-generated Makefiles as part of your hybrid redo/make-based project. 30 | 31 | 32 | # Is redo -j compatible with make -j? 33 | 34 | Yes! redo implements the same jobserver protocol as GNU make, which means 35 | that redo running under make -j, or make running under redo -j, will do the 36 | right thing. Thus, it's safe to mix-and-match redo and make in a recursive 37 | build system. 38 | 39 | Just make sure you declare your dependencies correctly; 40 | redo won't know all the specific dependencies included in 41 | your Makefile, and make won't know your redo dependencies, 42 | of course. 43 | 44 | One way of cheating is to just have your make.do script 45 | depend on *all* the source files of a subproject, like 46 | this: 47 | 48 | make -C subproject all 49 | find subproject -name '*.[ch]' | xargs redo-ifchange 50 | 51 | Now if any of the .c or .h files in subproject are changed, 52 | your make.do will run, which calls into the subproject to 53 | rebuild anything that might be needed. Worst case, if the 54 | dependencies are too generous, we end up calling 'make all' 55 | more often than necessary. But 'make all' probably runs 56 | pretty fast when there's nothing to do, so that's not so 57 | bad. 58 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os, setuptools, subprocess 2 | 3 | # Construct the redo input files, including redo.version, if we're 4 | # starting from the original redo source dir. If we're running 5 | # from the python pip package, the files already exist, so we 6 | # skip this step. 7 | mydir = os.path.dirname(__file__) 8 | script = os.path.join(mydir, 'do') 9 | verfile = os.path.join(mydir, 'redo/version/_version.py') 10 | if os.path.exists(script) and not os.path.exists(verfile): 11 | subprocess.check_call([script]) 12 | 13 | 14 | import redo.version 15 | 16 | 17 | def read(fname): 18 | return open(os.path.join(mydir, fname)).read() 19 | 20 | 21 | # FIXME: we probably need to build redo/sh on the target system, somehow. 22 | setuptools.setup( 23 | name = 'redo-tools', 24 | version = redo.version.TAG.replace('-', '+', 1), 25 | python_requires='>=2.7', 26 | author = 'Avery Pennarun', 27 | author_email = 'apenwarr@gmail.com', 28 | description = ('djb redo: a recursive, general purpose build system.'), 29 | long_description=read('README.md'), 30 | long_description_content_type='text/markdown', 31 | license = 'Apache', 32 | keywords = 'redo redo-ifchange make dependencies build system compiler', 33 | url = 'https://github.com/apenwarr/redo', 34 | packages = setuptools.find_packages(), 35 | classifiers = [ 36 | 'Development Status :: 4 - Beta', 37 | 'Environment :: Console', 38 | 'Topic :: Utilities', 39 | 'License :: OSI Approved :: Apache Software License', 40 | 'Operating System :: POSIX', 41 | 'Topic :: Software Development :: Build Tools', 42 | 'Topic :: Utilities', 43 | ], 44 | entry_points = { 45 | 'console_scripts': [ 46 | 'redo=redo.cmd_redo:main', 47 | 'redo-always=redo.cmd_always:main', 48 | 'redo-ifchange=redo.cmd_ifchange:main', 49 | 'redo-ifcreate=redo.cmd_ifcreate:main', 50 | 'redo-log=redo.cmd_log:main', 51 | 'redo-ood=redo.cmd_ood:main', 52 | 'redo-sources=redo.cmd_sources:main', 53 | 'redo-stamp=redo.cmd_stamp:main', 54 | 'redo-targets=redo.cmd_targets:main', 55 | 'redo-unlocked=redo.cmd_unlocked:main', 56 | 'redo-whichdo=redo.cmd_whichdo:main', 57 | ], 58 | }, 59 | ) 60 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: "redo: a recursive build system" 2 | theme: 3 | name: readthedocs 4 | hljs_languages: 5 | - python 6 | - r 7 | - shell 8 | - tex 9 | docs_dir: docs 10 | site_dir: docs.out 11 | strict: true 12 | repo_url: https://github.com/apenwarr/redo 13 | edit_uri: edit/master/docs 14 | extra_javascript: 15 | - fetchcode.js 16 | extra_css: 17 | - extra_style.css 18 | plugins: 19 | - exclude: 20 | glob: 21 | - cookbook/container/simple/* 22 | - cookbook/container/debdownload/* 23 | - cookbook/container/debootstrap/* 24 | - cookbook/container/debian/* 25 | - cookbook/container/libs/* 26 | - cookbook/container/*.fakeroot 27 | - cookbook/container/*.image 28 | - cookbook/container/*.initrd 29 | - cookbook/container/*.layer 30 | - cookbook/container/*.list 31 | - cookbook/*/out/* 32 | - cookbook/*/out.* 33 | - "t/*" 34 | - "*.eps" 35 | - "*.gz" 36 | - "*.log" 37 | - "*.pdf" 38 | - "*.ps" 39 | - "*.tar" 40 | - "*.tmp" 41 | - "*.1" 42 | regex: 43 | - ".*~" 44 | 45 | nav: 46 | - Introduction: index.md 47 | - Getting Started: GettingStarted.md 48 | - Contributing.md 49 | - Roadmap.md 50 | - Cookbook: 51 | - Hello World (hello.do, redo-ifchange): cookbook/hello/index.md 52 | - Text substitution (default.do, redo-always, redo-stamp): cookbook/defaults/index.md 53 | - R plots and LaTeX to pdf (side effects, multiple outputs): cookbook/latex/index.md 54 | - Docker and kvm containers (from scratch): cookbook/container/index.md 55 | - Portable C++ programs (using redoconf): cookbook/redoconf-simple/index.md 56 | - FAQ: 57 | - Basics: FAQBasics.md 58 | - Semantics: FAQSemantics.md 59 | - Interop with make: FAQInterop.md 60 | - Parallel Builds: FAQParallel.md 61 | - Implementation Details: FAQImpl.md 62 | - Reference Manual: 63 | - redo(1): redo.md 64 | - redo-ifchange(1): redo-ifchange.md 65 | - redo-ifcreate(1): redo-ifcreate.md 66 | - redo-always(1): redo-always.md 67 | - redo-stamp(1): redo-stamp.md 68 | - redo-sources(1): redo-sources.md 69 | - redo-targets(1): redo-targets.md 70 | - redo-ood(1): redo-ood.md 71 | - redo-whichdo(1): redo-whichdo.md 72 | - redo-log(1): redo-log.md 73 | --------------------------------------------------------------------------------