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

actively calling showHelp shows different output then help on fail does #1926

Closed
foxriver76 opened this issue Apr 26, 2021 · 2 comments
Closed
Labels

Comments

@foxriver76
Copy link

In our code we use commands and "subcommands", calling our tool via iobroker object will result in our code processing the command and then calling yargs.showHelp(), the generated output looks like:

iob object
Unknown command "object undefined"!
iobroker object

Object management

Commands:
  iobroker get <id>                                     Get object specified by id
...
...
...

I would expect, that it shows iobroker object get <id> and not iobroker get <id> as it is done when I call iobroker object --help:

moritz@moritz-ThinkPad-E470:~/workspaces/ioBroker.js-controller$ iob object --help
iobroker object

Object management

Commands:
  iobroker object get <id>                                     Get object specified by id
...
...
...

Why is there a difference, is this intended? If yes, how can I achieve the desired output via showHelp()?

You can find the relevant code here: https://github.com/ioBroker/ioBroker.js-controller/blob/12a235299be58d7bb4592d71d61478afe9f1797b/lib/setup.js#L34-L370

Reopen of #1853

@bcoe bcoe added the bug label May 2, 2021
@bcoe
Copy link
Member

bcoe commented May 2, 2021

@foxriver76 could you please try the next release of yargs@17 (17.0.0-candidate.13), I can reproduce your bug on yargs@16, but not the latest release of v17:

bencoe-macbookpro3:test-install bencoe$ node example.js object
appname object

Object management

Commands:
  appname object get <id>                                     Get object specified by id
  appname object set <id> <json-value>                        Set object with the given id by providing a new json object
  appname object set <id> propertyname=<value or json-value>  Update part of the object by providing a new value or partial object
  appname object extend <id> <json-value>                     Extend object with the given id by providing a new json object
  appname object del <id|pattern>                             Delete object with given id or all objects matching the pattern
  appname object chmod <object-mode> [state-mode] <id>        Change object rights
  appname object chown <user> <group> <id>                    Change object ownership
  appname object list <pattern>                               List object matching given pattern

with code:

