jakejs / jake

JavaScript build tool, similar to Make or Rake. Built to work with Node.js.
http://jakejs.com
Apache License 2.0
1.97k stars 190 forks source link

File rule without a target #259

Open aidanhs opened 10 years ago

aidanhs commented 10 years ago

Sometimes I want to be able to run some operation on a file but not have any output, e.g. allowing me to only hint js files changed since the last run.

I can currently do this with something like

var jshint = 'node_modules/jshint/bin/jshint -c .jshintrc';
function rep(name) {
  name.replace(/\.hint\.js$/, '.js');
}
rule(/tmp.*\.hint\.js$/, rep, { async: true }, function () {
  var ee = jake.createExec(jshint + ' ' + this.source, { interactive: true });
  ee.addListener('cmdEnd', (function () {
    jake.mkdirP(path.dirname(this.name));
    jake.cpR(this.source, this.name, { silent: true });
    console.log('end');
    complete();
  }).bind(this));
  ee.addListener('error', function () {
    console.log('err');
  });
  ee.run();
});

(untested, but gives the idea)

Needless to say, I'd prefer something a little less crazy. Some observations:

Coming back to the issue title, I'd like to get rid of my tmp directory handling and give rules with no target, e.g.

var srcfiles = glob('**/*.js');
rule(null, srcfiles, function () {
  // hinting
})

'null' rules would always be run so I'd envisage their main value as being inside tasks (i.e. a 'hint' task with the code above inside it). I don't know how rules currently behave when called from inside tasks, so possibly this is easier said than done.

aidanhs commented 10 years ago

I've deleted a previous comment about silent: true, it was unrelated.

mde commented 10 years ago

Wow, there's a lot going on here. :) First, to answer your question about output from the Exec object, having a look at how jake.exec is implemented will give you some idea of why output works the way it does: https://github.com/jakejs/jake/blob/master/lib/utils/index.js#L114 It's really just a thin wrapper around Exec -- just listened for the 'stdout' events and logs them out. jake.exec is really just a super-minimal way to run a bunch of shell commands and bail out if something goes wrong.

For what you're trying to do, it might make more sense to take advantage of the default FileTask behavior -- it will only run when one if its prereq files has changed. There's nothing passed in to indicate which one changed (it bails as soon as it finds a change in any item, which is generally what you want), but you can still iterate the original list and compare the "modTime" props to see which ones to lint.

I did it with a Jakefile like this:

var list = new jake.FileList(['**/*.js']);

file('monitor.txt', list.toArray(), function () {
  var self = this;
  console.log('Something changed');
  list.forEach(function (key) {
    var ft = jake.Task[key];
    if (ft.modTime > self.modTime) {
      console.log(ft.name);
    }
  });
  // Update the mod-time on the monitoring file
  fs.writeFileSync('monitor.txt', '');
});

task('default', ['monitor.txt']);