| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. |
| 4 |
| 5 """Common arguments to the various recipes.py subcommands. |
| 6 |
| 7 This is in a separate file for recipes.py for testing purposes. |
| 8 """ |
| 9 |
| 10 import json |
| 11 import logging |
| 12 import os |
| 13 |
| 14 from . import package_io |
| 15 |
| 16 from . import env |
| 17 |
| 18 import argparse # this is vendored |
| 19 |
| 20 from . import arguments_pb2 |
| 21 |
| 22 from google.protobuf import json_format as jsonpb |
| 23 |
| 24 |
| 25 def add_common_args(parser): |
| 26 class ProjectOverrideAction(argparse.Action): |
| 27 def __call__(self, parser, namespace, values, option_string=None): |
| 28 p = values.split('=', 2) |
| 29 if len(p) != 2: |
| 30 raise ValueError('Override must have the form: repo=path') |
| 31 project_id, path = p |
| 32 |
| 33 v = getattr(namespace, self.dest, None) |
| 34 if v is None: |
| 35 v = {} |
| 36 setattr(namespace, self.dest, v) |
| 37 |
| 38 if v.get(project_id): |
| 39 raise ValueError('An override is already defined for [%s] (%s)' % ( |
| 40 project_id, v[project_id])) |
| 41 path = os.path.abspath(os.path.expanduser(path)) |
| 42 if not os.path.isdir(path): |
| 43 raise ValueError('Override path [%s] is not a directory' % (path,)) |
| 44 v[project_id] = path |
| 45 |
| 46 def package_type(value): |
| 47 if not os.path.isfile(value): |
| 48 raise argparse.ArgumentTypeError( |
| 49 'Given recipes config file %r does not exist.' % (value,)) |
| 50 return package_io.PackageFile(value) |
| 51 |
| 52 parser.add_argument( |
| 53 '--package', |
| 54 type=package_type, |
| 55 help='Path to recipes.cfg of the recipe package to operate on' |
| 56 ', usually in infra/config/recipes.cfg') |
| 57 parser.add_argument( |
| 58 '--deps-path', |
| 59 type=os.path.abspath, |
| 60 help='Path where recipe engine dependencies will be extracted. Specify ' |
| 61 '"-" to use a temporary directory for deps, which will be cleaned ' |
| 62 'up on exit.') |
| 63 parser.add_argument( |
| 64 '--verbose', '-v', action='count', |
| 65 help='Increase logging verboisty') |
| 66 # TODO(phajdan.jr): Figure out if we need --no-fetch; remove if not. |
| 67 parser.add_argument( |
| 68 '--no-fetch', action='store_true', |
| 69 help='Disable automatic fetching') |
| 70 parser.add_argument('-O', '--project-override', metavar='ID=PATH', |
| 71 action=ProjectOverrideAction, |
| 72 help='Override a project repository path with a local one.') |
| 73 parser.add_argument( |
| 74 # Use 'None' as default so that we can recognize when none of the |
| 75 # bootstrap options were passed. |
| 76 '--use-bootstrap', action='store_true', default=None, |
| 77 help='Use bootstrap/bootstrap.py to create a isolated python virtualenv' |
| 78 ' with required python dependencies.') |
| 79 parser.add_argument( |
| 80 '--bootstrap-vpython-path', metavar='PATH', |
| 81 help='Specify the `vpython` executable path to use when bootstrapping (' |
| 82 'requires --use-bootstrap).') |
| 83 parser.add_argument( |
| 84 '--disable-bootstrap', action='store_false', dest='use_bootstrap', |
| 85 help='Disables bootstrap (see --use-bootstrap)') |
| 86 |
| 87 def operational_args_type(value): |
| 88 with open(value) as fd: |
| 89 return jsonpb.ParseDict(json.load(fd), arguments_pb2.Arguments()) |
| 90 |
| 91 parser.set_defaults( |
| 92 operational_args=arguments_pb2.Arguments(), |
| 93 bare_command=False, # don't call postprocess_func, don't use package_deps |
| 94 postprocess_func=lambda parser, args: None, |
| 95 ) |
| 96 |
| 97 parser.add_argument( |
| 98 '--operational-args-path', |
| 99 dest='operational_args', |
| 100 type=operational_args_type, |
| 101 help='The path to an operational Arguments file. If provided, this file ' |
| 102 'must contain a JSONPB-encoded Arguments protobuf message, and will ' |
| 103 'be integrated into the runtime parameters.') |
| 104 |
| 105 def post_process_args(parser, args): |
| 106 # TODO(iannucci): We should always do logging.basicConfig() (probably with |
| 107 # logging.WARNING), even if no verbose is passed. However we need to be |
| 108 # careful as this could cause issues with spurious/unexpected output. |
| 109 # I think it's risky enough to do in a different CL. |
| 110 |
| 111 if args.verbose > 0: |
| 112 logging.basicConfig() |
| 113 logging.getLogger().setLevel(logging.INFO) |
| 114 if args.verbose > 1: |
| 115 logging.getLogger().setLevel(logging.DEBUG) |
| 116 |
| 117 if args.bare_command: |
| 118 # TODO(iannucci): this is gross, and only for the remote subcommand; |
| 119 # remote doesn't behave like ANY other commands. A way to solve this will |
| 120 # be to allow --package to take a remote repo and then simply remove the |
| 121 # remote subcommand entirely. |
| 122 if args.package is not None: |
| 123 parser.error('%s forbids --package' % args.command) |
| 124 else: |
| 125 if not args.package: |
| 126 parser.error('%s requires --package' % args.command) |
| 127 |
| 128 return post_process_args |
| OLD | NEW |