Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to use sub command with option? #521

Closed
kylelix7 opened this issue Apr 6, 2016 · 19 comments
Closed

how to use sub command with option? #521

kylelix7 opened this issue Apr 6, 2016 · 19 comments

Comments

@kylelix7
Copy link

kylelix7 commented Apr 6, 2016

Hi I am trying sub command with option. Is there an example? I tried below code. How can I get the option value from the action callback?

 program
  .command('upload')
  .description('upload a file')
  .option('-f, --file <file>', 'file name')
  .action(function(file) {
    console.log("uploading...");
    console.log(file);
  });

 program.parse(process.argv);

$ node index.js upload -f filename
uploading...
Command {
commands: [],
options:
[ Option {
flags: '-f, --file ',
required: -12,
optional: 0,
bool: true,
short: '-f',
long: '--file',

@drewbrokke
Copy link

Hi @kylelix7, the last argument passed to the callback is actually an options object so you should be able to get the file name value with options.file.

program
  .command('upload')
  .description('upload a file')
  .option('-f, --file <file>', 'file name')
  .action(function(options) {
    console.log("uploading...");
    console.log(options.file);
  });

program.parse(process.argv);

If you have arguments available to the command (as in program.command('upload' [fileName])), they will be expected arguments in the callback function. See https://www.npmjs.com/package/commander#examples. Hope this helps!

@ninjasort
Copy link

What if you're using git-style commands in different files? The options don't seem to come through when chaining the .action cb

@gentunian
Copy link

If you want git-style sub commands this is something I would do:

/var/foo/bar/main:

#!/usr/bin/env node
'use strict';
const program = require('commander');

program
    .version('0.0.1')
    .command('create', 'command description')
    .parse(process.argv);

/var/foo/bar/main-create:

#!/usr/bin/env node
'use strict';
const program = require('commander');

program
    .version('0.0.1')
    .command('cluster','command description')
    .parse(process.argv);

/var/foo/bar/main-create-cluster

#!/usr/bin/env node
'use strict';
const program = require('commander');
program
    .version('0.0.1')
    .option('-n, --name <name>', 'Sets the cluster name')
    .option('-i, --ip <ip>', 'Sets the cluster ip')
    .parse(process.argv);

but note that commander won't show you help usage for options.

@dgem
Copy link

dgem commented Feb 6, 2017

Have a related question about subcommands... what if want to use common options across subcommands. Based on the above it seems I have to define them in all my subcommands. Am I missing something?

For example, I want to have a -l --loglevel [debug|info|warn|error] option for all my commands & subcommands. It seems I need to set a program.option in each top level command and all subcommands.

I guess I could have a function that takes program as a param, or is there a better way?

You can see my current attempts in https://github/dgem/kat-nip

@frankcchen
Copy link

frankcchen commented Oct 19, 2018

@gentunian Hey what if at the first level, I want to list the available sub-commands of 'create'? For example right now if I do
$cli-name create
by itself it will raise error since I don't give any sub-command.

@gentunian
Copy link

gentunian commented Oct 19, 2018

@frankcchen I cannot reproduce that:

~/code/nodejs/borrar/main.js:

#!/usr/bin/env node
'use strict';
const program = require('commander');

program
    .version('0.0.1')
    .command('create', 'command description')
    .parse(process.argv);

~/code/nodejs/borrar/main-create.js:

```javascript
#!/usr/bin/env node
'use strict';
const program = require('commander');

program
    .version('0.0.1')
    .command('cluster','command description')
    .parse(process.argv);

Test:

[seba@leyla:~/code/nodejs/borrar] 2s $ node main.js 
Usage: main [options] [command]

Options:
  -V, --version  output the version number
  -h, --help     output usage information

Commands:
  create         command description
  help [cmd]     display help for [cmd]
[seba@leyla:~/code/nodejs/borrar] $ node main.js create
Usage: main-create [options] [command]

Options:
  -V, --version  output the version number
  -h, --help     output usage information

Commands:
  cluster        command description
  help [cmd]     display help for [cmd]
[seba@leyla:~/code/nodejs/borrar] $ node main-create.js 
Usage: main-create [options] [command]

Options:
  -V, --version  output the version number
  -h, --help     output usage information

Commands:
  cluster        command description
  help [cmd]     display help for [cmd]

@frankcchen
Copy link

frankcchen commented Oct 22, 2018

@gentunian You're right.
What if I want to handle unsupported command at the top level aka main.js? Assume your program only has command 'create'. now if I do
$ node main.js bogus
It will have no output.

I have tried adding
.on('command:* , () => {...});
But it didn't really work. The added line intercepts all commands basically.

@gentunian
Copy link

gentunian commented Oct 22, 2018

@frankcchen I think you could try and play with the result of parsing the options/commands.

Play with this:

/var/foo/main.js:

#!/usr/bin/env node
'use strict';
const program = require('commander');

const r = program
    .version('0.0.1')
    .command('create', 'command description')
    .parse(process.argv);

if (r) {
   console.log('I think no matches were found');
}

I've edited the code. I think you could do a workaround just like that. Each sub-command may also follow the same workaround.

For reference what parse() function returns check the source code

@davidkjackson54
Copy link

davidkjackson54 commented Dec 26, 2018

I understand the process of how Commander handles subcommands and how each level is a js file in its own right - although i think this is a very cludgy approach.
I will have around 15 first level commands and maybe as many 10 second level commands for each of the first level command followed by optional parameters - so that is going to lead to a huge number of sub files all in the same top level folder - just to manage the process.
for example:
job list -prefix
job status -jname
job purge -jname
job submit -batchfile

in this example job is a top level command category and the second command (list etc) is the action to take within that category. I would like to isolate all the subcommand files relating to jobs into a jobs folder. That way I would at least be able to manage the 15 or so sub folders for my top level commands.

Rather than be fixed at using level 1 file followed by level 2 file having to be in the same folder is
there any means of being able to specify the structure as to where these files can be found?
I am at the point of wondering if Commander is actually the best tool for me to use for the type of Command Line Interface that I want to put in place?

What I would like to do seems reasonable but I have found no tool that will help accomplish what I want to do whilst also providing built in help.

@evalcodenet
Copy link

evalcodenet commented Jan 14, 2019

Following seems to work for me - though I'd also appreciate a proper solution. Grouping of commands and options would be nice too. And some option names conflict with the implementation of commander, e.g. 'name' or 'domain'.

commander
    .version('0.1.0')
    .description('CLI');

commander
    .command('deployment <command>')
    .description('Manage deployment')
    .option('')
    .option('create', 'Create deployment')
    .option('--cloud <provider>', 'Cloud provider', 'aws')
    .option('--region <region>', 'Region', 'eu-central-1')
    .option('--prefix <prefix>', 'Resource prefix', 'tld-domain')
    .option('')
    .option('update', 'Update deployment')
    .option('--prefix <prefix>', 'Resource prefix', 'tld-domain')
    .action((command, options) => {
        console.log(command, options);
    });

Can be invoked either way (though the help will produce Usage: deployment [options] <command>):

cli deployment create --prefix=my-domain
cli deployment --prefix=my-domain create

Generated Help - 1st Level

# cli --help
Usage: cli [options] [command]

CLI

Options:
  -V, --version                   output the version number
  -h, --help                      output usage information

Commands:
  deployment [options] <command>  Manage deployment

Generated Help - 2nd Level

# cli deployment --help
Usage: deployment [options] <command>

Manage deployment

Options:
                      
  create              Create deployment
  --cloud <provider>  Cloud provider (default: "aws")
  --region <region>   Region (default: "eu-central-1")
  --prefix <prefix>   Resource prefix (default: "tld-domain")
                      
  update              Update deployment
  --prefix <prefix>   Resource prefix (default: "tld-domain")

@shadowspawn
Copy link
Collaborator

There was an answer posted to the original post, which was options for a subcommand with an action handler.

There was an example posted for option getting passed down into sub-sub-command.

#563 is an open issue about program level options being available to executable subcommands.

Closing this issue as not covering something that will be actioned. Feel free to open a new issue if it comes up again, with new information and renewed interest.

Thank you for your contributions.

@NaveenDA
Copy link

Is there any way to show full help for subcommands commands like npm -l?

@shadowspawn
Copy link
Collaborator

shadowspawn commented Dec 12, 2019

@NaveenDA No, see #1078 and #905 for somewhat related issues. Nice example, thanks.

@kuncevic
Copy link

kuncevic commented Oct 15, 2021

@shadowspawn that would be really great to be able to add subcommands details to main help, so pips able to see more detailed picture about each command without a need to run help for details. What do you think?

@shadowspawn
Copy link
Collaborator

@kuncevic Commander does already list the subcommands in the program help. This is actually a bit like what npm -l does, which does not show the full subcommand help either.

Currently the info displayed for each subcommand is the command description, and you can put extra info in there. The same description is displayed in the subcommand help. (For interest, there is an issue about the opposite problem, that the detailed description was too much to list in the program help! #1291)

@nguyenthang338
Copy link

nguyenthang338 commented Oct 15, 2021

@kylelix7

i work for me used options in subcommand don't need opts() fuctions.
program
.command('upload')
.description('upload a file')
.option('-f, --file ', 'file name')
.action(function(options) {
myfunction(options.file) ;

});

program.parse(process.argv);

@kuncevic
Copy link

kuncevic commented Oct 15, 2021

@shadowspawn is there anyway to list the options details as well within main help output?

@shadowspawn
Copy link
Collaborator

@kuncevic Open a new issue with some more detail. This issue was closed a couple of years ago, and is not the place for all subcommand questions. 😄

@kuncevic
Copy link

done #1624

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests