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

Unified Diff: gclient.py

Issue 2839008: Make the DEPS parsing saner. (Closed)
Patch Set: Take 3. fixes issue with double-parsed DEPS Created 10 years, 6 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 | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.
« no previous file with comments | « no previous file | tests/fake_repos.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698