app: handle unexpected command name better
Right now if you run a zephyr extension like 'west build' outside of a workspace, argparse says: [...] invalid choice: ‘build’ [...] This is because argparse's subcommand parser doesn't seem to have any API to add a catch-all value for when the user provides an unknown command, so it expects that exactly the subcommands we told it about are available. This is confusing to users, and now that we have our own EarlyArgs parsed, we can do better by printing some west-specific help if we aren't in a workspace: usage: west [-h] [-z ZEPHYR_BASE] [-v] [-V] <command> ... west: unknown command "build"; do you need to run this inside a workspace? as well as if you are: usage: west [-h] [-z ZEPHYR_BASE] [-v] [-V] <command> ... west: unknown command "foo"; workspace /home/mbolivar/zp does not define this extension command -- try "west help" Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
parent
f9630e37be
commit
d842371089
|
@ -184,6 +184,8 @@ class WestApp:
|
||||||
def run(self, argv):
|
def run(self, argv):
|
||||||
# Run the command-line application with argument list 'argv'.
|
# Run the command-line application with argument list 'argv'.
|
||||||
|
|
||||||
|
early_args = parse_early_args(argv)
|
||||||
|
|
||||||
# Silence validation errors from pykwalify, which are logged at
|
# Silence validation errors from pykwalify, which are logged at
|
||||||
# logging.ERROR level. We want to handle those ourselves as
|
# logging.ERROR level. We want to handle those ourselves as
|
||||||
# needed.
|
# needed.
|
||||||
|
@ -218,7 +220,7 @@ class WestApp:
|
||||||
self.setup_parsers()
|
self.setup_parsers()
|
||||||
|
|
||||||
# OK, we are all set. Run the command.
|
# OK, we are all set. Run the command.
|
||||||
self.run_command(argv)
|
self.run_command(argv, early_args)
|
||||||
|
|
||||||
def load_manifest(self):
|
def load_manifest(self):
|
||||||
# Try to parse the manifest. We'll save it if that works, so
|
# Try to parse the manifest. We'll save it if that works, so
|
||||||
|
@ -451,11 +453,12 @@ class WestApp:
|
||||||
|
|
||||||
return parser, subparser_gen
|
return parser, subparser_gen
|
||||||
|
|
||||||
def run_command(self, argv):
|
def run_command(self, argv, early_args):
|
||||||
# Parse command line arguments and run the WestCommand.
|
# Parse command line arguments and run the WestCommand.
|
||||||
# If we're running an extension, instantiate it from its
|
# If we're running an extension, instantiate it from its
|
||||||
# spec and re-parse arguments before running.
|
# spec and re-parse arguments before running.
|
||||||
|
|
||||||
|
self.handle_early_arg_errors(early_args)
|
||||||
args, unknown = self.west_parser.parse_known_args(args=argv)
|
args, unknown = self.west_parser.parse_known_args(args=argv)
|
||||||
|
|
||||||
# Set up logging verbosity before running the command, for
|
# Set up logging verbosity before running the command, for
|
||||||
|
@ -537,6 +540,30 @@ class WestApp:
|
||||||
except WestNotFound as wnf:
|
except WestNotFound as wnf:
|
||||||
self.cmd.die(str(wnf))
|
self.cmd.die(str(wnf))
|
||||||
|
|
||||||
|
def handle_early_arg_errors(self, early_args):
|
||||||
|
# If early_args indicates we should error out, handle it
|
||||||
|
# gracefully. This provides more user-friendly output than
|
||||||
|
# argparse can do on its own.
|
||||||
|
|
||||||
|
if (early_args.command_name and
|
||||||
|
(early_args.command_name not in self.builtins and
|
||||||
|
(not self.extensions or
|
||||||
|
early_args.command_name not in self.extensions))):
|
||||||
|
self.handle_unknown_command(early_args.command_name)
|
||||||
|
|
||||||
|
def handle_unknown_command(self, command_name):
|
||||||
|
if self.topdir:
|
||||||
|
extra_help = (f'workspace {self.topdir} does not define '
|
||||||
|
'this extension command -- try "west help"')
|
||||||
|
else:
|
||||||
|
extra_help = 'do you need to run this inside a workspace?'
|
||||||
|
self.print_usage_and_exit(f'west: unknown command "{command_name}"; '
|
||||||
|
f'{extra_help}')
|
||||||
|
|
||||||
|
def print_usage_and_exit(self, message):
|
||||||
|
self.west_parser.print_usage(file=sys.stderr)
|
||||||
|
sys.exit(message)
|
||||||
|
|
||||||
def run_builtin(self, args, unknown):
|
def run_builtin(self, args, unknown):
|
||||||
self.queued_io.append(
|
self.queued_io.append(
|
||||||
lambda cmd: cmd.dbg('args namespace:', args,
|
lambda cmd: cmd.dbg('args namespace:', args,
|
||||||
|
|
Loading…
Reference in New Issue