Skip to content

Instantly share code, notes, and snippets.

@mde
Forked from johnmdonahue/gist:2671849
Created May 13, 2012 19:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mde/2689923 to your computer and use it in GitHub Desktop.
Save mde/2689923 to your computer and use it in GitHub Desktop.
How to handle pre-req flow using Jake.exec
var spawn = require('child_process').spawn;
desc('Do thing 1');
task('thing1', [], function () {
var cmds = ['node -e "console.log(\'--> Thing 1... Executing\')"'];
console.log('--> Thing 1... Starting');
jake.exec(cmds, function () {
var echo = spawn('echo',
["--> Thing 1... I'm doing a spawned process in thing 1"])
, data = '';
echo.stdout.on('data', function (d) {
data += d;
});
echo.stdout.on('end', function () {
console.log(data);
});
echo.on('exit', function () {
console.log('--> Thing 1... Done');
complete();
});
}, {stdout: true});
}, {async: true});
desc('Do thing 2');
task('thing2', [], function () {
console.log('--> Thing 2... Starting');
var cmds = ['node -e "console.log(\'--> Thing 2... Executing\')"'];
jake.exec(cmds, function () {
console.log('--> Thing 2... Done');
complete();
}, {stdout: true});
}, {async: true});
desc('Do thing 3');
task('thing3', [], function () {
console.log('--> Thing 3... Starting');
var cmds = ['node -e "console.log(\'--> Thing 3... Executing\')"'];
jake.exec(cmds, function () {
console.log('--> Thing 3... Done');
complete();
}, {stdout: true});
}, {async: true});
desc('Do all the things');
task('default', ['thing1', 'thing2'], function () {
console.log('* Default... Starting');
var cmds = ['node -e "console.log(\'* Default... Executing\')"' ];
jake.exec(cmds, function () {
var thing = jake.Task.thing3;
thing.addListener('complete', function () {
console.log('* Default... Done');
complete();
});
thing.invoke();
}, {stdout: true});
}, {async: true});
/*
jake
--> Thing 1... Starting
--> Thing 1... Executing
--> Thing 1... I'm doing a spawned process in thing 1
--> Thing 1... Done
--> Thing 2... Starting
--> Thing 2... Executing
--> Thing 2... Done
* Default... Starting
* Default... Executing
--> Thing 3... Starting
--> Thing 3... Executing
--> Thing 3... Done
* Default... Done
*/
@mde
Copy link
Author

mde commented May 13, 2012

There are a couple of things going on here.

  1. The whole point of having jake.exec is so you can do async shell-operations and still enforce order of operations. There's no reason I can think of to do a child-process spawn on your own (jake.exec streams output as well).
  2. Shelling out is asynchronous, so tasks that shell out all have to be async:true.
  3. You could use your own spawn if you made the task async, and then hooked the complete call to the "exit" event on the process.
  4. You can also run tasks as if they were prereqs by calling them via invoke/execute inside the main task. But if the prereq task shells out, you have to hook to its "complete" event for the rest of your execution.

@johnmdonahue
Copy link

Thanks for the reply @mde! A few comments/questions on your points:

  1. The use of spawn here was just to illustrate that this method will execute synchronously. Before converting things over to use Jake.exec, I was using vanilla spawn/exec and this worked fine. But after converting I now have a flow control issue. Do you think it would make more sense for me to go back to standard node spawn/exec? It seems like it may be the more straight-forward way to enforce flow in this case.
  2. I guess I was wondering if there is a way to make Jake.exec or something like it synchronous without resorting to 3 or 4. Is this something that is being considered for a future release? I am loving Jake.exec but I can't see a clean way to implement it for procedure-sensitive build tasks (e.g. ['Check for required packages', 'Update submodules', 'Build temp core and lint', 'Build', 'Minify']) where each task is is ideally standalone both for the sake of individual execution and reusability.

Thanks again for the feedback!

@johnmdonahue
Copy link

@mde Hahaha! Whoops! I just read your comments not realizing until just now you had edited the source. I'll play around with that. Thanks. ;)

@mde
Copy link
Author

mde commented May 13, 2012

Yes, I should have been clearer that the code above is a working version of what you seemed to be wanting here, including how to use spawn (even though you shouldn't really need it) and how to use invoke.

Yes, the entire reason for having an "async:true" flag for tasks is so you can break things down into smaller units of code for reusability, and still ensure prereqs execute sequentially. You should always flag a task that does asynchronous work as async and use complete, even if it's initially a standalone task.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment