Mike Frysinger | e58c0e2 | 2017-10-04 15:43:30 -0400 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
Chris Sosa | 90c7850 | 2012-10-05 17:07:42 -0700 | [diff] [blame] | 2 | # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
David Pursell | e19f83b | 2015-07-01 12:57:07 -0700 | [diff] [blame] | 6 | """This implements the entry point for the `cros` CLI toolset. |
Don Garrett | 25f309a | 2014-03-19 14:02:12 -0700 | [diff] [blame] | 7 | |
David Pursell | e19f83b | 2015-07-01 12:57:07 -0700 | [diff] [blame] | 8 | This script is invoked by chromite/bin/cros, which sets up the |
David Pursell | ffb9004 | 2015-03-23 09:21:41 -0700 | [diff] [blame] | 9 | proper execution environment and calls this module's main() function. |
Don Garrett | 25f309a | 2014-03-19 14:02:12 -0700 | [diff] [blame] | 10 | |
| 11 | In turn, this script looks for a subcommand based on how it was invoked. For |
David Pursell | ffb9004 | 2015-03-23 09:21:41 -0700 | [diff] [blame] | 12 | example, `cros lint` will use the cli/cros/cros_lint.py subcommand. |
Don Garrett | 25f309a | 2014-03-19 14:02:12 -0700 | [diff] [blame] | 13 | |
David Pursell | ffb9004 | 2015-03-23 09:21:41 -0700 | [diff] [blame] | 14 | See cli/ for actual command implementations. |
Don Garrett | 25f309a | 2014-03-19 14:02:12 -0700 | [diff] [blame] | 15 | """ |
| 16 | |
Mike Frysinger | 383367e | 2014-09-16 15:06:17 -0400 | [diff] [blame] | 17 | from __future__ import print_function |
| 18 | |
David Pursell | f1c27c1 | 2015-03-18 09:51:38 -0700 | [diff] [blame] | 19 | from chromite.cli import command |
Chris Sosa | b445f79 | 2012-10-11 15:26:39 -0700 | [diff] [blame] | 20 | from chromite.lib import commandline |
Ralph Nathan | 91874ca | 2015-03-19 13:29:41 -0700 | [diff] [blame] | 21 | from chromite.lib import cros_logging as logging |
Chris Sosa | 90c7850 | 2012-10-05 17:07:42 -0700 | [diff] [blame] | 22 | |
| 23 | |
Brian Harring | 984988f | 2012-10-10 22:53:30 -0700 | [diff] [blame] | 24 | def GetOptions(my_commands): |
David Pursell | 643ed34 | 2015-07-07 09:24:32 -0700 | [diff] [blame] | 25 | """Returns the parser to use for commandline parsing. |
Chris Sosa | 90c7850 | 2012-10-05 17:07:42 -0700 | [diff] [blame] | 26 | |
David Pursell | 643ed34 | 2015-07-07 09:24:32 -0700 | [diff] [blame] | 27 | Args: |
| 28 | my_commands: A dictionary mapping subcommand names to classes. |
| 29 | |
| 30 | Returns: |
| 31 | A commandline.ArgumentParser object. |
| 32 | """ |
| 33 | parser = commandline.ArgumentParser(caching=True, default_log_level='notice') |
| 34 | |
| 35 | if my_commands: |
| 36 | subparsers = parser.add_subparsers(title='Subcommands') |
| 37 | for cmd_name in sorted(my_commands.iterkeys()): |
| 38 | class_def = my_commands[cmd_name] |
| 39 | epilog = getattr(class_def, 'EPILOG', None) |
| 40 | sub_parser = subparsers.add_parser( |
| 41 | cmd_name, description=class_def.__doc__, epilog=epilog, |
| 42 | caching=class_def.use_caching_options, |
| 43 | formatter_class=commandline.argparse.RawDescriptionHelpFormatter) |
| 44 | class_def.AddParser(sub_parser) |
Chris Sosa | 90c7850 | 2012-10-05 17:07:42 -0700 | [diff] [blame] | 45 | |
| 46 | return parser |
| 47 | |
| 48 | |
Ryan Cui | 47f80e4 | 2013-04-01 19:01:54 -0700 | [diff] [blame] | 49 | def _RunSubCommand(subcommand): |
| 50 | """Helper function for testing purposes.""" |
Ryan Cui | de21f48 | 2013-08-06 11:50:59 -0700 | [diff] [blame] | 51 | return subcommand.Run() |
Ryan Cui | 47f80e4 | 2013-04-01 19:01:54 -0700 | [diff] [blame] | 52 | |
| 53 | |
Mike Frysinger | 9ad5fab | 2013-05-30 13:37:26 -0400 | [diff] [blame] | 54 | def main(argv): |
David Pursell | dfbfbc8 | 2015-03-05 10:59:16 -0800 | [diff] [blame] | 55 | try: |
David Pursell | f1c27c1 | 2015-03-18 09:51:38 -0700 | [diff] [blame] | 56 | parser = GetOptions(command.ListCommands()) |
David Pursell | dfbfbc8 | 2015-03-05 10:59:16 -0800 | [diff] [blame] | 57 | # Cros currently does nothing without a subcmd. Print help if no args are |
| 58 | # specified. |
| 59 | if not argv: |
| 60 | parser.print_help() |
| 61 | return 1 |
| 62 | |
| 63 | namespace = parser.parse_args(argv) |
David Pursell | ffb9004 | 2015-03-23 09:21:41 -0700 | [diff] [blame] | 64 | subcommand = namespace.command_class(namespace) |
Aviv Keshet | 01a82e9 | 2017-03-02 17:39:59 -0800 | [diff] [blame] | 65 | try: |
| 66 | code = _RunSubCommand(subcommand) |
| 67 | except (commandline.ChrootRequiredError, commandline.ExecRequiredError): |
| 68 | # The higher levels want these passed back, so oblige. |
| 69 | raise |
| 70 | except Exception as e: |
| 71 | code = 1 |
| 72 | logging.error('cros %s failed before completing.', |
| 73 | subcommand.command_name) |
| 74 | if namespace.debug: |
Mike Frysinger | 684d36e | 2015-06-03 05:03:34 -0400 | [diff] [blame] | 75 | raise |
Aviv Keshet | 01a82e9 | 2017-03-02 17:39:59 -0800 | [diff] [blame] | 76 | else: |
| 77 | logging.error(e) |
Mike Frysinger | a46f57d | 2018-07-19 12:18:22 -0400 | [diff] [blame] | 78 | logging.error('(Re-run with --debug for more details.)') |
Mike Frysinger | 684d36e | 2015-06-03 05:03:34 -0400 | [diff] [blame] | 79 | |
Aviv Keshet | 01a82e9 | 2017-03-02 17:39:59 -0800 | [diff] [blame] | 80 | if code is not None: |
| 81 | return code |
David Pursell | dfbfbc8 | 2015-03-05 10:59:16 -0800 | [diff] [blame] | 82 | |
| 83 | return 0 |
| 84 | except KeyboardInterrupt: |
| 85 | logging.debug('Aborted due to keyboard interrupt.') |
Chris Sosa | 90c7850 | 2012-10-05 17:07:42 -0700 | [diff] [blame] | 86 | return 1 |