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

Side by Side Diff: recipes.py

Issue 2844153002: [recipes.py] move test arg parsing to its module (Closed)
Patch Set: rebase Created 3 years, 7 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 | « recipe_engine/test.py ('k') | 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 16 matching lines...) Expand all
27 sys.path.insert(0, ROOT_DIR) 27 sys.path.insert(0, ROOT_DIR)
28 28
29 from recipe_engine import env 29 from recipe_engine import env
30 30
31 import argparse # this is vendored 31 import argparse # this is vendored
32 from recipe_engine import arguments_pb2 32 from recipe_engine import arguments_pb2
33 from recipe_engine import util as recipe_util 33 from recipe_engine import util as recipe_util
34 from google.protobuf import json_format as jsonpb 34 from google.protobuf import json_format as jsonpb
35 35
36 36
37 def test(config_file, package_deps, args):
38 try:
39 from recipe_engine import test
40 except ImportError:
41 logging.error(
42 'Error while importing testing libraries. You may be missing the pip'
43 ' package "coverage". Install it, or use the --use-bootstrap command'
44 ' line argument when calling into the recipe engine, which will install'
45 ' it for you.')
46 raise
47
48 from recipe_engine import loader
49 from recipe_engine import package
50
51 universe = loader.RecipeUniverse(package_deps, config_file)
52 universe_view = loader.UniverseView(universe, package_deps.root_package)
53
54 # Prevent flakiness caused by stale pyc files.
55 package.cleanup_pyc(package_deps.root_package.recipes_dir)
56
57 return test.main(
58 universe_view, raw_args=args.args,
59 engine_flags=args.operational_args.engine_flags)
60
61
62 def handle_recipe_return(recipe_result, result_filename, stream_engine, 37 def handle_recipe_return(recipe_result, result_filename, stream_engine,
63 engine_flags): 38 engine_flags):
64 if engine_flags and engine_flags.use_result_proto: 39 if engine_flags and engine_flags.use_result_proto:
65 return new_handle_recipe_return( 40 return new_handle_recipe_return(
66 recipe_result, result_filename, stream_engine) 41 recipe_result, result_filename, stream_engine)
67 42
68 if 'recipe_result' in recipe_result.result: 43 if 'recipe_result' in recipe_result.result:
69 result_string = json.dumps( 44 result_string = json.dumps(
70 recipe_result.result['recipe_result'], indent=2) 45 recipe_result.result['recipe_result'], indent=2)
71 if result_filename: 46 if result_filename:
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 '--disable-bootstrap', action='store_false', dest='use_bootstrap', 301 '--disable-bootstrap', action='store_false', dest='use_bootstrap',
327 help='Disables bootstrap (see --use-bootstrap)') 302 help='Disables bootstrap (see --use-bootstrap)')
328 303
329 def operational_args_type(value): 304 def operational_args_type(value):
330 with open(value) as fd: 305 with open(value) as fd:
331 return jsonpb.ParseDict(json.load(fd), arguments_pb2.Arguments()) 306 return jsonpb.ParseDict(json.load(fd), arguments_pb2.Arguments())
332 307
333 parser.set_defaults( 308 parser.set_defaults(
334 operational_args=arguments_pb2.Arguments(), 309 operational_args=arguments_pb2.Arguments(),
335 bare_command=False, # don't call postprocess_func, don't use package_deps 310 bare_command=False, # don't call postprocess_func, don't use package_deps
311 postprocess_func=lambda parser, args: None,
336 ) 312 )
337 313
338 parser.add_argument( 314 parser.add_argument(
339 '--operational-args-path', 315 '--operational-args-path',
340 dest='operational_args', 316 dest='operational_args',
341 type=operational_args_type, 317 type=operational_args_type,
342 help='The path to an operational Arguments file. If provided, this file ' 318 help='The path to an operational Arguments file. If provided, this file '
343 'must contain a JSONPB-encoded Arguments protobuf message, and will ' 319 'must contain a JSONPB-encoded Arguments protobuf message, and will '
344 'be integrated into the runtime parameters.') 320 'be integrated into the runtime parameters.')
345 321
(...skipping 12 matching lines...) Expand all
358 return post_process_args 334 return post_process_args
359 335
360 336
361 def main(): 337 def main():
362 parser = argparse.ArgumentParser( 338 parser = argparse.ArgumentParser(
363 description='Interact with the recipe system.') 339 description='Interact with the recipe system.')
364 340
365 common_postprocess_func = add_common_args(parser) 341 common_postprocess_func = add_common_args(parser)
366 342
367 from recipe_engine import fetch, lint_test, bundle, depgraph, autoroll 343 from recipe_engine import fetch, lint_test, bundle, depgraph, autoroll
368 from recipe_engine import remote, refs, doc 344 from recipe_engine import remote, refs, doc, test
369 to_add = [fetch, lint_test, bundle, depgraph, autoroll, remote, refs, doc] 345 to_add = [
346 fetch, lint_test, bundle, depgraph, autoroll, remote, refs, doc, test,
347 ]
370 348
371 subp = parser.add_subparsers() 349 subp = parser.add_subparsers()
372 for module in to_add: 350 for module in to_add:
373 module.add_subparser(subp) 351 module.add_subparser(subp)
374 352
375 test_p = subp.add_parser(
376 'test',
377 description='Generate or check expectations by simulation')
378 test_p.set_defaults(command='test')
379 test_p.add_argument('args', nargs=argparse.REMAINDER)
380
381 353
382 def properties_file_type(filename): 354 def properties_file_type(filename):
383 with (sys.stdin if filename == '-' else open(filename)) as f: 355 with (sys.stdin if filename == '-' else open(filename)) as f:
384 obj = json.load(f) 356 obj = json.load(f)
385 if not isinstance(obj, dict): 357 if not isinstance(obj, dict):
386 raise argparse.ArgumentTypeError( 358 raise argparse.ArgumentTypeError(
387 'must contain a JSON object, i.e. `{}`.') 359 'must contain a JSON object, i.e. `{}`.')
388 return obj 360 return obj
389 361
390 def parse_prop(prop): 362 def parse_prop(prop):
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 run_p.add_argument( 416 run_p.add_argument(
445 'props', 417 'props',
446 nargs=argparse.REMAINDER, 418 nargs=argparse.REMAINDER,
447 type=parse_prop, 419 type=parse_prop,
448 help='A list of property pairs; e.g. mastername=chromium.linux ' 420 help='A list of property pairs; e.g. mastername=chromium.linux '
449 'issue=12345. The property value will be decoded as JSON, but if ' 421 'issue=12345. The property value will be decoded as JSON, but if '
450 'this decoding fails the value will be interpreted as a string.') 422 'this decoding fails the value will be interpreted as a string.')
451 423
452 args = parser.parse_args() 424 args = parser.parse_args()
453 common_postprocess_func(parser, args) 425 common_postprocess_func(parser, args)
454 if hasattr(args, 'postprocess_func'): 426 args.postprocess_func(parser, args)
455 args.postprocess_func(parser, args)
456 427
457 # TODO(iannucci): We should always do logging.basicConfig() (probably with 428 # TODO(iannucci): We should always do logging.basicConfig() (probably with
458 # logging.WARNING), even if no verbose is passed. However we need to be 429 # logging.WARNING), even if no verbose is passed. However we need to be
459 # careful as this could cause issues with spurious/unexpected output. I think 430 # careful as this could cause issues with spurious/unexpected output. I think
460 # it's risky enough to do in a different CL. 431 # it's risky enough to do in a different CL.
461 432
462 if args.verbose > 0: 433 if args.verbose > 0:
463 logging.basicConfig() 434 logging.basicConfig()
464 logging.getLogger().setLevel(logging.INFO) 435 logging.getLogger().setLevel(logging.INFO)
465 if args.verbose > 1: 436 if args.verbose > 1:
466 logging.getLogger().setLevel(logging.DEBUG) 437 logging.getLogger().setLevel(logging.DEBUG)
467 438
468 # Auto-enable bootstrap for test command invocations (necessary to get recent
469 # enough version of coverage package), unless explicitly disabled.
470 if args.command == 'test' and args.use_bootstrap is None:
471 args.use_bootstrap = True
472
473 # If we're bootstrapping, construct our bootstrap environment. If we're 439 # If we're bootstrapping, construct our bootstrap environment. If we're
474 # using a custom deps path, install our enviornment there too. 440 # using a custom deps path, install our enviornment there too.
475 if args.use_bootstrap and not env.USING_BOOTSTRAP: 441 if args.use_bootstrap and not env.USING_BOOTSTRAP:
476 logging.debug('Bootstrapping recipe engine through vpython...') 442 logging.debug('Bootstrapping recipe engine through vpython...')
477 443
478 bootstrap_env = os.environ.copy() 444 bootstrap_env = os.environ.copy()
479 bootstrap_env[env.BOOTSTRAP_ENV_KEY] = '1' 445 bootstrap_env[env.BOOTSTRAP_ENV_KEY] = '1'
480 446
481 cmd = [ 447 cmd = [
482 sys.executable, 448 sys.executable,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
518 repo_root, config_file, allow_fetch=not args.no_fetch, 484 repo_root, config_file, allow_fetch=not args.no_fetch,
519 deps_path=args.deps_path, overrides=args.project_override) 485 deps_path=args.deps_path, overrides=args.project_override)
520 except subprocess.CalledProcessError: 486 except subprocess.CalledProcessError:
521 # A git checkout failed somewhere. Return 2, which is the sign that this is 487 # A git checkout failed somewhere. Return 2, which is the sign that this is
522 # an infra failure, rather than a test failure. 488 # an infra failure, rather than a test failure.
523 return 2 489 return 2
524 490
525 if hasattr(args, 'func'): 491 if hasattr(args, 'func'):
526 return args.func(package_deps, args) 492 return args.func(package_deps, args)
527 493
528 if args.command == 'test': 494 if args.command == 'run':
529 return test(config_file, package_deps, args)
530 elif args.command == 'run':
531 return run(config_file, package_deps, args) 495 return run(config_file, package_deps, args)
532 else: 496 else:
533 print """Dear sir or madam, 497 print """Dear sir or madam,
534 It has come to my attention that a quite impossible condition has come 498 It has come to my attention that a quite impossible condition has come
535 to pass in the specification you have issued a request for us to fulfill. 499 to pass in the specification you have issued a request for us to fulfill.
536 It is with a heavy heart that I inform you that, at the present juncture, 500 It is with a heavy heart that I inform you that, at the present juncture,
537 there is no conceivable next action to be taken upon your request, and as 501 there is no conceivable next action to be taken upon your request, and as
538 such, we have decided to abort the request with a nonzero status code. We 502 such, we have decided to abort the request with a nonzero status code. We
539 hope that your larger goals have not been put at risk due to this 503 hope that your larger goals have not been put at risk due to this
540 unfortunate circumstance, and wish you the best in deciding the next action 504 unfortunate circumstance, and wish you the best in deciding the next action
(...skipping 20 matching lines...) Expand all
561 525
562 if not isinstance(ret, int): 526 if not isinstance(ret, int):
563 if ret is None: 527 if ret is None:
564 ret = 0 528 ret = 0
565 else: 529 else:
566 print >> sys.stderr, ret 530 print >> sys.stderr, ret
567 ret = 1 531 ret = 1
568 sys.stdout.flush() 532 sys.stdout.flush()
569 sys.stderr.flush() 533 sys.stderr.flush()
570 os._exit(ret) 534 os._exit(ret)
OLDNEW
« no previous file with comments | « recipe_engine/test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698