Chromium Code Reviews| 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 universe_view = loader.UniverseView(universe, package_deps.root_package) | 52 universe_view = loader.UniverseView(universe, package_deps.root_package) |
| 53 | 53 |
| 54 # Prevent flakiness caused by stale pyc files. | 54 # Prevent flakiness caused by stale pyc files. |
| 55 package.cleanup_pyc(package_deps.root_package.recipes_dir) | 55 package.cleanup_pyc(package_deps.root_package.recipes_dir) |
| 56 | 56 |
| 57 return test.main( | 57 return test.main( |
| 58 universe_view, raw_args=args.args, | 58 universe_view, raw_args=args.args, |
| 59 engine_flags=args.operational_args.engine_flags) | 59 engine_flags=args.operational_args.engine_flags) |
| 60 | 60 |
| 61 | 61 |
| 62 def lint(config_file, package_deps, args): | |
| 63 from recipe_engine import lint_test | |
| 64 from recipe_engine import loader | |
| 65 | |
| 66 universe = loader.RecipeUniverse(package_deps, config_file) | |
| 67 universe_view = loader.UniverseView(universe, package_deps.root_package) | |
| 68 | |
| 69 lint_test.main(universe_view, args.whitelist or []) | |
| 70 | |
| 71 | |
| 72 def bundle(config_file, package_deps, args): | |
| 73 from recipe_engine import bundle | |
| 74 from recipe_engine import loader | |
| 75 | |
| 76 universe = loader.RecipeUniverse(package_deps, config_file) | |
| 77 | |
| 78 bundle.main(package_deps.root_package, universe, args.destination) | |
| 79 | |
| 80 | |
| 81 def handle_recipe_return(recipe_result, result_filename, stream_engine, | 62 def handle_recipe_return(recipe_result, result_filename, stream_engine, |
| 82 engine_flags): | 63 engine_flags): |
| 83 if engine_flags and engine_flags.use_result_proto: | 64 if engine_flags and engine_flags.use_result_proto: |
| 84 return new_handle_recipe_return( | 65 return new_handle_recipe_return( |
| 85 recipe_result, result_filename, stream_engine) | 66 recipe_result, result_filename, stream_engine) |
| 86 | 67 |
| 87 if 'recipe_result' in recipe_result.result: | 68 if 'recipe_result' in recipe_result.result: |
| 88 result_string = json.dumps( | 69 result_string = json.dumps( |
| 89 recipe_result.result['recipe_result'], indent=2) | 70 recipe_result.result['recipe_result'], indent=2) |
| 90 if result_filename: | 71 if result_filename: |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 | 143 |
| 163 def get_properties_from_operational_args(op_args): | 144 def get_properties_from_operational_args(op_args): |
| 164 if not op_args.properties.property: | 145 if not op_args.properties.property: |
| 165 return None | 146 return None |
| 166 return _op_properties_to_dict(op_args.properties.property) | 147 return _op_properties_to_dict(op_args.properties.property) |
| 167 | 148 |
| 168 op_args = args.operational_args | 149 op_args = args.operational_args |
| 169 op_properties = get_properties_from_operational_args(op_args) | 150 op_properties = get_properties_from_operational_args(op_args) |
| 170 if args.properties and op_properties: | 151 if args.properties and op_properties: |
| 171 raise ValueError( | 152 raise ValueError( |
| 172 "Got operational args properties as well as CLI properties.") | 153 'Got operational args properties as well as CLI properties.') |
| 173 | 154 |
| 174 properties = op_properties | 155 properties = op_properties |
| 175 if not properties: | 156 if not properties: |
| 176 properties = args.properties | 157 properties = args.properties |
| 177 | 158 |
| 178 properties['recipe'] = args.recipe | 159 properties['recipe'] = args.recipe |
| 179 | 160 |
| 180 properties = recipe_util.strip_unicode(properties) | 161 properties = recipe_util.strip_unicode(properties) |
| 181 | 162 |
| 182 os.environ['PYTHONUNBUFFERED'] = '1' | 163 os.environ['PYTHONUNBUFFERED'] = '1' |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 print >> sys.stderr, '--verbose-json passed without --output-json' | 233 print >> sys.stderr, '--verbose-json passed without --output-json' |
| 253 return 1 | 234 return 1 |
| 254 | 235 |
| 255 return autoroll.main(args, repo_root, config_file) | 236 return autoroll.main(args, repo_root, config_file) |
| 256 | 237 |
| 257 | 238 |
| 258 class ProjectOverrideAction(argparse.Action): | 239 class ProjectOverrideAction(argparse.Action): |
| 259 def __call__(self, parser, namespace, values, option_string=None): | 240 def __call__(self, parser, namespace, values, option_string=None): |
| 260 p = values.split('=', 2) | 241 p = values.split('=', 2) |
| 261 if len(p) != 2: | 242 if len(p) != 2: |
| 262 raise ValueError("Override must have the form: repo=path") | 243 raise ValueError('Override must have the form: repo=path') |
| 263 project_id, path = p | 244 project_id, path = p |
| 264 | 245 |
| 265 v = getattr(namespace, self.dest, None) | 246 v = getattr(namespace, self.dest, None) |
| 266 if v is None: | 247 if v is None: |
| 267 v = {} | 248 v = {} |
| 268 setattr(namespace, self.dest, v) | 249 setattr(namespace, self.dest, v) |
| 269 | 250 |
| 270 if v.get(project_id): | 251 if v.get(project_id): |
| 271 raise ValueError("An override is already defined for [%s] (%s)" % ( | 252 raise ValueError('An override is already defined for [%s] (%s)' % ( |
| 272 project_id, v[project_id])) | 253 project_id, v[project_id])) |
| 273 path = os.path.abspath(os.path.expanduser(path)) | 254 path = os.path.abspath(os.path.expanduser(path)) |
| 274 if not os.path.isdir(path): | 255 if not os.path.isdir(path): |
| 275 raise ValueError("Override path [%s] is not a directory" % (path,)) | 256 raise ValueError('Override path [%s] is not a directory' % (path,)) |
| 276 v[project_id] = path | 257 v[project_id] = path |
| 277 | 258 |
| 278 | 259 |
| 279 def depgraph(config_file, package_deps, args): | 260 def depgraph(config_file, package_deps, args): |
| 280 from recipe_engine import depgraph | 261 from recipe_engine import depgraph |
| 281 from recipe_engine import loader | 262 from recipe_engine import loader |
| 282 | 263 |
| 283 universe = loader.RecipeUniverse(package_deps, config_file) | 264 universe = loader.RecipeUniverse(package_deps, config_file) |
| 284 | 265 |
| 285 depgraph.main(universe, package_deps.root_package, | 266 depgraph.main(universe, package_deps.root_package, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 320 'list': lambda prop: [_op_property_value(v) for v in prop.list.property], | 301 'list': lambda prop: [_op_property_value(v) for v in prop.list.property], |
| 321 } | 302 } |
| 322 | 303 |
| 323 def _op_property_value(prop): | 304 def _op_property_value(prop): |
| 324 """Returns the Python-converted value of an arguments_pb2.Property. | 305 """Returns the Python-converted value of an arguments_pb2.Property. |
| 325 | 306 |
| 326 Args: | 307 Args: |
| 327 prop (arguments_pb2.Property): property to convert. | 308 prop (arguments_pb2.Property): property to convert. |
| 328 Returns: The converted value. | 309 Returns: The converted value. |
| 329 Raises: | 310 Raises: |
| 330 ValueError: If "prop" is incomplete or invalid. | 311 ValueError: If 'prop' is incomplete or invalid. |
| 331 """ | 312 """ |
| 332 typ = prop.WhichOneof('value') | 313 typ = prop.WhichOneof('value') |
| 333 conv = _OP_PROPERTY_CONV.get(typ) | 314 conv = _OP_PROPERTY_CONV.get(typ) |
| 334 if not conv: | 315 if not conv: |
| 335 raise ValueError('Unknown property field [%s]' % (typ,)) | 316 raise ValueError('Unknown property field [%s]' % (typ,)) |
| 336 return conv(prop) | 317 return conv(prop) |
| 337 | 318 |
| 338 | 319 |
| 339 def _op_properties_to_dict(pmap): | 320 def _op_properties_to_dict(pmap): |
| 340 """Creates a properties dictionary from an arguments_pb2.PropertyMap entry. | 321 """Creates a properties dictionary from an arguments_pb2.PropertyMap entry. |
| 341 | 322 |
| 342 Args: | 323 Args: |
| 343 pmap (arguments_pb2.PropertyMap): Map to convert to dictionary form. | 324 pmap (arguments_pb2.PropertyMap): Map to convert to dictionary form. |
| 344 Returns (dict): A dictionary derived from the properties in "pmap". | 325 Returns (dict): A dictionary derived from the properties in 'pmap'. |
| 345 """ | 326 """ |
| 346 return dict((k, _op_property_value(pmap[k])) for k in pmap) | 327 return dict((k, _op_property_value(pmap[k])) for k in pmap) |
| 347 | 328 |
| 348 | 329 |
| 349 def add_common_args(parser): | 330 def add_common_args(parser): |
| 350 from recipe_engine import package_io | 331 from recipe_engine import package_io |
| 351 | 332 |
| 352 def package_type(value): | 333 def package_type(value): |
| 353 if not os.path.isfile(value): | 334 if not os.path.isfile(value): |
| 354 raise argparse.ArgumentTypeError( | 335 raise argparse.ArgumentTypeError( |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 370 '--verbose', '-v', action='count', | 351 '--verbose', '-v', action='count', |
| 371 help='Increase logging verboisty') | 352 help='Increase logging verboisty') |
| 372 # TODO(phajdan.jr): Figure out if we need --no-fetch; remove if not. | 353 # TODO(phajdan.jr): Figure out if we need --no-fetch; remove if not. |
| 373 parser.add_argument( | 354 parser.add_argument( |
| 374 '--no-fetch', action='store_true', | 355 '--no-fetch', action='store_true', |
| 375 help='Disable automatic fetching') | 356 help='Disable automatic fetching') |
| 376 parser.add_argument('-O', '--project-override', metavar='ID=PATH', | 357 parser.add_argument('-O', '--project-override', metavar='ID=PATH', |
| 377 action=ProjectOverrideAction, | 358 action=ProjectOverrideAction, |
| 378 help='Override a project repository path with a local one.') | 359 help='Override a project repository path with a local one.') |
| 379 parser.add_argument( | 360 parser.add_argument( |
| 380 # Use "None" as default so that we can recognize when none of the | 361 # Use 'None' as default so that we can recognize when none of the |
| 381 # bootstrap options were passed. | 362 # bootstrap options were passed. |
| 382 '--use-bootstrap', action='store_true', default=None, | 363 '--use-bootstrap', action='store_true', default=None, |
| 383 help='Use bootstrap/bootstrap.py to create a isolated python virtualenv' | 364 help='Use bootstrap/bootstrap.py to create a isolated python virtualenv' |
| 384 ' with required python dependencies.') | 365 ' with required python dependencies.') |
| 385 parser.add_argument( | 366 parser.add_argument( |
| 386 '--disable-bootstrap', action='store_false', dest='use_bootstrap', | 367 '--disable-bootstrap', action='store_false', dest='use_bootstrap', |
| 387 help='Disables bootstrap (see --use-bootstrap)') | 368 help='Disables bootstrap (see --use-bootstrap)') |
| 388 | 369 |
| 389 def operational_args_type(value): | 370 def operational_args_type(value): |
| 390 with open(value) as fd: | 371 with open(value) as fd: |
| 391 return jsonpb.ParseDict(json.load(fd), arguments_pb2.Arguments()) | 372 return jsonpb.ParseDict(json.load(fd), arguments_pb2.Arguments()) |
| 392 | 373 |
| 393 parser.set_defaults(operational_args=arguments_pb2.Arguments()) | 374 parser.set_defaults(operational_args=arguments_pb2.Arguments()) |
| 394 | 375 |
| 395 parser.add_argument( | 376 parser.add_argument( |
| 396 '--operational-args-path', | 377 '--operational-args-path', |
| 397 dest='operational_args', | 378 dest='operational_args', |
| 398 type=operational_args_type, | 379 type=operational_args_type, |
| 399 help='The path to an operational Arguments file. If provided, this file ' | 380 help='The path to an operational Arguments file. If provided, this file ' |
| 400 'must contain a JSONPB-encoded Arguments protobuf message, and will ' | 381 'must contain a JSONPB-encoded Arguments protobuf message, and will ' |
| 401 'be integrated into the runtime parameters.') | 382 'be integrated into the runtime parameters.') |
| 402 | 383 |
| 384 def post_process_args(parser, args): | |
| 385 if args.command == 'remote': | |
| 386 # TODO(iannucci): this is a hack; remote doesn't behave like ANY other | |
| 387 # commands. A way to solve this will be to allow --package to take | |
| 388 # a remote repo and then simply remove the remote subcommand entirely. | |
| 389 return | |
| 403 | 390 |
| 404 def post_process_common_args(parser, args): | 391 if not args.package: |
| 405 if args.command == "remote": | 392 parser.error('%s requires --package' % args.command) |
| 406 # TODO(iannucci): this is a hack; remote doesn't behave like ANY other | |
| 407 # commands. A way to solve this will be to allow --package to take a remote | |
| 408 # repo and then simply remove the remote subcommand entirely. | |
| 409 return | |
| 410 | 393 |
| 411 if not args.package: | 394 return post_process_args |
| 412 parser.error('%s requires --package' % args.command) | |
| 413 | 395 |
| 414 | 396 |
| 415 def main(): | 397 def main(): |
| 416 parser = argparse.ArgumentParser( | 398 parser = argparse.ArgumentParser( |
| 417 description='Interact with the recipe system.') | 399 description='Interact with the recipe system.') |
| 418 | 400 |
| 419 add_common_args(parser) | 401 common_postprocess_func = add_common_args(parser) |
| 402 | |
| 403 from recipe_engine import fetch, lint_test, bundle | |
| 404 to_add = [fetch, lint_test, bundle] | |
| 420 | 405 |
| 421 subp = parser.add_subparsers() | 406 subp = parser.add_subparsers() |
| 422 | 407 for module in to_add: |
| 423 fetch_p = subp.add_parser( | 408 module.add_subparser(subp) |
| 424 'fetch', | |
| 425 description='Fetch and update dependencies.') | |
| 426 fetch_p.set_defaults(command='fetch') | |
| 427 | 409 |
| 428 test_p = subp.add_parser( | 410 test_p = subp.add_parser( |
| 429 'test', | 411 'test', |
| 430 description='Generate or check expectations by simulation') | 412 description='Generate or check expectations by simulation') |
| 431 test_p.set_defaults(command='test') | 413 test_p.set_defaults(command='test') |
| 432 test_p.add_argument('args', nargs=argparse.REMAINDER) | 414 test_p.add_argument('args', nargs=argparse.REMAINDER) |
| 433 | 415 |
| 434 lint_p = subp.add_parser( | |
| 435 'lint', | |
| 436 description='Check recipes for stylistic and hygenic issues') | |
| 437 lint_p.set_defaults(command='lint') | |
| 438 | |
| 439 lint_p.add_argument( | |
| 440 '--whitelist', '-w', action='append', | |
| 441 help='A regexp matching module names to add to the default whitelist. ' | |
| 442 'Use multiple times to add multiple patterns,') | |
| 443 | |
| 444 bundle_p = subp.add_parser( | |
| 445 'bundle', | |
| 446 description=( | |
| 447 'Create a hermetically runnable recipe bundle. This captures the result' | |
| 448 ' of all network operations the recipe_engine might normally do to' | |
| 449 ' bootstrap itself.')) | |
| 450 bundle_p.set_defaults(command='bundle') | |
| 451 bundle_p.add_argument( | |
| 452 '--destination', default='./bundle', | |
| 453 type=os.path.abspath, | |
| 454 help='The directory of where to put the bundle (default: %(default)r).') | |
| 455 | 416 |
| 456 def properties_file_type(filename): | 417 def properties_file_type(filename): |
| 457 with (sys.stdin if filename == '-' else open(filename)) as f: | 418 with (sys.stdin if filename == '-' else open(filename)) as f: |
| 458 obj = json.load(f) | 419 obj = json.load(f) |
| 459 if not isinstance(obj, dict): | 420 if not isinstance(obj, dict): |
| 460 raise argparse.ArgumentTypeError( | 421 raise argparse.ArgumentTypeError( |
| 461 "must contain a JSON object, i.e. `{}`.") | 422 'must contain a JSON object, i.e. `{}`.') |
| 462 return obj | 423 return obj |
| 463 | 424 |
| 464 def parse_prop(prop): | 425 def parse_prop(prop): |
| 465 key, val = prop.split('=', 1) | 426 key, val = prop.split('=', 1) |
| 466 try: | 427 try: |
| 467 val = json.loads(val) | 428 val = json.loads(val) |
| 468 except (ValueError, SyntaxError): | 429 except (ValueError, SyntaxError): |
| 469 pass # If a value couldn't be evaluated, keep the string version | 430 pass # If a value couldn't be evaluated, keep the string version |
| 470 return {key: val} | 431 return {key: val} |
| 471 | 432 |
| 472 def properties_type(value): | 433 def properties_type(value): |
| 473 obj = json.loads(value) | 434 obj = json.loads(value) |
| 474 if not isinstance(obj, dict): | 435 if not isinstance(obj, dict): |
| 475 raise argparse.ArgumentTypeError("must contain a JSON object, i.e. `{}`.") | 436 raise argparse.ArgumentTypeError('must contain a JSON object, i.e. `{}`.') |
| 476 return obj | 437 return obj |
| 477 | 438 |
| 478 run_p = subp.add_parser( | 439 run_p = subp.add_parser( |
| 479 'run', | 440 'run', |
| 480 description='Run a recipe locally') | 441 description='Run a recipe locally') |
| 481 run_p.set_defaults(command='run', properties={}) | 442 run_p.set_defaults(command='run', properties={}) |
| 482 | 443 |
| 483 run_p.add_argument( | 444 run_p.add_argument( |
| 484 '--workdir', | 445 '--workdir', |
| 485 type=os.path.abspath, | 446 type=os.path.abspath, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 516 'recipe', | 477 'recipe', |
| 517 help='The recipe to execute') | 478 help='The recipe to execute') |
| 518 run_p.add_argument( | 479 run_p.add_argument( |
| 519 'props', | 480 'props', |
| 520 nargs=argparse.REMAINDER, | 481 nargs=argparse.REMAINDER, |
| 521 type=parse_prop, | 482 type=parse_prop, |
| 522 help='A list of property pairs; e.g. mastername=chromium.linux ' | 483 help='A list of property pairs; e.g. mastername=chromium.linux ' |
| 523 'issue=12345. The property value will be decoded as JSON, but if ' | 484 'issue=12345. The property value will be decoded as JSON, but if ' |
| 524 'this decoding fails the value will be interpreted as a string.') | 485 'this decoding fails the value will be interpreted as a string.') |
| 525 | 486 |
| 487 | |
| 526 remote_p = subp.add_parser( | 488 remote_p = subp.add_parser( |
| 527 'remote', | 489 'remote', |
| 528 description='Invoke a recipe command from specified repo and revision') | 490 description='Invoke a recipe command from specified repo and revision') |
| 529 remote_p.set_defaults(command='remote') | 491 remote_p.set_defaults(command='remote') |
| 530 remote_p.add_argument( | 492 remote_p.add_argument( |
| 531 '--repository', required=True, | 493 '--repository', required=True, |
| 532 help='URL of a git repository to fetch') | 494 help='URL of a git repository to fetch') |
| 533 remote_p.add_argument( | 495 remote_p.add_argument( |
| 534 '--revision', | 496 '--revision', |
| 535 help=( | 497 help=( |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 597 'doc', | 559 'doc', |
| 598 description='List all known modules reachable from the current package, ' | 560 description='List all known modules reachable from the current package, ' |
| 599 'with their documentation') | 561 'with their documentation') |
| 600 doc_p.add_argument('recipe', nargs='?', | 562 doc_p.add_argument('recipe', nargs='?', |
| 601 help='Restrict documentation to this recipe') | 563 help='Restrict documentation to this recipe') |
| 602 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, | 564 doc_p.add_argument('--kind', default='jsonpb', choices=doc_kinds, |
| 603 help='Output this kind of documentation') | 565 help='Output this kind of documentation') |
| 604 doc_p.set_defaults(command='doc') | 566 doc_p.set_defaults(command='doc') |
| 605 | 567 |
| 606 args = parser.parse_args() | 568 args = parser.parse_args() |
| 607 post_process_common_args(parser, args) | 569 common_postprocess_func(parser, args) |
| 570 if hasattr(args, 'postprocess_func'): | |
|
dnj
2017/04/27 16:33:53
ew ... maybe ABC / classes are actually the way to
| |
| 571 args.postprocess_func(parser, args) | |
| 608 | 572 |
| 609 # TODO(iannucci): We should always do logging.basicConfig() (probably with | 573 # TODO(iannucci): We should always do logging.basicConfig() (probably with |
| 610 # logging.WARNING), even if no verbose is passed. However we need to be | 574 # logging.WARNING), even if no verbose is passed. However we need to be |
| 611 # careful as this could cause issues with spurious/unexpected output. I think | 575 # careful as this could cause issues with spurious/unexpected output. I think |
| 612 # it's risky enough to do in a different CL. | 576 # it's risky enough to do in a different CL. |
| 613 | 577 |
| 614 if args.verbose > 0: | 578 if args.verbose > 0: |
| 615 logging.basicConfig() | 579 logging.basicConfig() |
| 616 logging.getLogger().setLevel(logging.INFO) | 580 logging.getLogger().setLevel(logging.INFO) |
| 617 if args.verbose > 1: | 581 if args.verbose > 1: |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 # to automatically find a consistent state, rather than bailing out. | 675 # to automatically find a consistent state, rather than bailing out. |
| 712 # Especially that only some subcommands refer to package_deps. | 676 # Especially that only some subcommands refer to package_deps. |
| 713 package_deps = package.PackageDeps.create( | 677 package_deps = package.PackageDeps.create( |
| 714 repo_root, config_file, allow_fetch=not args.no_fetch, | 678 repo_root, config_file, allow_fetch=not args.no_fetch, |
| 715 deps_path=args.deps_path, overrides=args.project_override) | 679 deps_path=args.deps_path, overrides=args.project_override) |
| 716 except subprocess.CalledProcessError: | 680 except subprocess.CalledProcessError: |
| 717 # A git checkout failed somewhere. Return 2, which is the sign that this is | 681 # A git checkout failed somewhere. Return 2, which is the sign that this is |
| 718 # an infra failure, rather than a test failure. | 682 # an infra failure, rather than a test failure. |
| 719 return 2 | 683 return 2 |
| 720 | 684 |
| 721 if args.command == 'fetch': | 685 if hasattr(args, 'func'): |
| 722 # We already did everything in the create() call above. | 686 return args.func(package_deps, args) |
| 723 assert not args.no_fetch, 'Fetch? No-fetch? Make up your mind!' | 687 |
| 724 return 0 | 688 if args.command == 'test': |
| 725 elif args.command == 'test': | |
| 726 return test(config_file, package_deps, args) | 689 return test(config_file, package_deps, args) |
| 727 elif args.command == 'bundle': | |
| 728 return bundle(config_file, package_deps, args) | |
| 729 elif args.command == 'lint': | |
| 730 return lint(config_file, package_deps, args) | |
| 731 elif args.command == 'run': | 690 elif args.command == 'run': |
| 732 return run(config_file, package_deps, args) | 691 return run(config_file, package_deps, args) |
| 733 elif args.command == 'autoroll': | 692 elif args.command == 'autoroll': |
| 734 return autoroll(repo_root, config_file, args) | 693 return autoroll(repo_root, config_file, args) |
| 735 elif args.command == 'depgraph': | 694 elif args.command == 'depgraph': |
| 736 return depgraph(config_file, package_deps, args) | 695 return depgraph(config_file, package_deps, args) |
| 737 elif args.command == 'refs': | 696 elif args.command == 'refs': |
| 738 return refs(config_file, package_deps, args) | 697 return refs(config_file, package_deps, args) |
| 739 elif args.command == 'doc': | 698 elif args.command == 'doc': |
| 740 return doc(config_file, package_deps, args) | 699 return doc(config_file, package_deps, args) |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 770 | 729 |
| 771 if not isinstance(ret, int): | 730 if not isinstance(ret, int): |
| 772 if ret is None: | 731 if ret is None: |
| 773 ret = 0 | 732 ret = 0 |
| 774 else: | 733 else: |
| 775 print >> sys.stderr, ret | 734 print >> sys.stderr, ret |
| 776 ret = 1 | 735 ret = 1 |
| 777 sys.stdout.flush() | 736 sys.stdout.flush() |
| 778 sys.stderr.flush() | 737 sys.stderr.flush() |
| 779 os._exit(ret) | 738 os._exit(ret) |
| OLD | NEW |