# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """This implements the entry point for the `cros` CLI toolset. This script is invoked by chromite/bin/cros, which sets up the proper execution environment and calls this module's main() function. In turn, this script looks for a subcommand based on how it was invoked. For example, `cros lint` will use the cli/cros/cros_lint.py subcommand. See cli/ for actual command implementations. """ from __future__ import print_function import sys from chromite.cli import command from chromite.lib import commandline from chromite.lib import cros_logging as logging from chromite.lib import stats def GetOptions(my_commands): """Returns the parser to use for commandline parsing. Args: my_commands: A dictionary mapping subcommand names to classes. Returns: A commandline.ArgumentParser object. """ parser = commandline.ArgumentParser(caching=True, default_log_level='notice') if my_commands: subparsers = parser.add_subparsers(title='Subcommands') for cmd_name in sorted(my_commands.iterkeys()): class_def = my_commands[cmd_name] epilog = getattr(class_def, 'EPILOG', None) sub_parser = subparsers.add_parser( cmd_name, description=class_def.__doc__, epilog=epilog, caching=class_def.use_caching_options, formatter_class=commandline.argparse.RawDescriptionHelpFormatter) class_def.AddParser(sub_parser) return parser def _RunSubCommand(subcommand): """Helper function for testing purposes.""" return subcommand.Run() def main(argv): try: parser = GetOptions(command.ListCommands()) # Cros currently does nothing without a subcmd. Print help if no args are # specified. if not argv: parser.print_help() return 1 namespace = parser.parse_args(argv) subcommand = namespace.command_class(namespace) with stats.UploadContext() as queue: if subcommand.upload_stats: cmd_base = subcommand.options.command_class.command_name cmd_stats = stats.Stats.SafeInit(cmd_line=sys.argv, cmd_base=cmd_base) if cmd_stats: queue.put([cmd_stats, stats.StatsUploader.URL, subcommand.upload_stats_timeout]) # TODO: to make command completion faster, send an interrupt signal to the # stats uploader task after the subcommand completes. try: code = _RunSubCommand(subcommand) except (commandline.ChrootRequiredError, commandline.ExecRequiredError): # The higher levels want these passed back, so oblige. raise except Exception as e: code = 1 logging.error('cros %s failed before completing.', subcommand.command_name) if namespace.debug: raise else: logging.error(e) if code is not None: return code return 0 except KeyboardInterrupt: logging.debug('Aborted due to keyboard interrupt.') return 1