OLD | NEW |
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 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 | 234 |
235 if v.get(project_id): | 235 if v.get(project_id): |
236 raise ValueError('An override is already defined for [%s] (%s)' % ( | 236 raise ValueError('An override is already defined for [%s] (%s)' % ( |
237 project_id, v[project_id])) | 237 project_id, v[project_id])) |
238 path = os.path.abspath(os.path.expanduser(path)) | 238 path = os.path.abspath(os.path.expanduser(path)) |
239 if not os.path.isdir(path): | 239 if not os.path.isdir(path): |
240 raise ValueError('Override path [%s] is not a directory' % (path,)) | 240 raise ValueError('Override path [%s] is not a directory' % (path,)) |
241 v[project_id] = path | 241 v[project_id] = path |
242 | 242 |
243 | 243 |
244 def doc(config_file, package_deps, args): | |
245 from recipe_engine import doc | |
246 from recipe_engine import loader | |
247 | |
248 universe = loader.RecipeUniverse(package_deps, config_file) | |
249 universe_view = loader.UniverseView(universe, package_deps.root_package) | |
250 | |
251 doc.main(universe_view, args.recipe, args.kind) | |
252 | |
253 | |
254 # Map of arguments_pb2.Property "value" oneof conversion functions. | 244 # Map of arguments_pb2.Property "value" oneof conversion functions. |
255 # | 245 # |
256 # The fields here should be kept in sync with the "value" oneof field names in | 246 # The fields here should be kept in sync with the "value" oneof field names in |
257 # the arguments_pb2.Arguments.Property protobuf message. | 247 # the arguments_pb2.Arguments.Property protobuf message. |
258 _OP_PROPERTY_CONV = { | 248 _OP_PROPERTY_CONV = { |
259 's': lambda prop: prop.s, | 249 's': lambda prop: prop.s, |
260 'int': lambda prop: prop.int, | 250 'int': lambda prop: prop.int, |
261 'uint': lambda prop: prop.uint, | 251 'uint': lambda prop: prop.uint, |
262 'd': lambda prop: prop.d, | 252 'd': lambda prop: prop.d, |
263 'b': lambda prop: prop.b, | 253 'b': lambda prop: prop.b, |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 return post_process_args | 354 return post_process_args |
365 | 355 |
366 | 356 |
367 def main(): | 357 def main(): |
368 parser = argparse.ArgumentParser( | 358 parser = argparse.ArgumentParser( |
369 description='Interact with the recipe system.') | 359 description='Interact with the recipe system.') |
370 | 360 |
371 common_postprocess_func = add_common_args(parser) | 361 common_postprocess_func = add_common_args(parser) |
372 | 362 |
373 from recipe_engine import fetch, lint_test, bundle, depgraph, autoroll | 363 from recipe_engine import fetch, lint_test, bundle, depgraph, autoroll |
374 from recipe_engine import remote, refs | 364 from recipe_engine import remote, refs, doc |
375 to_add = [fetch, lint_test, bundle, depgraph, autoroll, remote, refs] | 365 to_add = [fetch, lint_test, bundle, depgraph, autoroll, remote, refs, doc] |
376 | 366 |
377 subp = parser.add_subparsers() | 367 subp = parser.add_subparsers() |
378 for module in to_add: | 368 for module in to_add: |
379 module.add_subparser(subp) | 369 module.add_subparser(subp) |
380 | 370 |
381 test_p = subp.add_parser( | 371 test_p = subp.add_parser( |
382 'test', | 372 'test', |
383 description='Generate or check expectations by simulation') | 373 description='Generate or check expectations by simulation') |
384 test_p.set_defaults(command='test') | 374 test_p.set_defaults(command='test') |
385 test_p.add_argument('args', nargs=argparse.REMAINDER) | 375 test_p.add_argument('args', nargs=argparse.REMAINDER) |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 'recipe', | 438 'recipe', |
449 help='The recipe to execute') | 439 help='The recipe to execute') |
450 run_p.add_argument( | 440 run_p.add_argument( |
451 'props', | 441 'props', |
452 nargs=argparse.REMAINDER, | 442 nargs=argparse.REMAINDER, |
453 type=parse_prop, | 443 type=parse_prop, |
454 help='A list of property pairs; e.g. mastername=chromium.linux ' | 444 help='A list of property pairs; e.g. mastername=chromium.linux ' |
455 'issue=12345. The property value will be decoded as JSON, but if ' | 445 'issue=12345. The property value will be decoded as JSON, but if ' |
456 'this decoding fails the value will be interpreted as a string.') | 446 'this decoding fails the value will be interpreted as a string.') |
457 | 447 |
458 doc_kinds=('binarypb', 'jsonpb', 'textpb', 'markdown(github)', | |
459 'markdown(gitiles)') | |
460 doc_p = subp.add_parser( | |
461 'doc', | |
462 description='List all known modules reachable from the current package, ' | |
463 'with their documentation') | |
464 doc_p.add_argument('recipe', nargs='?', | |
465 help='Restrict documentation to this recipe') | |
466 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, | |
467 help='Output this kind of documentation') | |
468 doc_p.set_defaults(command='doc') | |
469 | |
470 args = parser.parse_args() | 448 args = parser.parse_args() |
471 common_postprocess_func(parser, args) | 449 common_postprocess_func(parser, args) |
472 if hasattr(args, 'postprocess_func'): | 450 if hasattr(args, 'postprocess_func'): |
473 args.postprocess_func(parser, args) | 451 args.postprocess_func(parser, args) |
474 | 452 |
475 # TODO(iannucci): We should always do logging.basicConfig() (probably with | 453 # TODO(iannucci): We should always do logging.basicConfig() (probably with |
476 # logging.WARNING), even if no verbose is passed. However we need to be | 454 # logging.WARNING), even if no verbose is passed. However we need to be |
477 # careful as this could cause issues with spurious/unexpected output. I think | 455 # careful as this could cause issues with spurious/unexpected output. I think |
478 # it's risky enough to do in a different CL. | 456 # it's risky enough to do in a different CL. |
479 | 457 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 # an infra failure, rather than a test failure. | 560 # an infra failure, rather than a test failure. |
583 return 2 | 561 return 2 |
584 | 562 |
585 if hasattr(args, 'func'): | 563 if hasattr(args, 'func'): |
586 return args.func(package_deps, args) | 564 return args.func(package_deps, args) |
587 | 565 |
588 if args.command == 'test': | 566 if args.command == 'test': |
589 return test(config_file, package_deps, args) | 567 return test(config_file, package_deps, args) |
590 elif args.command == 'run': | 568 elif args.command == 'run': |
591 return run(config_file, package_deps, args) | 569 return run(config_file, package_deps, args) |
592 elif args.command == 'doc': | |
593 return doc(config_file, package_deps, args) | |
594 else: | 570 else: |
595 print """Dear sir or madam, | 571 print """Dear sir or madam, |
596 It has come to my attention that a quite impossible condition has come | 572 It has come to my attention that a quite impossible condition has come |
597 to pass in the specification you have issued a request for us to fulfill. | 573 to pass in the specification you have issued a request for us to fulfill. |
598 It is with a heavy heart that I inform you that, at the present juncture, | 574 It is with a heavy heart that I inform you that, at the present juncture, |
599 there is no conceivable next action to be taken upon your request, and as | 575 there is no conceivable next action to be taken upon your request, and as |
600 such, we have decided to abort the request with a nonzero status code. We | 576 such, we have decided to abort the request with a nonzero status code. We |
601 hope that your larger goals have not been put at risk due to this | 577 hope that your larger goals have not been put at risk due to this |
602 unfortunate circumstance, and wish you the best in deciding the next action | 578 unfortunate circumstance, and wish you the best in deciding the next action |
603 in your venture and larger life. | 579 in your venture and larger life. |
(...skipping 19 matching lines...) Expand all Loading... |
623 | 599 |
624 if not isinstance(ret, int): | 600 if not isinstance(ret, int): |
625 if ret is None: | 601 if ret is None: |
626 ret = 0 | 602 ret = 0 |
627 else: | 603 else: |
628 print >> sys.stderr, ret | 604 print >> sys.stderr, ret |
629 ret = 1 | 605 ret = 1 |
630 sys.stdout.flush() | 606 sys.stdout.flush() |
631 sys.stderr.flush() | 607 sys.stderr.flush() |
632 os._exit(ret) | 608 os._exit(ret) |
OLD | NEW |