Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: recipes.py

Issue 2845523004: [recipes.py] refactor loading for operational_arguments. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2015 The LUCI Authors. All rights reserved. 2 # Copyright 2015 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file. 4 # that can be found in the LICENSE file.
5 5
6 """Tool to interact with recipe repositories. 6 """Tool to interact with recipe repositories.
7 7
8 This tool operates on the nearest ancestor directory containing an 8 This tool operates on the nearest ancestor directory containing an
9 infra/config/recipes.cfg. 9 infra/config/recipes.cfg.
10 """ 10 """
(...skipping 15 matching lines...) Expand all
26 26
27 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) 27 ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
28 sys.path.insert(0, ROOT_DIR) 28 sys.path.insert(0, ROOT_DIR)
29 29
30 from recipe_engine import env 30 from recipe_engine import env
31 from recipe_engine import arguments_pb2 31 from recipe_engine import arguments_pb2
32 from recipe_engine import util as recipe_util 32 from recipe_engine import util as recipe_util
33 from google.protobuf import json_format as jsonpb 33 from google.protobuf import json_format as jsonpb
34 34
35 35
36 def test(config_file, package_deps, args, op_args): 36 def test(config_file, package_deps, args):
37 try: 37 try:
38 from recipe_engine import test 38 from recipe_engine import test
39 except ImportError: 39 except ImportError:
40 logging.error( 40 logging.error(
41 'Error while importing testing libraries. You may be missing the pip' 41 'Error while importing testing libraries. You may be missing the pip'
42 ' package "coverage". Install it, or use the --use-bootstrap command' 42 ' package "coverage". Install it, or use the --use-bootstrap command'
43 ' line argument when calling into the recipe engine, which will install' 43 ' line argument when calling into the recipe engine, which will install'
44 ' it for you.') 44 ' it for you.')
45 raise 45 raise
46 46
47 from recipe_engine import loader 47 from recipe_engine import loader
48 from recipe_engine import package 48 from recipe_engine import package
49 49
50 universe = loader.RecipeUniverse(package_deps, config_file) 50 universe = loader.RecipeUniverse(package_deps, config_file)
51 universe_view = loader.UniverseView(universe, package_deps.root_package) 51 universe_view = loader.UniverseView(universe, package_deps.root_package)
52 52
53 # Prevent flakiness caused by stale pyc files. 53 # Prevent flakiness caused by stale pyc files.
54 package.cleanup_pyc(package_deps.root_package.recipes_dir) 54 package.cleanup_pyc(package_deps.root_package.recipes_dir)
55 55
56 return test.main( 56 return test.main(
57 universe_view, raw_args=args.args, 57 universe_view, raw_args=args.args,
58 engine_flags=op_args.engine_flags) 58 engine_flags=args.operational_args.engine_flags)
59 59
60 60
61 def lint(config_file, package_deps, args): 61 def lint(config_file, package_deps, args):
62 from recipe_engine import lint_test 62 from recipe_engine import lint_test
63 from recipe_engine import loader 63 from recipe_engine import loader
64 64
65 universe = loader.RecipeUniverse(package_deps, config_file) 65 universe = loader.RecipeUniverse(package_deps, config_file)
66 universe_view = loader.UniverseView(universe, package_deps.root_package) 66 universe_view = loader.UniverseView(universe, package_deps.root_package)
67 67
68 lint_test.main(universe_view, args.whitelist or []) 68 lint_test.main(universe_view, args.whitelist or [])
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 141
142 with stream_engine.make_step_stream('Failure reason') as s: 142 with stream_engine.make_step_stream('Failure reason') as s:
143 with s.new_log_stream('reason') as l: 143 with s.new_log_stream('reason') as l:
144 l.write_split(f.human_reason) 144 l.write_split(f.human_reason)
145 145
146 return 1 146 return 1
147 147
148 return 0 148 return 0
149 149
150 150
151 def run(config_file, package_deps, args, op_args): 151 def run(config_file, package_deps, args):
152 from recipe_engine import run as recipe_run 152 from recipe_engine import run as recipe_run
153 from recipe_engine import loader 153 from recipe_engine import loader
154 from recipe_engine import step_runner 154 from recipe_engine import step_runner
155 from recipe_engine import stream 155 from recipe_engine import stream
156 from recipe_engine import stream_logdog 156 from recipe_engine import stream_logdog
157 157
158 if args.props: 158 if args.props:
159 for p in args.props: 159 for p in args.props:
160 args.properties.update(p) 160 args.properties.update(p)
161 161
162 def get_properties_from_operational_args(op_args): 162 def get_properties_from_operational_args(op_args):
163 if not op_args.properties.property: 163 if not op_args.properties.property:
164 return None 164 return None
165 return _op_properties_to_dict(op_args.properties.property) 165 return _op_properties_to_dict(op_args.properties.property)
166 166
167 op_args = args.operational_args
167 op_properties = get_properties_from_operational_args(op_args) 168 op_properties = get_properties_from_operational_args(op_args)
168 if args.properties and op_properties: 169 if args.properties and op_properties:
169 raise ValueError( 170 raise ValueError(
170 "Got operational args properties as well as CLI properties.") 171 "Got operational args properties as well as CLI properties.")
171 172
172 properties = op_properties 173 properties = op_properties
173 if not properties: 174 if not properties:
174 properties = args.properties 175 properties = args.properties
175 176
176 properties['recipe'] = args.recipe 177 properties['recipe'] = args.recipe
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 help='Override a project repository path with a local one.') 377 help='Override a project repository path with a local one.')
377 parser.add_argument( 378 parser.add_argument(
378 # Use "None" as default so that we can recognize when none of the 379 # Use "None" as default so that we can recognize when none of the
379 # bootstrap options were passed. 380 # bootstrap options were passed.
380 '--use-bootstrap', action='store_true', default=None, 381 '--use-bootstrap', action='store_true', default=None,
381 help='Use bootstrap/bootstrap.py to create a isolated python virtualenv' 382 help='Use bootstrap/bootstrap.py to create a isolated python virtualenv'
382 ' with required python dependencies.') 383 ' with required python dependencies.')
383 parser.add_argument( 384 parser.add_argument(
384 '--disable-bootstrap', action='store_false', dest='use_bootstrap', 385 '--disable-bootstrap', action='store_false', dest='use_bootstrap',
385 help='Disables bootstrap (see --use-bootstrap)') 386 help='Disables bootstrap (see --use-bootstrap)')
387
388 def operational_args_type(value):
389 op_args = arguments_pb2.Arguments()
390 with open(value) as fd:
dnj 2017/04/26 19:52:04 nit: Up to you, but if you care you could make thi
iannucci 2017/04/26 20:08:35 oh, yeah I just transplanted this code without loo
391 data = fd.read()
392 jsonpb.Parse(data, op_args)
393 return op_args
394
386 parser.add_argument( 395 parser.add_argument(
387 '--operational-args-path', action='store', 396 '--operational-args-path',
388 type=os.path.abspath, 397 dest='operational_args',
398 type=operational_args_type,
389 help='The path to an operational Arguments file. If provided, this file ' 399 help='The path to an operational Arguments file. If provided, this file '
390 'must contain a JSONPB-encoded Arguments protobuf message, and will ' 400 'must contain a JSONPB-encoded Arguments protobuf message, and will '
391 'be integrated into the runtime parameters.') 401 'be integrated into the runtime parameters.')
392 402
393 403
394 def post_process_common_args(parser, args): 404 def post_process_common_args(parser, args):
395 if args.command == "remote": 405 if args.command == "remote":
396 # TODO(iannucci): this is a hack; remote doesn't behave like ANY other 406 # TODO(iannucci): this is a hack; remote doesn't behave like ANY other
397 # commands. A way to solve this will be to allow --package to take a remote 407 # commands. A way to solve this will be to allow --package to take a remote
398 # repo and then simply remove the remote subcommand entirely. 408 # repo and then simply remove the remote subcommand entirely.
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 'with their documentation') 599 'with their documentation')
590 doc_p.add_argument('recipe', nargs='?', 600 doc_p.add_argument('recipe', nargs='?',
591 help='Restrict documentation to this recipe') 601 help='Restrict documentation to this recipe')
592 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, 602 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds,
593 help='Output this kind of documentation') 603 help='Output this kind of documentation')
594 doc_p.set_defaults(command='doc') 604 doc_p.set_defaults(command='doc')
595 605
596 args = parser.parse_args() 606 args = parser.parse_args()
597 post_process_common_args(parser, args) 607 post_process_common_args(parser, args)
598 608
599 # Load/parse operational arguments.
600 op_args = arguments_pb2.Arguments()
601 if args.operational_args_path is not None:
602 with open(args.operational_args_path) as fd:
603 data = fd.read()
604 jsonpb.Parse(data, op_args)
605
606 # TODO(iannucci): We should always do logging.basicConfig() (probably with 609 # TODO(iannucci): We should always do logging.basicConfig() (probably with
607 # logging.WARNING), even if no verbose is passed. However we need to be 610 # logging.WARNING), even if no verbose is passed. However we need to be
608 # careful as this could cause issues with spurious/unexpected output. I think 611 # careful as this could cause issues with spurious/unexpected output. I think
609 # it's risky enough to do in a different CL. 612 # it's risky enough to do in a different CL.
610 613
611 if args.verbose > 0: 614 if args.verbose > 0:
612 logging.basicConfig() 615 logging.basicConfig()
613 logging.getLogger().setLevel(logging.INFO) 616 logging.getLogger().setLevel(logging.INFO)
614 if args.verbose > 1: 617 if args.verbose > 1:
615 logging.getLogger().setLevel(logging.DEBUG) 618 logging.getLogger().setLevel(logging.DEBUG)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
668 return subprocess.call( 671 return subprocess.call(
669 [ 672 [
670 os.path.join(env_path, 'bin', python_exe), 673 os.path.join(env_path, 'bin', python_exe),
671 '-B', # Don't compile "pyo" binaries. 674 '-B', # Don't compile "pyo" binaries.
672 '-E', # Don't use PYTHON* enviornment variables. 675 '-E', # Don't use PYTHON* enviornment variables.
673 '-s', # Don't use user 'site.py'. 676 '-s', # Don't use user 'site.py'.
674 os.path.join(ROOT_DIR, 'recipes.py'), 677 os.path.join(ROOT_DIR, 'recipes.py'),
675 ] + sys.argv[1:]) 678 ] + sys.argv[1:])
676 679
677 # Standard recipe engine operation. 680 # Standard recipe engine operation.
678 return _real_main(args, op_args) 681 return _real_main(args)
679 682
680 finally: 683 finally:
681 # If we're using a temporary deps directory, clean it up here. 684 # If we're using a temporary deps directory, clean it up here.
682 if temp_deps_dir: 685 if temp_deps_dir:
683 logging.info('Cleaning up temporary deps path: %s', temp_deps_dir) 686 logging.info('Cleaning up temporary deps path: %s', temp_deps_dir)
684 687
685 # Remove as much of the temporary directory as we can. If something goes 688 # Remove as much of the temporary directory as we can. If something goes
686 # wrong, log the error, but don't actually raise anything. 689 # wrong, log the error, but don't actually raise anything.
687 def on_error(_function, path, excinfo): 690 def on_error(_function, path, excinfo):
688 logging.error('Error cleaning up temporary deps file: %s', path, 691 logging.error('Error cleaning up temporary deps file: %s', path,
689 exc_info=excinfo) 692 exc_info=excinfo)
690 shutil.rmtree(temp_deps_dir, onerror=on_error) 693 shutil.rmtree(temp_deps_dir, onerror=on_error)
691 694
692 695
693 def _real_main(args, op_args): 696 def _real_main(args):
694 from recipe_engine import package, package_io 697 from recipe_engine import package
695 698
696 # Commands which do not require config_file, package_deps, and other objects 699 # Commands which do not require config_file, package_deps, and other objects
697 # initialized later. 700 # initialized later.
698 if args.command == 'remote': 701 if args.command == 'remote':
699 return remote(args) 702 return remote(args)
700 703
701 config_file = args.package 704 config_file = args.package
702 repo_root = package.InfraRepoConfig().from_recipes_cfg(args.package.path) 705 repo_root = package.InfraRepoConfig().from_recipes_cfg(args.package.path)
703 706
704 try: 707 try:
705 # TODO(phajdan.jr): gracefully handle inconsistent deps when rolling. 708 # TODO(phajdan.jr): gracefully handle inconsistent deps when rolling.
706 # This fails if the starting point does not have consistent dependency 709 # This fails if the starting point does not have consistent dependency
707 # graph. When performing an automated roll, it'd make sense to attempt 710 # graph. When performing an automated roll, it'd make sense to attempt
708 # to automatically find a consistent state, rather than bailing out. 711 # to automatically find a consistent state, rather than bailing out.
709 # Especially that only some subcommands refer to package_deps. 712 # Especially that only some subcommands refer to package_deps.
710 package_deps = package.PackageDeps.create( 713 package_deps = package.PackageDeps.create(
711 repo_root, config_file, allow_fetch=not args.no_fetch, 714 repo_root, config_file, allow_fetch=not args.no_fetch,
712 deps_path=args.deps_path, overrides=args.project_override) 715 deps_path=args.deps_path, overrides=args.project_override)
713 except subprocess.CalledProcessError: 716 except subprocess.CalledProcessError:
714 # A git checkout failed somewhere. Return 2, which is the sign that this is 717 # A git checkout failed somewhere. Return 2, which is the sign that this is
715 # an infra failure, rather than a test failure. 718 # an infra failure, rather than a test failure.
716 return 2 719 return 2
717 720
718 if args.command == 'fetch': 721 if args.command == 'fetch':
719 # We already did everything in the create() call above. 722 # We already did everything in the create() call above.
720 assert not args.no_fetch, 'Fetch? No-fetch? Make up your mind!' 723 assert not args.no_fetch, 'Fetch? No-fetch? Make up your mind!'
721 return 0 724 return 0
722 elif args.command == 'test': 725 elif args.command == 'test':
723 return test(config_file, package_deps, args, op_args) 726 return test(config_file, package_deps, args)
724 elif args.command == 'bundle': 727 elif args.command == 'bundle':
725 return bundle(config_file, package_deps, args) 728 return bundle(config_file, package_deps, args)
726 elif args.command == 'lint': 729 elif args.command == 'lint':
727 return lint(config_file, package_deps, args) 730 return lint(config_file, package_deps, args)
728 elif args.command == 'run': 731 elif args.command == 'run':
729 return run(config_file, package_deps, args, op_args) 732 return run(config_file, package_deps, args)
730 elif args.command == 'autoroll': 733 elif args.command == 'autoroll':
731 return autoroll(repo_root, config_file, args) 734 return autoroll(repo_root, config_file, args)
732 elif args.command == 'depgraph': 735 elif args.command == 'depgraph':
733 return depgraph(config_file, package_deps, args) 736 return depgraph(config_file, package_deps, args)
734 elif args.command == 'refs': 737 elif args.command == 'refs':
735 return refs(config_file, package_deps, args) 738 return refs(config_file, package_deps, args)
736 elif args.command == 'doc': 739 elif args.command == 'doc':
737 return doc(config_file, package_deps, args) 740 return doc(config_file, package_deps, args)
738 else: 741 else:
739 print """Dear sir or madam, 742 print """Dear sir or madam,
(...skipping 27 matching lines...) Expand all
767 770
768 if not isinstance(ret, int): 771 if not isinstance(ret, int):
769 if ret is None: 772 if ret is None:
770 ret = 0 773 ret = 0
771 else: 774 else:
772 print >> sys.stderr, ret 775 print >> sys.stderr, ret
773 ret = 1 776 ret = 1
774 sys.stdout.flush() 777 sys.stdout.flush()
775 sys.stderr.flush() 778 sys.stderr.flush()
776 os._exit(ret) 779 os._exit(ret)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698