| #!/usr/bin/env python3 |
| # Copyright 2023 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| Provides a framework for command line interfaces based on argh. |
| |
| It automatically adds common arguments, such as -v, -vv and --color to provide consistent |
| behavior. |
| """ |
| |
| import argparse |
| import sys |
| import traceback |
| from typing import ( |
| Any, |
| Callable, |
| Optional, |
| ) |
| |
| from .util import ( |
| add_common_args, |
| parse_common_args, |
| print_timing_info, |
| record_time, |
| verbose, |
| ensure_packages_exist, |
| ) |
| |
| ensure_packages_exist("argh") |
| import argh # type: ignore |
| |
| # Hack: argh does not support type annotations. This prevents type errors. |
| argh: Any # type: ignore |
| |
| |
| def run_main(main_fn: Callable[..., Any], usage: Optional[str] = None): |
| run_commands(default_fn=main_fn, usage=usage) |
| |
| |
| def run_commands( |
| *functions: Callable[..., Any], |
| default_fn: Optional[Callable[..., Any]] = None, |
| usage: Optional[str] = None, |
| ): |
| """ |
| Allow the user to call the provided functions with command line arguments translated to |
| function arguments via argh: https://pythonhosted.org/argh |
| """ |
| exit_code = 0 |
| try: |
| parser = argparse.ArgumentParser( |
| description=usage, |
| # Docstrings are used as the description in argparse, preserve their formatting. |
| formatter_class=argparse.RawDescriptionHelpFormatter, |
| # Do not allow implied abbreviations. Abbreviations should be manually specified. |
| allow_abbrev=False, |
| ) |
| add_common_args(parser) |
| |
| # Add provided commands to parser. Do not use sub-commands if we just got one function. |
| if functions: |
| argh.add_commands(parser, functions) # type: ignore |
| if default_fn: |
| argh.set_default_command(parser, default_fn) # type: ignore |
| |
| with record_time("Total Time"): |
| # Call main method |
| argh.dispatch(parser) # type: ignore |
| |
| except Exception as e: |
| if verbose(): |
| traceback.print_exc() |
| else: |
| print(e) |
| exit_code = 1 |
| |
| if parse_common_args().timing_info: |
| print_timing_info() |
| |
| sys.exit(exit_code) |
| |
| |
| if __name__ == "__main__": |
| import doctest |
| |
| (failures, num_tests) = doctest.testmod(optionflags=doctest.ELLIPSIS) |
| sys.exit(1 if failures > 0 else 0) |