From f641e52e3ba76c190bc19f1cc2373420c3c030af Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Sat, 1 Jan 2011 22:00:14 -0800 Subject: [PATCH] Handle .do files that start with "#!/" to specify an explicit interpreter. Now you can have your .do files interpreted by whatever interpreter you want. --- README.md | 29 +++++++++++++++++++++-------- builder.py | 3 +++ minimal/do | 8 +++++++- t/.gitignore | 1 + t/clean.do | 2 +- t/nonshelltest.do | 3 +++ t/test.do | 3 ++- 7 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 t/nonshelltest.do diff --git a/README.md b/README.md index ce655c0..4c26d50 100644 --- a/README.md +++ b/README.md @@ -437,15 +437,28 @@ changed, you can run `redo-ifchange target` instead. # Can my .do files be written in a language other than sh? -FIXME: Not presently. In theory, we could support starting your .do files -with the magic "#!/" sequence (eg. #!/usr/bin/python) and then using that -shell to run your .do script. But that opens new problems, like figuring -out what is the equivalent of the `redo-ifchange` command in python. Do you -just run it in a subprocess? That might be unnecessarily slow. And so on. +Yes. If the first line of your .do file starts with the +magic "#!/" sequence (eg. `#!/usr/bin/python`), then redo +will execute your script using that particular interpreter. -Right now, `redo` explicitly runs `sh filename.do`. The main reasons for -this are to make the #!/ line optional, and so you don't have to remember to -`chmod +x` your .do files. +Note that this is slightly different from normal Unix +execution semantics: redo never execs your script directly; +it only looks for the "#!/" line. The main reason for this +is so that your .do scripts don't have to be marked +executable (chmod +x). Executable .do scripts would +suggest to users that they should run them directly, and +they shouldn't; .do scripts should always be executed +inside an instance of redo, so that dependencies can be +tracked correctly. + +WARNING: If your .do script *is* written in Unix sh, we +recommend *not* including the `#!/bin/sh` line. That's +because there are many variations of /bin/sh, and not all +of them are POSIX compliant. redo tries pretty hard to +find a good default shell that will be "as POSIXy as +possible," and if you override it using #!/bin/sh, you lose +this benefit and you'll have to worry more about +portability. # Can a single .do script generate multiple outputs? diff --git a/builder.py b/builder.py index 81a6c5c..5527693 100644 --- a/builder.py +++ b/builder.py @@ -128,6 +128,9 @@ class BuildJob: if vars.VERBOSE: argv[1] += 'v' if vars.XTRACE: argv[1] += 'x' if vars.VERBOSE or vars.XTRACE: log_('\n') + firstline = open(dofile).readline().strip() + if firstline.startswith('#!/'): + argv[0:2] = firstline[2:].split(' ') log('%s\n' % _nice(t)) self.argv = argv sf.is_generated = True diff --git a/minimal/do b/minimal/do index 198e8fe..30d740c 100755 --- a/minimal/do +++ b/minimal/do @@ -57,7 +57,13 @@ _run_dofile() export DO_DEPTH="$DO_DEPTH " export REDO_TARGET=$PWD/$TARGET set -e - . "$PWD/$DOFILE" >"$TARGET.tmp2" + read line1 <"$PWD/$DOFILE" + cmd=${line1#"#!/"} + if [ "$cmd" != "$line1" ]; then + /$cmd "$PWD/$DOFILE" "$@" >"$TARGET.tmp2" + else + . "$PWD/$DOFILE" >"$TARGET.tmp2" + fi } diff --git a/t/.gitignore b/t/.gitignore index 375c938..1ff112f 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -23,3 +23,4 @@ test2.args /ifcreate[12] /broken /shellfile +/nonshelltest diff --git a/t/clean.do b/t/clean.do index 1b3b8b4..d845e1d 100644 --- a/t/clean.do +++ b/t/clean.do @@ -1,6 +1,6 @@ redo example/clean curse/clean deps/clean "space dir/clean" stamp/clean \ defaults-flat/clean -rm -f broken shellfile mode1 makedir.log chdir1 deltest2 \ +rm -f broken nonshelltest shellfile mode1 makedir.log chdir1 deltest2 \ hello [by]ellow *.o *~ .*~ *.log CC LD passfail silence silence.do \ touch1 touch1.do always1 ifcreate[12].dep ifcreate[12] rm -rf makedir diff --git a/t/nonshelltest.do b/t/nonshelltest.do new file mode 100644 index 0000000..fc8a02d --- /dev/null +++ b/t/nonshelltest.do @@ -0,0 +1,3 @@ +#!/usr/bin/env perl +$a="perly"; +print "hello $a world\n"; diff --git a/t/test.do b/t/test.do index 187fa64..65538e3 100644 --- a/t/test.do +++ b/t/test.do @@ -1,5 +1,6 @@ redo-ifchange all ./hello >&2 -redo shelltest deltest deltest2 test.args test2.args passfailtest chdirtest \ +redo nonshelltest shelltest \ + deltest deltest2 test.args test2.args passfailtest chdirtest \ curse/test deps/test "space dir/test" modetest makedir2 \ silencetest touchtest stamp/test alwaystest ifcreate-test