Index: gclient.py |
diff --git a/gclient.py b/gclient.py |
index 0cc99da2d2098e0a65eb2474bc7649a1f63ea439..55305bd8c4b2493766dfa995b9ad735a50613da0 100644 |
--- a/gclient.py |
+++ b/gclient.py |
@@ -166,6 +166,8 @@ class Dependency(GClientKeywords): |
self.deps_hooks = [] |
self.dependencies = [] |
self.deps_file = deps_file or self.DEPS_FILE |
+ self.deps_parsed = False |
+ self.direct_reference = False |
# Sanity checks |
if not self.name and self.parent: |
@@ -179,49 +181,37 @@ class Dependency(GClientKeywords): |
raise gclient_utils.Error('deps_file name must not be a path, just a ' |
'filename. %s' % self.deps_file) |
- def _ParseSolutionDeps(self, solution_name, solution_deps_content, |
- custom_vars, parse_hooks): |
- """Parses the DEPS file for the specified solution. |
- |
- Args: |
- solution_name: The name of the solution to query. |
- solution_deps_content: Content of the DEPS file for the solution |
- custom_vars: A dict of vars to override any vars defined in the DEPS file. |
- |
- Returns: |
- A dict mapping module names (as relative paths) to URLs or an empty |
- dict if the solution does not have a DEPS file. |
- """ |
- # Skip empty |
- if not solution_deps_content: |
+ def ParseDepsFile(self, direct_reference): |
+ """Parses the DEPS file for this dependency.""" |
+ if direct_reference: |
+ # Maybe it was referenced earlier by a From() keyword but it's now |
+ # directly referenced. |
+ self.direct_reference = direct_reference |
+ self.deps_parsed = True |
+ filepath = os.path.join(self.root_dir(), self.name, self.deps_file) |
+ if not os.path.isfile(filepath): |
return {} |
- # Eval the content |
+ deps_content = gclient_utils.FileRead(filepath) |
+ |
+ # Eval the content. |
+ # One thing is unintuitive, vars= {} must happen before Var() use. |
local_scope = {} |
- var = self.VarImpl(custom_vars, local_scope) |
+ var = self.VarImpl(self.custom_vars, local_scope) |
global_scope = { |
- "File": self.FileImpl, |
- "From": self.FromImpl, |
- "Var": var.Lookup, |
- "deps_os": {}, |
+ 'File': self.FileImpl, |
+ 'From': self.FromImpl, |
+ 'Var': var.Lookup, |
+ 'deps_os': {}, |
} |
- exec(solution_deps_content, global_scope, local_scope) |
- deps = local_scope.get("deps", {}) |
- |
+ exec(deps_content, global_scope, local_scope) |
+ deps = local_scope.get('deps', {}) |
# load os specific dependencies if defined. these dependencies may |
# override or extend the values defined by the 'deps' member. |
- if "deps_os" in local_scope: |
- if self._options.deps_os is not None: |
- deps_to_include = self._options.deps_os.split(",") |
- if "all" in deps_to_include: |
- deps_to_include = list(set(self.DEPS_OS_CHOICES.itervalues())) |
- else: |
- deps_to_include = [self.DEPS_OS_CHOICES.get(sys.platform, "unix")] |
- |
- deps_to_include = set(deps_to_include) |
- for deps_os_key in deps_to_include: |
- os_deps = local_scope["deps_os"].get(deps_os_key, {}) |
- if len(deps_to_include) > 1: |
- # Ignore any overrides when including deps for more than one |
+ if 'deps_os' in local_scope: |
+ for deps_os_key in self.enforced_os(): |
+ os_deps = local_scope['deps_os'].get(deps_os_key, {}) |
+ if len(self.enforced_os()) > 1: |
+ # Ignore any conflict when including deps for more than one |
# platform, so we collect the broadest set of dependencies available. |
# We may end up with the wrong revision of something for our |
# platform, but this is the best we can do. |
@@ -229,36 +219,35 @@ class Dependency(GClientKeywords): |
else: |
deps.update(os_deps) |
- if 'hooks' in local_scope and parse_hooks: |
- # TODO(maruel): Temporary Hack. Since this function is misplaced, find the |
- # right 'self' to add the hooks. |
- for d in self.dependencies: |
- if d.name == solution_name: |
- d.deps_hooks.extend(local_scope['hooks']) |
- break |
+ self.deps_hooks.extend(local_scope.get('hooks', [])) |
+ |
+ # If a line is in custom_deps, but not in the solution, we want to append |
+ # this line to the solution. |
+ for d in self.custom_deps: |
+ if d not in deps: |
+ deps[d] = self.custom_deps[d] |
# If use_relative_paths is set in the DEPS file, regenerate |
# the dictionary using paths relative to the directory containing |
# the DEPS file. |
- if local_scope.get('use_relative_paths'): |
+ use_relative_paths = local_scope.get('use_relative_paths', False) |
+ if use_relative_paths: |
rel_deps = {} |
for d, url in deps.items(): |
# normpath is required to allow DEPS to use .. in their |
# dependency local path. |
- rel_deps[os.path.normpath(os.path.join(solution_name, d))] = url |
- return rel_deps |
- else: |
- return deps |
+ rel_deps[os.path.normpath(os.path.join(self.name, d))] = url |
+ deps = rel_deps |
+ # TODO(maruel): Add these dependencies into self.dependencies. |
+ return deps |
- def _ParseAllDeps(self, solution_urls, solution_deps_content): |
+ def _ParseAllDeps(self, solution_urls): |
"""Parse the complete list of dependencies for the client. |
Args: |
solution_urls: A dict mapping module names (as relative paths) to URLs |
corresponding to the solutions specified by the client. This parameter |
is passed as an optimization. |
- solution_deps_content: A dict mapping module names to the content |
- of their DEPS files |
Returns: |
A dict mapping module names (as relative paths) to URLs corresponding |
@@ -269,11 +258,7 @@ class Dependency(GClientKeywords): |
""" |
deps = {} |
for solution in self.dependencies: |
- solution_deps = self._ParseSolutionDeps( |
- solution.name, |
- solution_deps_content[solution.name], |
- solution.custom_vars, |
- True) |
+ solution_deps = solution.ParseDepsFile(True) |
# If a line is in custom_deps, but not in the solution, we want to append |
# this line to the solution. |
@@ -379,6 +364,12 @@ class Dependency(GClientKeywords): |
if matching_file_list: |
self._RunHookAction(hook_dict, matching_file_list) |
+ def root_dir(self): |
+ return self.parent.root_dir() |
+ |
+ def enforced_os(self): |
+ return self.parent.enforced_os() |
+ |
class GClient(Dependency): |
"""Main gclient checkout root where .gclient resides.""" |
@@ -428,8 +419,15 @@ solutions = [ |
def __init__(self, root_dir, options): |
Dependency.__init__(self, None, None, None) |
- self._root_dir = root_dir |
self._options = options |
+ if options.deps_os: |
+ enforced_os = options.deps_os.split(',') |
+ else: |
+ enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] |
+ if 'all' in enforced_os: |
+ enforced_os = self.DEPS_OS_CHOICES.itervalues() |
+ self._enforced_os = list(set(enforced_os)) |
+ self._root_dir = root_dir |
self.config_content = None |
def SetConfig(self, content): |
@@ -567,7 +565,6 @@ solutions = [ |
run_scm = not (command == 'runhooks' and self._options.force) |
entries = {} |
- entries_deps_content = {} |
file_list = [] |
# Run on the base solutions first. |
for solution in self.dependencies: |
@@ -582,18 +579,10 @@ solutions = [ |
scm.RunCommand(command, self._options, args, file_list) |
file_list = [os.path.join(name, f.strip()) for f in file_list] |
self._options.revision = None |
- try: |
- deps_content = gclient_utils.FileRead( |
- os.path.join(self.root_dir(), name, solution.deps_file)) |
- except IOError, e: |
- if e.errno != errno.ENOENT: |
- raise |
- deps_content = "" |
- entries_deps_content[name] = deps_content |
# Process the dependencies next (sort alphanumerically to ensure that |
# containing directories get populated first and for readability) |
- deps = self._ParseAllDeps(entries, entries_deps_content) |
+ deps = self._ParseAllDeps(entries) |
deps_to_process = deps.keys() |
deps_to_process.sort() |
@@ -625,16 +614,12 @@ solutions = [ |
# Second pass for inherited deps (via the From keyword) |
for d in deps_to_process: |
if isinstance(deps[d], self.FromImpl): |
- filename = os.path.join(self.root_dir(), |
- deps[d].module_name, |
- self.DEPS_FILE) |
- content = gclient_utils.FileRead(filename) |
- sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, |
- False) |
# Getting the URL from the sub_deps file can involve having to resolve |
# a File() or having to resolve a relative URL. To resolve relative |
# URLs, we need to pass in the orignal sub deps URL. |
sub_deps_base_url = deps[deps[d].module_name] |
+ sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url |
+ ).ParseDepsFile(False) |
url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) |
entries[d] = url |
if run_scm: |
@@ -722,7 +707,6 @@ solutions = [ |
# Dictionary of { path : SCM url } to ensure no duplicate solutions |
solution_names = {} |
entries = {} |
- entries_deps_content = {} |
# Run on the base solutions first. |
for solution in self.dependencies: |
# Dictionary of { path : SCM url } to describe the gclient checkout |
@@ -732,22 +716,10 @@ solutions = [ |
(url, rev) = GetURLAndRev(name, solution.url) |
entries[name] = "%s@%s" % (url, rev) |
solution_names[name] = "%s@%s" % (url, rev) |
- deps_file = solution.deps_file |
- if '/' in deps_file or '\\' in deps_file: |
- raise gclient_utils.Error('deps_file name must not be a path, just a ' |
- 'filename.') |
- try: |
- deps_content = gclient_utils.FileRead( |
- os.path.join(self.root_dir(), name, deps_file)) |
- except IOError, e: |
- if e.errno != errno.ENOENT: |
- raise |
- deps_content = "" |
- entries_deps_content[name] = deps_content |
# Process the dependencies next (sort alphanumerically to ensure that |
# containing directories get populated first and for readability) |
- deps = self._ParseAllDeps(entries, entries_deps_content) |
+ deps = self._ParseAllDeps(entries) |
deps_to_process = deps.keys() |
deps_to_process.sort() |
@@ -764,13 +736,11 @@ solutions = [ |
if deps_parent_url.find("@") < 0: |
raise gclient_utils.Error("From %s missing revisioned url" % |
deps[d].module_name) |
- content = gclient_utils.FileRead(os.path.join( |
- self.root_dir(), |
- deps[d].module_name, |
- self.DEPS_FILE)) |
- sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, |
- False) |
- (url, rev) = GetURLAndRev(d, sub_deps[d]) |
+ sub_deps_base_url = deps[deps[d].module_name] |
+ sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url |
+ ).ParseDepsFile(False) |
+ url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) |
+ (url, rev) = GetURLAndRev(d, url) |
entries[d] = "%s@%s" % (url, rev) |
# Build the snapshot configuration string |
@@ -799,6 +769,9 @@ solutions = [ |
def root_dir(self): |
return self._root_dir |
+ def enforced_os(self): |
+ return self._enforced_os |
+ |
#### gclient commands. |