| 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 |