1# Copyright 2020 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Defines arguments for the pw command.""" 15 16import argparse 17import logging 18from pathlib import Path 19import sys 20from typing import NoReturn 21 22from pw_cli import plugins 23from pw_cli.branding import banner 24 25_HELP_HEADER = '''The Pigweed command line interface (CLI). 26 27Example uses: 28 pw logdemo 29 pw --loglevel debug watch out/clang 30''' 31 32 33def parse_args() -> argparse.Namespace: 34 return _parser().parse_args() 35 36 37def print_banner() -> None: 38 """Prints the PIGWEED (or project specific) banner to stderr.""" 39 print(banner(), file=sys.stderr) 40 41 42def format_help(registry: plugins.Registry) -> str: 43 """Returns the pw help information as a string.""" 44 return f'{_parser().format_help()}\n{registry.short_help()}' 45 46 47class _ArgumentParserWithBanner(argparse.ArgumentParser): 48 """Parser that the Pigweed banner when there are parsing errors.""" 49 def error(self, message: str) -> NoReturn: 50 print_banner() 51 self.print_usage(sys.stderr) 52 self.exit(2, f'{self.prog}: error: {message}\n') 53 54 55def _parser() -> argparse.ArgumentParser: 56 """Creates an argument parser for the pw command.""" 57 argparser = _ArgumentParserWithBanner( 58 prog='pw', 59 add_help=False, 60 description=_HELP_HEADER, 61 formatter_class=argparse.RawDescriptionHelpFormatter) 62 63 def directory(arg: str) -> Path: 64 path = Path(arg) 65 if path.is_dir(): 66 return path.resolve() 67 68 raise argparse.ArgumentTypeError(f'{path} is not a directory') 69 70 def log_level(arg: str) -> int: 71 try: 72 return getattr(logging, arg.upper()) 73 except AttributeError: 74 raise argparse.ArgumentTypeError( 75 f'{arg.upper()} is not a valid log level') 76 77 # Do not use the built-in help argument so that displaying the help info can 78 # be deferred until the pw plugins have been registered. 79 argparser.add_argument('-h', 80 '--help', 81 action='store_true', 82 help='Display this help message and exit') 83 argparser.add_argument( 84 '-C', 85 '--directory', 86 type=directory, 87 default=Path.cwd(), 88 help='Change to this directory before doing anything') 89 argparser.add_argument( 90 '-l', 91 '--loglevel', 92 type=log_level, 93 default=logging.INFO, 94 help='Set the log level (debug, info, warning, error, critical)') 95 argparser.add_argument('--no-banner', 96 action='store_true', 97 help='Do not print the Pigweed banner') 98 argparser.add_argument( 99 'command', 100 nargs='?', 101 help='Which command to run; see supported commands below') 102 argparser.add_argument( 103 'plugin_args', 104 metavar='...', 105 nargs=argparse.REMAINDER, 106 help='Remaining arguments are forwarded to the command') 107 108 return argparser 109