gruntjs/grunt

using multi-value command-line options

Closed this issue · 11 comments

Grunt uses nopt for handling command-line options. nopt allows you to pass a set of values assigned to a single option, like so:

$ node my-program.js --many 1 --many null --many foo
resulting in
{ many: ["1", "null", "foo"] }

But when using grunt.option("many") only the last value is returned:
{ many: "foo" }

Is there a way to use an array as an options value without adding my own in cli.js?

using grunt 0.4.0a

Which option are you trying to pass multiple values to? nopt won't process multiple options like that unless they are explicitly specified as arrays in knownOpts. Depending on what you're trying to do, this might be an issue for nopt itself, as unknown options are considered boolean by default.

You're right nopt does behave that way. I'm moving the AngularJS project from rake to grunt. The option I'm passing is for a grunt plugin I'm writing for testacular, to override which browsers it runs the tests in.

$ grunt test --in Chrome --in Firefox

I've made it work with this:

$ grunt test --in=[Chrome,Firefox] and manually parsing the args, but that's not ideal.

The other solution is modifying cli.js to add a custom Array type, not ideal either.

Maybe grunt could have a way of registering new arg types? Something like

grunt.addOption('in', {short: 'i', info: 'browsers to test in', type: Array});

That would give grunt plugins a predictable way to handle custom options intended for them. What do you think?

Actually that probably wouldn't work since cli.js has already run and args already parsed by that point. But it could be configured in the Gruntfile.

Hmm. This seems like something that could/should be configurable in nopt (how it handles unknown options). Would you mind trying your hand over there before we add more APIs to grunt?

You bet.
npm/nopt#17

I like this idea and I've added it to the list of things we're going to tackle in .5. It'll be a bit, but we won't forget, I promise :). Closing this for now.

Here is how I solved such an issue:
julkue/wabp@0ff15c7#diff-35b4a816e0441e6a375cd925af50752cR139
You can pass a list of files to exclude in a task, e.g. --exclude="index.html, assets/**". The one-liner will convert it to an array like ['!index.html', '!assets/**'].

@tkellen I'm wondering if a solution for this issue ever made it into grunt ? Have done some digging around (haven't looked through source yet) but haven't found anything.

I have the same usecase as the OP : $ node my-program.js --many 1 --many null --many foo results in grunt.option('many') = foo.

I can adopt the workaround suggested by @julmot but wanted to see if there is a built in solution first ?

Thanks!

shama commented

@kylezeeuwen Which version of Grunt are you using? 1.0.1 should allow you to do the following now:

$ grunt --many=1 --many=null --many=foo
Running "default" task
[ '1', null, 'foo' ]

Hi @shama I am using grunt 0.4.5. I upgraded to 1.0.1 and can confirm the behaviour you specify above. It appears all my grunt tasks still work which is pretty sweet.

I did notice that I can no longer specify grunt task --option foo as the = is now necessary, e.g., grunt task --option=foo but I imagine this is a known breaking update and deliberate in order to support multi value args with nopts.

Thanks or the quick response I'm satisfied with my service today ;)

💃