Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(278)

Unified Diff: recipe_engine/loader.py

Issue 1344583003: Recipe package system. (Closed) Base URL: git@github.com:luci/recipes-py.git@master
Patch Set: Recompiled proto Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « recipe_engine/lint_test.py ('k') | recipe_engine/package.proto » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: recipe_engine/loader.py
diff --git a/recipe_engine/loader.py b/recipe_engine/loader.py
index eafbeb5d4f29b4187c134b979b36a3bfb0e3ff6b..a88d6c7432e5371b5024f1d33810eec08a6afdb4 100644
--- a/recipe_engine/loader.py
+++ b/recipe_engine/loader.py
@@ -41,8 +41,8 @@ class RecipeScript(object):
with _preserve_path():
execfile(script_path, script_vars)
- script_vars['LOADED_DEPS'] = universe.deps_from_mixed(
- script_vars.get('DEPS', []), os.path.basename(script_path))
+ script_vars['LOADED_DEPS'] = universe.deps_from_spec(
+ script_vars.get('DEPS', []))
return cls(script_vars)
@@ -62,8 +62,10 @@ class Dependency(object):
class PathDependency(Dependency):
- def __init__(self, path, local_name, universe, base_path=None):
- self._path = _normalize_path(base_path, path)
+ def __init__(self, path, local_name, universe):
+ assert os.path.isabs(path), (
+ 'Path dependencies must be absolute, but %s is not' % path)
+ self._path = path
self._local_name = local_name
# We forbid modules from living outside our main paths to keep clients
@@ -95,19 +97,32 @@ class NamedDependency(PathDependency):
raise NoSuchRecipe('Recipe module named %s does not exist' % name)
+class PackageDependency(PathDependency):
+ # TODO(luqui): Forbid depending on a module from a (locally) undeclared
+ # dependency.
+ def __init__(self, package, module, local_name, universe):
+ mod_path = (
+ universe.package_deps.get_package(package).module_path(module))
+ super(PackageDependency, self).__init__(
+ mod_path, local_name, universe=universe)
+
+
class RecipeUniverse(object):
- def __init__(self, module_dirs, recipe_dirs):
+ def __init__(self, package_deps):
self._loaded = {}
- self._module_dirs = module_dirs[:]
- self._recipe_dirs = recipe_dirs[:]
+ self._package_deps = package_deps
@property
def module_dirs(self):
- return self._module_dirs
+ return self._package_deps.all_module_dirs
@property
def recipe_dirs(self):
- return self._recipe_dirs
+ return self._package_deps.all_recipe_dirs
+
+ @property
+ def package_deps(self):
+ return self._package_deps
def load(self, dep):
"""Load a Dependency."""
@@ -123,26 +138,31 @@ class RecipeUniverse(object):
self._loaded[name] = mod
return mod
- def deps_from_names(self, deps):
- """Load dependencies given a list simple module names (old style)."""
- return { dep: self.load(NamedDependency(dep, universe=self))
- for dep in deps }
-
- def deps_from_paths(self, deps, base_path):
- """Load dependencies given a dictionary of local names to module paths
- (new style)."""
- return { name: self.load(PathDependency(path, name,
- universe=self, base_path=base_path))
- for name, path in deps.iteritems() }
-
- def deps_from_mixed(self, deps, base_path):
- """Load dependencies given either a new style or old style deps spec."""
- if isinstance(deps, (list, tuple)):
- return self.deps_from_names(deps)
- elif isinstance(deps, dict):
- return self.deps_from_paths(deps, base_path)
+ def _dep_from_name(self, name):
+ if '/' in name:
+ [package,module] = name.split('/')
+ dep = PackageDependency(package, module, module, universe=self)
else:
- raise ValueError('%s is not a valid or known deps structure' % deps)
+ # Old style: bare module name, search paths to find it.
+ module = name
+ dep = NamedDependency(name, universe=self)
+
+ return module, dep
+
+ def deps_from_spec(self, spec):
+ # Automatic local names.
+ if isinstance(spec, (list, tuple)):
+ deps = {}
+ for item in spec:
+ name, dep = self._dep_from_name(item)
+ deps[name] = self.load(dep)
+ # Explicit local names.
+ elif isinstance(spec, dict):
+ deps = {}
+ for name, item in spec.iteritems():
+ _, dep = self._dep_from_name(item)
+ deps[name] = self.load(dep)
+ return deps
def load_recipe(self, recipe):
"""Given name of a recipe, loads and returns it as RecipeScript instance.
@@ -163,10 +183,11 @@ class RecipeUniverse(object):
module_name, example = recipe.split(':')
assert example.endswith('example')
for module_dir in self.module_dirs:
- for subitem in os.listdir(module_dir):
- if module_name == subitem:
- return RecipeScript.from_script_path(
- os.path.join(module_dir, subitem, 'example.py'), self)
+ if os.path.isdir(module_dir):
+ for subitem in os.listdir(module_dir):
+ if module_name == subitem:
+ return RecipeScript.from_script_path(
+ os.path.join(module_dir, subitem, 'example.py'), self)
raise NoSuchRecipe(recipe,
'Recipe example %s:%s does not exist' %
(module_name, example))
@@ -214,13 +235,6 @@ def _preserve_path():
sys.path = old_path
-def _normalize_path(base_path, path):
- if base_path is None or os.path.isabs(path):
- return os.path.realpath(path)
- else:
- return os.path.realpath(os.path.join(base_path, path))
-
-
def _find_and_load_module(fullname, modname, path):
imp.acquire_lock()
try:
@@ -244,8 +258,7 @@ def _load_recipe_module_module(path, universe):
mod = _find_and_load_module(fullname, modname, path)
# This actually loads the dependencies.
- mod.LOADED_DEPS = universe.deps_from_mixed(
- getattr(mod, 'DEPS', []), os.path.basename(path))
+ mod.LOADED_DEPS = universe.deps_from_spec(getattr(mod, 'DEPS', []))
# Prevent any modules that mess with sys.path from leaking.
with _preserve_path():
« no previous file with comments | « recipe_engine/lint_test.py ('k') | recipe_engine/package.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698