3

I am either blanking out or it is more complex that it should have been.

I am trying to run grunt-init from a Grunt task, something like this:

grunt.registerTask('init', 'Scaffold various artifacts', function(param) {
  // analyze `param` and pass execution to `grunt-init`
  // run `grunt-init path/to/some/template/based/on/param/value`
});

The part of analysis of the param is, of course, not the issue. It's running the grunt-init that is.

Running grunt-init directly in the same folder as the below attempts works fine.

I've tried the following methods (path to template is inlined for shortness of the code), all to no avail:

grunt-shell

shell: {
    init: {
        options: { 
            stdout: true,
            callback: function(err, stdout, stderr, cb) {
                ...
            }
        },
        command: 'grunt-init path/to/some/template/based/on/param/value'
    }
}

and then:

grunt.registerTask('init', 'Scaffold various artifacts', function(param) {
    grunt.task.run(['shell:init']);
});

and in command line:

grunt init

or from command line directly:

grunt shell:init

grunt-exec

exec: {
    init: {
        cmd: 'grunt-init path/to/some/template/based/on/param/value',
        callback: function() {
            ...
        }
    }
}

and then:

grunt.registerTask('init', 'Scaffold various artifacts', function(param) {
    grunt.task.run(['exec:init']);
});

and in command line:

grunt init

or from command line directly:

grunt exec:init

Node's exec

grunt.registerTask('init', 'Scaffold various artifacts', function(param) {
    var exec = require('child_process').exec;
    exec('grunt-init path/to/some/template/based/on/param/value', function(err, stdout, stderr) {
        ...
    });
});

and in command line:

grunt init

Nothing.

There were various attempts, best of which would print the first line of grunt-init prompt:

Running "init" task

And that's it.

What am I missing? Should I have connected the stdout somehow?

ZenMaster
  • 12,363
  • 5
  • 36
  • 59

2 Answers2

3

Create a child process with grunt.util.spawn. You can make it asynchronous and set stdio to 'inherit' so that any template prompts can be answered. Also, you should set a cwd or else it will try to overwrite your existing Gruntfile.js!

grunt.registerTask('init', 'Scaffold various artifacts', function(grunt_init_template) {

    var done = this.async();

    grunt.util.spawn({
        cmd: 'grunt-init',
        args: [grunt_init_template],
        opts: {
            stdio: 'inherit',
            cwd: 'new_project_dir',
        }
    }, function (err, result, code) {
        done();
    });
});
mattwad
  • 1,743
  • 17
  • 13
0

I think I found a way, but it feels hack-ish to me. I am going to answer this, but, please give yours too.

It can be done using grunt-parallel

grunt-parallel

where task is defined using:

parallel: {
    init: {
        options: {
            stream: true
        },
        tasks: [
            {cmd: 'grunt-init'}
        ]
    }            
}

and init task is:

grunt.registerTask('init', 'Scaffold various artifacts', function(param) {
    // calculate path based on `param`
    ...
    grunt.config.set('parallel.init.tasks.0.args', ['path/to/some/template/based/on/param/value']);
    grunt.task.run(['parallel:init']);
});

then, running the following in command line:

grunt init:<some param indicating template type or similar>

properly runs grunt-init.

ZenMaster
  • 12,363
  • 5
  • 36
  • 59