const yargs = require('./')
  .scriptName('appname')
  .locale('en')// otherwise it could be mixed, because our implementations are in english
  .version(false) // disable yargs own version handling, because we have our own depending on passed instances
  .completion('_createCompletion', false) // can be created via iob _createCompletion >> ~/.bashrc or ~/.bash_profile for OSX
  .command('setup', 'Setup ioBroker', {
      redis: {
          describe: 'Setup as redis',
          type: 'boolean'
      },
      objects: {
          describe: 'Objects <host>',
          default: '127.0.0.1',
          type: 'number'
      },
      states: {
          describe: 'States <host>',
          default: '127.0.0.1',
          type: 'number'
      },
      'port <port>': {
          describe: 'Port of redis',
          default: 6379,
          type: 'number'
      },
      custom: {
          describe: 'Custom setup',
          type: 'boolean'
      },
      first: {
          describe: 'Initial setup',
          type: 'boolean'
      }
  })
  .command('start', 'Starts the js-controller', yargs => {
      yargs
          .command('all', 'Starts js-controller and all adapters')
          .command('<adapter>[.<instance>]', 'Starts a specified adapter instance');
  })
  .command('stop', 'stops the js-controller', yargs => {
      yargs
          .command('<adapter>[.<instance>]', 'Stops a specified adapter instance');
  })
  .command('restart', 'Restarts js-controller', yargs => {
      yargs
          .command('<adapter>[.<instance>]', 'Restarts a specified adapter instance', {});
  })
  .command('debug <adapter>[.<instance>]', 'Starts a Node.js debugging session for the adapter instance', {
      ip: {
          describe: 'IP-address <ip>',
          type: 'string'
      },
      port: {
          describe: 'Port <port>',
          type: 'number'
      },
      wait: {
          describe: 'Wait',
          type: 'boolean'
      }
  })
  .command('info', 'Shows the host info', {})
  .command('logs [<adapter>]', 'Monitor log', {
      'lines=1000': { // TODO: it's the only place we use = we should avoid this
          describe: 'Number of lines',
          type: 'string'
      },
      watch: {
          describe: 'Watch',
          type: 'boolean'
      }
  })
  .command('add <adapter> [desiredNumber]', 'Add instance of adapter', {
      enabled: {
          describe: 'Enable adapter',
          type: 'boolean'
      },
      host: {
          describe: 'Host <host>',
          type: 'string'
      },
      port: {
          describe: 'Port <port>',
          type: 'number'
      }
  })
  .command('install <adapter>', 'Installs a specified adapter', {})
  .command('rebuild <adapter>|self', 'Rebuilds a specified adapter', {
      install: {
          describe: 'Install',
          type: 'boolean'
      }
  })
  .command('url <url> [<name>]', 'Install adapter from specified url, e.g. GitHub', {})
  .command('del <adapter>', 'Remove adapter from system', {})
  .command('del <adapter>.<instance>', 'Remove adapter instance', {})
  .command('update [<repositoryUrl>]', 'Update repository and list adapters', {
      updateable: {
          describe: 'Only show updateable adapters',
          alias: 'u',
          type: 'boolean'
      },
      installed: {
          describe: 'Only show installed adapters',
          alias: 'i',
          type: 'boolean'
      },
      force: {
          describe: 'Bypass hash check',
          alias: 'f',
          type: 'boolean'
      }
  })
  .command('upgrade', 'Upgrade management', yargs => {
      yargs
          .command('[<repositoryUrl>]', 'Upgrade all adapters, optionally you can specify the repository url', {
              yes: {
                  describe: 'Bypass questionnaire',
                  alias: 'y',
                  type: 'boolean'
              }
          })
          .command('self [<repositoryUrl>]', 'Upgrade js-controller, optionally you can specify the repository url', {
              force: {
                  describe: 'Allow downgrades',
                  alias: 'f',
                  type: 'boolean'
              }
          })
          .command('all [<repositoryUrl>]', 'Upgrade all adapters, optionally you can specify the repository url', {
              force: {
                  describe: 'Allow downgrades',
                  alias: 'f',
                  type: 'boolean'
              }
          })
          .command('<adapter> [<repositoryUrl>]', 'Upgrade specified adapter, optionally you can specify the repository url', {
              y: {
                  describe: 'Bypass questionnaire',
                  alias: 'y',
                  type: 'boolean'
              }
          });
  })
  .command('upload', 'Upload management', yargs => {
      yargs
          .command(`<pathToLocalFile> <pathIn${tools.appName}>`, 'Upload given files to provided path to make them available for instances', {})
          .command('all', 'Upload all adapter files to make them available for instances', {})
          .command('<adapter>', 'Upload specified adapter files to make them available for instances', {});
  })
  .command('object', 'Object management', yargs => {
      yargs
          .command('get <id>', 'Get object specified by id', {})
          .command('set <id> <json-value>', 'Set object with the given id by providing a new json object', {})
          .command('set <id> propertyname=<value or json-value>', 'Update part of the object by providing a new value or partial object', {})
          .command('extend <id> <json-value>', 'Extend object with the given id by providing a new json object', {})
          .command('del <id|pattern>', 'Delete object with given id or all objects matching the pattern', {
              y: {
                  describe: 'Bypass questionnaire',
                  alias: 'y',
                  type: 'boolean'
              }
          })
          .command('chmod <object-mode> [state-mode] <id>', 'Change object rights', {})
          .command('chown <user> <group> <id>', 'Change object ownership', {})
          .command('list <pattern>', 'List object matching given pattern', {});
  })
  .command('state', 'State management', yargs => {
      yargs
          .command('get <id>', 'Get state, specified by id', {})
          .command('getplain <id>', 'Get plain state, specified by id', {
              pretty: {
                  describe: 'Prettify output',
                  type: 'boolean'
              }
          })
          .command('getvalue <id>', 'Get state value, specified by id', {})
          .command('set <id> <value> [<ack>]', 'Set state, specified by id', {})
          .command('del <id>', 'Delete state, specified by id', {});
  })
  .command('message <adapter>[.instance] <command> [<message>]', 'Send message to adapter instance/s', {})
  .command('list <type> [<filter>]', 'List all entries, like objects', {})
  .command('chmod <mode> <file>', 'Change file rights', {})
  .command('chown <user> <group> <file>', 'Change file ownership', {})
  .command('touch <file>', 'Touch file', {})
  .command('rm <file>', 'Remove file', {})
  .command('file', 'File management', yargs => {
      yargs
          .command(`read <${tools.appName}-path-to-read> [<filesystem-path-to-write>]`, `Read file from ${tools.appName} path and optionally write to destination`, {})
          .command(`write <filesystem-path-to-read> <${tools.appName}-path-to-write>`, `Read file from path and write it to ${tools.appName} path`,{})
          .command(`rm <${tools.appName}-path-to-delete>`, 'Remove file', {})
          .command('sync', 'Sync files', {});
  })
  .command('user', 'User commands', yargs => {
      yargs
          .command('add <user>', 'Add new user',yargs => {
              yargs.option('ingroup', {
                  describe: 'User group',
                  type: 'string'
              })
                  .option('password', {
                      describe: 'User password',
                      type: 'string'
                  });
          })
          .command('del <user>', 'Delete user', {})
          .command('passwd <user>', 'Change user password', yargs => {
              yargs
                  .option('password', {
                      describe: 'User password',
                      type: 'string'
                  });
          })
          .command('enable <user>', 'Enable user', {})
          .command('disable <user>', 'Disable user', {})
          .command('get <user>', 'Get user', {})
          .command('check <user>', 'Check user password', yargs => {
              yargs
                  .option('password', {
                      describe: 'User password',
                      type: 'string'
                  });
          });
  })
  .command('group', 'group management', yargs => {
      yargs
          .command('add <group>', 'Add group', {})
          .command('del <group>', 'Remove group', {})
          .command('list <group>', 'List group', {})
          .command('enable <group>', 'Enable group', {})
          .command('disable <group>', 'Disable group', {})
          .command('get <group>', 'Get group', {})
          .command('adduser <group> <user>', 'Add user to group', {})
          .command('deluser <group> <user>', 'Remove user from group', {});
  })
  .command('host <hostname>', 'Set host to given hostname', yargs => {
      yargs
          .command('this', 'Initialize current host', {})
          .command('set <hostname>', 'Set host with specified hostname', {})
          .command('remove <hostname>', 'Remove host with specified hostname', {});
  })
  .command('set <adapter>.<instance>', 'Change settings of adapter config', {
      customOption: {
          describe: 'Set the name of the parameter you want to change as option followed by its value, e. g. --port 80'
      }
  })
  .command('license <license.file or license.text>', 'Update license by given file', {})
  .command('cert', 'Certificate management', yargs => {
      yargs
          .command('create', 'Create certificate', {})
          .command('view [<certificate name>]', 'Show certificate', {});
  })
  .command('clean <yes>', 'Clears all objects and states', {})
  .command('backup', 'Create backup', {})
  .command('restore <backup name or path>', 'Restore a specified backup', {})
  .command('validate <backup name or path>', 'Validate a specified backup', {})
  .command('status [all|<adapter>.<instance>]', 'Status of ioBroker or adapter instance', {})
  .command('repo [<name>]', 'Show repo information', yargs => {
      yargs
          .command('set <name>', 'Set active repository')
          .command('repo del <name>', 'Remove repository');
  })
  .command('uuid', 'Show uuid of the installation', {})
  .command('unsetup', 'Reset license, installation secret and language', {})
  .command('fix', 'Execute the installation fixer script, this updates your ioBroker installation', {})
  .command('multihost', 'Multihost management', yargs => {
      yargs
          .command('enable', 'Enable multihost discovery', {
              secure: {
                  describe: 'Use secure connection',
                  type: 'boolean'
              },
              persist: {
                  describe: 'Enable persistent discovery',
                  type: 'boolean'
              }
          })
          .command('disable', 'Disable multihost discovery')
          .command('browse', 'Browse for multihost server')
          .command('connect', 'Connect to multihost server');
  })
  .command('compact', 'compact group management', yargs => {
      yargs
          .command('enable', 'Enable compact mode in general')
          .command('on', 'Enable compact mode in general')
          .command('disable', 'Disable compact mode in general')
          .command('off', 'Disable compact mode in general')
          .command('<adapter>.<instance> status', 'Show if compact mode is enabled for a specific instance')
          .command('<adapter>.<instance> group <group-id>', 'Define compact group of a specific adapter')
          .command('<adapter>.<instance> <disable|off>', 'Enable or disable compact mode for specified adapter instance')
          .command('compact <adapter>.<instance> <enable|on> [group-id]', 'Enable or disable compact mode for specified adapter instance and set compact group optionally');
  })
  .command('plugin', 'Plugin management', yargs => {
      yargs
          .command('enable <pluginname>', 'Enables a plugin for the specified host or instance. If no host is specified, the current one is used', {
              host: {
                  describe: 'Hostname',
                  type: 'string'
              },
              instance: {
                  describe: 'Instance, e.g. hm-rpc.0',
                  type: 'string'
              }
          })
          .command('disable <pluginname>', 'Disables a plugin for the specified host or instance. If no host is specified, the current one is used', {
              host: {
                  describe: 'Hostname',
                  type: 'string'
              },
              instance: {
                  describe: 'Instance, e.g. hm-rpc.0',
                  type: 'string'
              }
          })
          .command('status <pluginname>', 'Checks if a plugin is enabled for the specified host or instance. If no host is specified, the current one is used', {
              host: {
                  describe: 'Hostname',
                  type: 'string'
              },
              instance: {
                  describe: 'Instance, e.g. hm-rpc.0',
                  type: 'string'
              }
          });
  })
  .command('version [<adapter>]', 'Show version of js-controller or specified adapter')
  .option('version', {
      describe: 'Show version',
      type: 'boolean',
      alias: 'v'
  })
  .wrap(null)
  ;

yargs.parse(process.argv.slice(2));
yargs.showHelp();

@foxriver76
Copy link
Author

yes, fixed now. Thank you!

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

No branches or pull requests

2 participants