OLD | NEW |
1 # Copyright 2016 The LUCI Authors. All rights reserved. | 1 # Copyright 2016 The LUCI Authors. All rights reserved. |
2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
4 | 4 |
5 import collections | 5 import collections |
6 import contextlib | 6 import contextlib |
7 import imp | 7 import imp |
8 import inspect | 8 import inspect |
9 import os | 9 import os |
10 import sys | 10 import sys |
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 return mod_api | 583 return mod_api |
584 | 584 |
585 mapper = DependencyMapper(instantiator) | 585 mapper = DependencyMapper(instantiator) |
586 # Provide a fake module to the ScriptApi so that recipes can use: | 586 # Provide a fake module to the ScriptApi so that recipes can use: |
587 # * .name | 587 # * .name |
588 # * .resource | 588 # * .resource |
589 # * .package_repo_resource | 589 # * .package_repo_resource |
590 # This is obviously a hack, however it homogenizes the api and removes the | 590 # This is obviously a hack, however it homogenizes the api and removes the |
591 # need for some ugly workarounds in user code. A better way to do this would | 591 # need for some ugly workarounds in user code. A better way to do this would |
592 # be to migrate all recipes to be members of modules. | 592 # be to migrate all recipes to be members of modules. |
593 name = os.path.join( | 593 is_module = recipe_script_path.startswith(toplevel_package.module_dirs[0]) |
594 toplevel_package.name, | 594 rel_to = toplevel_package.recipe_dirs[0] |
595 os.path.relpath( | 595 if is_module: |
596 os.path.splitext(recipe_script_path)[0], | 596 rel_to = toplevel_package.module_dirs[0] |
597 toplevel_package.recipe_dirs[0])) | 597 rel_path = os.path.relpath(os.path.splitext(recipe_script_path)[0], rel_to) |
| 598 if is_module: |
| 599 mod_name, recipe = rel_path.split(os.path.sep, 1) |
| 600 rel_path = "%s:%s" % (mod_name, recipe) |
| 601 name = "%s::%s" % (toplevel_package.name, rel_path) |
598 fakeModule = collections.namedtuple( | 602 fakeModule = collections.namedtuple( |
599 "fakeModule", "PACKAGE_REPO_ROOT NAME RESOURCE_DIRECTORY")( | 603 "fakeModule", "PACKAGE_REPO_ROOT NAME RESOURCE_DIRECTORY")( |
600 Path(PackageRepoBasePath(toplevel_package)), | 604 Path(PackageRepoBasePath(toplevel_package)), |
601 name, | 605 name, |
602 Path(RecipeScriptBasePath( | 606 Path(RecipeScriptBasePath( |
603 name, os.path.splitext(recipe_script_path)[0]+".resources"))) | 607 name, os.path.splitext(recipe_script_path)[0]+".resources"))) |
604 api = RecipeScriptApi(module=fakeModule, engine=engine, | 608 api = RecipeScriptApi(module=fakeModule, engine=engine, |
605 test_data=test_data.get_module_test_data(None)) | 609 test_data=test_data.get_module_test_data(None)) |
606 for k, v in toplevel_deps.iteritems(): | 610 for k, v in toplevel_deps.iteritems(): |
607 setattr(api, k, mapper.instantiate(v)) | 611 setattr(api, k, mapper.instantiate(v)) |
| 612 |
| 613 # Always instantiate the path module at least once so that string functions on |
| 614 # Path objects work. This extra load doesn't actually attach the loaded path |
| 615 # module to the api return, so if recipes want to use the path module, they |
| 616 # still need to import it. If the recipe already loaded the path module |
| 617 # (somewhere, could be transitively), then this extra load is a no-op. |
| 618 # TODO(iannucci): The way paths work need to be reimplemented sanely :/ |
| 619 path_spec = engine._universe_view.deps_from_spec(['recipe_engine/path']) |
| 620 mapper.instantiate(path_spec['path']) |
| 621 |
608 return api | 622 return api |
609 | 623 |
610 | 624 |
611 def create_test_api(toplevel_deps, universe): | 625 def create_test_api(toplevel_deps, universe): |
612 def instantiator(mod, deps): | 626 def instantiator(mod, deps): |
613 modapi = (getattr(mod, 'TEST_API', None) or RecipeTestApi)(module=mod) | 627 modapi = (getattr(mod, 'TEST_API', None) or RecipeTestApi)(module=mod) |
614 for k,v in deps.iteritems(): | 628 for k,v in deps.iteritems(): |
615 setattr(modapi.m, k, v) | 629 setattr(modapi.m, k, v) |
616 return modapi | 630 return modapi |
617 | 631 |
618 mapper = DependencyMapper(instantiator) | 632 mapper = DependencyMapper(instantiator) |
619 api = RecipeTestApi(module=None) | 633 api = RecipeTestApi(module=None) |
620 for k,v in toplevel_deps.iteritems(): | 634 for k,v in toplevel_deps.iteritems(): |
621 setattr(api, k, mapper.instantiate(v)) | 635 setattr(api, k, mapper.instantiate(v)) |
622 return api | 636 return api |
623 | 637 |
624 | 638 |
625 def _resolve_requirement(req, engine): | 639 def _resolve_requirement(req, engine): |
626 if req._typ == 'client': | 640 if req._typ == 'client': |
627 return engine._get_client(req._name) | 641 return engine._get_client(req._name) |
628 else: | 642 else: |
629 raise ValueError('Unknown requirement type [%s]' % (req._typ,)) | 643 raise ValueError('Unknown requirement type [%s]' % (req._typ,)) |
OLD | NEW |