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 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 def _op_properties_to_dict(pmap): | 337 def _op_properties_to_dict(pmap): |
338 """Creates a properties dictionary from an arguments_pb2.PropertyMap entry. | 338 """Creates a properties dictionary from an arguments_pb2.PropertyMap entry. |
339 | 339 |
340 Args: | 340 Args: |
341 pmap (arguments_pb2.PropertyMap): Map to convert to dictionary form. | 341 pmap (arguments_pb2.PropertyMap): Map to convert to dictionary form. |
342 Returns (dict): A dictionary derived from the properties in "pmap". | 342 Returns (dict): A dictionary derived from the properties in "pmap". |
343 """ | 343 """ |
344 return dict((k, _op_property_value(pmap[k])) for k in pmap) | 344 return dict((k, _op_property_value(pmap[k])) for k in pmap) |
345 | 345 |
346 | 346 |
347 def main(): | 347 def add_common_args(parser): |
348 parser = argparse.ArgumentParser( | 348 from recipe_engine import package_io |
349 description='Interact with the recipe system.') | 349 |
| 350 def package_type(value): |
| 351 if not os.path.isfile(value): |
| 352 raise argparse.ArgumentTypeError( |
| 353 'Given recipes config file %r does not exist.' % (value,)) |
| 354 return package_io.PackageFile(value) |
350 | 355 |
351 parser.add_argument( | 356 parser.add_argument( |
352 '--package', | 357 '--package', |
353 type=os.path.abspath, | 358 type=package_type, |
354 help='Path to recipes.cfg of the recipe package to operate on' | 359 help='Path to recipes.cfg of the recipe package to operate on' |
355 ', usually in infra/config/recipes.cfg') | 360 ', usually in infra/config/recipes.cfg') |
356 parser.add_argument( | 361 parser.add_argument( |
357 '--deps-path', | 362 '--deps-path', |
358 type=os.path.abspath, | 363 type=os.path.abspath, |
359 help='Path where recipe engine dependencies will be extracted. Specify ' | 364 help='Path where recipe engine dependencies will be extracted. Specify ' |
360 '"-" to use a temporary directory for deps, which will be cleaned ' | 365 '"-" to use a temporary directory for deps, which will be cleaned ' |
361 'up on exit.') | 366 'up on exit.') |
362 parser.add_argument( | 367 parser.add_argument( |
363 '--verbose', '-v', action='count', | 368 '--verbose', '-v', action='count', |
(...skipping 14 matching lines...) Expand all Loading... |
378 parser.add_argument( | 383 parser.add_argument( |
379 '--disable-bootstrap', action='store_false', dest='use_bootstrap', | 384 '--disable-bootstrap', action='store_false', dest='use_bootstrap', |
380 help='Disables bootstrap (see --use-bootstrap)') | 385 help='Disables bootstrap (see --use-bootstrap)') |
381 parser.add_argument( | 386 parser.add_argument( |
382 '--operational-args-path', action='store', | 387 '--operational-args-path', action='store', |
383 type=os.path.abspath, | 388 type=os.path.abspath, |
384 help='The path to an operational Arguments file. If provided, this file ' | 389 help='The path to an operational Arguments file. If provided, this file ' |
385 'must contain a JSONPB-encoded Arguments protobuf message, and will ' | 390 'must contain a JSONPB-encoded Arguments protobuf message, and will ' |
386 'be integrated into the runtime parameters.') | 391 'be integrated into the runtime parameters.') |
387 | 392 |
| 393 |
| 394 def post_process_common_args(parser, args): |
| 395 if args.command == "remote": |
| 396 # 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 |
| 398 # repo and then simply remove the remote subcommand entirely. |
| 399 return |
| 400 |
| 401 if not args.package: |
| 402 parser.error('%s requires --package' % args.command) |
| 403 |
| 404 |
| 405 def main(): |
| 406 parser = argparse.ArgumentParser( |
| 407 description='Interact with the recipe system.') |
| 408 |
| 409 add_common_args(parser) |
| 410 |
388 subp = parser.add_subparsers() | 411 subp = parser.add_subparsers() |
389 | 412 |
390 fetch_p = subp.add_parser( | 413 fetch_p = subp.add_parser( |
391 'fetch', | 414 'fetch', |
392 description='Fetch and update dependencies.') | 415 description='Fetch and update dependencies.') |
393 fetch_p.set_defaults(command='fetch') | 416 fetch_p.set_defaults(command='fetch') |
394 | 417 |
395 test_p = subp.add_parser( | 418 test_p = subp.add_parser( |
396 'test', | 419 'test', |
397 description='Generate or check expectations by simulation') | 420 description='Generate or check expectations by simulation') |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 'doc', | 587 'doc', |
565 description='List all known modules reachable from the current package, ' | 588 description='List all known modules reachable from the current package, ' |
566 'with their documentation') | 589 'with their documentation') |
567 doc_p.add_argument('recipe', nargs='?', | 590 doc_p.add_argument('recipe', nargs='?', |
568 help='Restrict documentation to this recipe') | 591 help='Restrict documentation to this recipe') |
569 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, | 592 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, |
570 help='Output this kind of documentation') | 593 help='Output this kind of documentation') |
571 doc_p.set_defaults(command='doc') | 594 doc_p.set_defaults(command='doc') |
572 | 595 |
573 args = parser.parse_args() | 596 args = parser.parse_args() |
| 597 post_process_common_args(parser, args) |
574 | 598 |
575 # Load/parse operational arguments. | 599 # Load/parse operational arguments. |
576 op_args = arguments_pb2.Arguments() | 600 op_args = arguments_pb2.Arguments() |
577 if args.operational_args_path is not None: | 601 if args.operational_args_path is not None: |
578 with open(args.operational_args_path) as fd: | 602 with open(args.operational_args_path) as fd: |
579 data = fd.read() | 603 data = fd.read() |
580 jsonpb.Parse(data, op_args) | 604 jsonpb.Parse(data, op_args) |
581 | 605 |
582 # TODO(iannucci): We should always do logging.basicConfig() (probably with | 606 # TODO(iannucci): We should always do logging.basicConfig() (probably with |
583 # logging.WARNING), even if no verbose is passed. However we need to be | 607 # logging.WARNING), even if no verbose is passed. However we need to be |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 | 691 |
668 | 692 |
669 def _real_main(args, op_args): | 693 def _real_main(args, op_args): |
670 from recipe_engine import package, package_io | 694 from recipe_engine import package, package_io |
671 | 695 |
672 # Commands which do not require config_file, package_deps, and other objects | 696 # Commands which do not require config_file, package_deps, and other objects |
673 # initialized later. | 697 # initialized later. |
674 if args.command == 'remote': | 698 if args.command == 'remote': |
675 return remote(args) | 699 return remote(args) |
676 | 700 |
677 assert args.package, 'No recipe config (--package) given.' | 701 config_file = args.package |
678 assert os.path.isfile(args.package), ( | 702 repo_root = package.InfraRepoConfig().from_recipes_cfg(args.package.path) |
679 'Given recipes config file %r does not exist.' % (args.package,)) | |
680 repo_root = package.InfraRepoConfig().from_recipes_cfg(args.package) | |
681 config_file = package_io.PackageFile(args.package) | |
682 | 703 |
683 try: | 704 try: |
684 # TODO(phajdan.jr): gracefully handle inconsistent deps when rolling. | 705 # TODO(phajdan.jr): gracefully handle inconsistent deps when rolling. |
685 # This fails if the starting point does not have consistent dependency | 706 # This fails if the starting point does not have consistent dependency |
686 # graph. When performing an automated roll, it'd make sense to attempt | 707 # graph. When performing an automated roll, it'd make sense to attempt |
687 # to automatically find a consistent state, rather than bailing out. | 708 # to automatically find a consistent state, rather than bailing out. |
688 # Especially that only some subcommands refer to package_deps. | 709 # Especially that only some subcommands refer to package_deps. |
689 package_deps = package.PackageDeps.create( | 710 package_deps = package.PackageDeps.create( |
690 repo_root, config_file, allow_fetch=not args.no_fetch, | 711 repo_root, config_file, allow_fetch=not args.no_fetch, |
691 deps_path=args.deps_path, overrides=args.project_override) | 712 deps_path=args.deps_path, overrides=args.project_override) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
746 | 767 |
747 if not isinstance(ret, int): | 768 if not isinstance(ret, int): |
748 if ret is None: | 769 if ret is None: |
749 ret = 0 | 770 ret = 0 |
750 else: | 771 else: |
751 print >> sys.stderr, ret | 772 print >> sys.stderr, ret |
752 ret = 1 | 773 ret = 1 |
753 sys.stdout.flush() | 774 sys.stdout.flush() |
754 sys.stderr.flush() | 775 sys.stderr.flush() |
755 os._exit(ret) | 776 os._exit(ret) |
OLD | NEW |