| OLD | NEW | 
|     1 #!/usr/bin/python |     1 #!/usr/bin/python | 
|     2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |     2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
|     3 # Use of this source code is governed by a BSD-style license that can be |     3 # Use of this source code is governed by a BSD-style license that can be | 
|     4 # found in the LICENSE file. |     4 # found in the LICENSE file. | 
|     5  |     5  | 
|     6 """Meta checkout manager supporting both Subversion and GIT. |     6 """Meta checkout manager supporting both Subversion and GIT. | 
|     7  |     7  | 
|     8 Files |     8 Files | 
|     9   .gclient      : Current client configuration, written by 'config' command. |     9   .gclient      : Current client configuration, written by 'config' command. | 
|    10                   Format is a Python script defining 'solutions', a list whose |    10                   Format is a Python script defining 'solutions', a list whose | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|    42                it will be removed from the list and the list will be extended |    42                it will be removed from the list and the list will be extended | 
|    43                by the list of matching files. |    43                by the list of matching files. | 
|    44  |    44  | 
|    45   Example: |    45   Example: | 
|    46     hooks = [ |    46     hooks = [ | 
|    47       { "pattern": "\\.(gif|jpe?g|pr0n|png)$", |    47       { "pattern": "\\.(gif|jpe?g|pr0n|png)$", | 
|    48         "action":  ["python", "image_indexer.py", "--all"]}, |    48         "action":  ["python", "image_indexer.py", "--all"]}, | 
|    49     ] |    49     ] | 
|    50 """ |    50 """ | 
|    51  |    51  | 
|    52 __version__ = "0.5.1" |    52 __version__ = "0.5.2" | 
|    53  |    53  | 
|    54 import logging |    54 import logging | 
|    55 import optparse |    55 import optparse | 
|    56 import os |    56 import os | 
|    57 import posixpath |    57 import posixpath | 
|    58 import pprint |    58 import pprint | 
|    59 import re |    59 import re | 
|    60 import subprocess |    60 import subprocess | 
|    61 import sys |    61 import sys | 
|    62 import threading |    62 import threading | 
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   237       elif var_name in self._local_scope.get("vars", {}): |   237       elif var_name in self._local_scope.get("vars", {}): | 
|   238         return self._local_scope["vars"][var_name] |   238         return self._local_scope["vars"][var_name] | 
|   239       raise gclient_utils.Error("Var is not defined: %s" % var_name) |   239       raise gclient_utils.Error("Var is not defined: %s" % var_name) | 
|   240  |   240  | 
|   241  |   241  | 
|   242 class Dependency(GClientKeywords, WorkItem): |   242 class Dependency(GClientKeywords, WorkItem): | 
|   243   """Object that represents a dependency checkout.""" |   243   """Object that represents a dependency checkout.""" | 
|   244   DEPS_FILE = 'DEPS' |   244   DEPS_FILE = 'DEPS' | 
|   245  |   245  | 
|   246   def __init__(self, parent, name, url, safesync_url, custom_deps, |   246   def __init__(self, parent, name, url, safesync_url, custom_deps, | 
|   247                custom_vars, deps_file): |   247                custom_vars, deps_file, should_process): | 
|   248     GClientKeywords.__init__(self) |   248     GClientKeywords.__init__(self) | 
|   249     self.parent = parent |   249     self.parent = parent | 
|   250     self.name = name |   250     self.name = name | 
|   251     self.url = url |   251     self.url = url | 
|   252     self.parsed_url = None |   252     self.parsed_url = None | 
|   253     # These 2 are only set in .gclient and not in DEPS files. |   253     # These 2 are only set in .gclient and not in DEPS files. | 
|   254     self.safesync_url = safesync_url |   254     self.safesync_url = safesync_url | 
|   255     self.custom_vars = custom_vars or {} |   255     self.custom_vars = custom_vars or {} | 
|   256     self.custom_deps = custom_deps or {} |   256     self.custom_deps = custom_deps or {} | 
|   257     self.deps_hooks = [] |   257     self.deps_hooks = [] | 
|   258     self.dependencies = [] |   258     self.dependencies = [] | 
|   259     self.deps_file = deps_file or self.DEPS_FILE |   259     self.deps_file = deps_file or self.DEPS_FILE | 
|   260     # A cache of the files affected by the current operation, necessary for |   260     # A cache of the files affected by the current operation, necessary for | 
|   261     # hooks. |   261     # hooks. | 
|   262     self._file_list = [] |   262     self._file_list = [] | 
|   263     # If it is not set to True, the dependency wasn't processed for its child |   263     # If it is not set to True, the dependency wasn't processed for its child | 
|   264     # dependency, i.e. its DEPS wasn't read. |   264     # dependency, i.e. its DEPS wasn't read. | 
|   265     self.deps_parsed = False |   265     self.deps_parsed = False | 
|   266     # A direct reference is dependency that is referenced by a deps, deps_os or |   266     # This dependency should be processed, i.e. checked out | 
|   267     # solution. A indirect one is one that was loaded with From() or that |   267     self.should_process = should_process | 
|   268     # exceeded recursion limit. |  | 
|   269     self.direct_reference = False |  | 
|   270     # This dependency has been processed, i.e. checked out |   268     # This dependency has been processed, i.e. checked out | 
|   271     self.processed = False |   269     self.processed = False | 
|   272     # This dependency had its hook run |   270     # This dependency had its hook run | 
|   273     self.hooks_ran = False |   271     self.hooks_ran = False | 
|   274     # Required dependencies to run before running this one: |   272     # Required dependencies to run before running this one: | 
|   275     self.requirements = [] |   273     self.requirements = [] | 
|   276     if self.parent and self.parent.name: |   274     if self.parent and self.parent.name: | 
|   277       self.requirements.append(self.parent.name) |   275       self.requirements.append(self.parent.name) | 
|   278     if isinstance(self.url, self.FromImpl): |   276     if isinstance(self.url, self.FromImpl): | 
|   279       self.requirements.append(self.url.module_name) |   277       self.requirements.append(self.url.module_name) | 
|   280  |   278  | 
|   281     # Sanity checks |   279     # Sanity checks | 
|   282     if not self.name and self.parent: |   280     if not self.name and self.parent: | 
|   283       raise gclient_utils.Error('Dependency without name') |   281       raise gclient_utils.Error('Dependency without name') | 
|   284     if not isinstance(self.url, |   282     if not isinstance(self.url, | 
|   285         (basestring, self.FromImpl, self.FileImpl, None.__class__)): |   283         (basestring, self.FromImpl, self.FileImpl, None.__class__)): | 
|   286       raise gclient_utils.Error('dependency url must be either a string, None, ' |   284       raise gclient_utils.Error('dependency url must be either a string, None, ' | 
|   287                                 'File() or From() instead of %s' % |   285                                 'File() or From() instead of %s' % | 
|   288                                 self.url.__class__.__name__) |   286                                 self.url.__class__.__name__) | 
|   289     if '/' in self.deps_file or '\\' in self.deps_file: |   287     if '/' in self.deps_file or '\\' in self.deps_file: | 
|   290       raise gclient_utils.Error('deps_file name must not be a path, just a ' |   288       raise gclient_utils.Error('deps_file name must not be a path, just a ' | 
|   291                                 'filename. %s' % self.deps_file) |   289                                 'filename. %s' % self.deps_file) | 
|   292  |   290  | 
|   293   def LateOverride(self, url): |   291   def LateOverride(self, url): | 
|   294     """Resolves the parsed url from url. |   292     """Resolves the parsed url from url. | 
|   295  |   293  | 
|   296     Manages From() keyword accordingly. Do not touch self.parsed_url nor |   294     Manages From() keyword accordingly. Do not touch self.parsed_url nor | 
|   297     self.url because it may called with other urls due to From().""" |   295     self.url because it may called with other urls due to From().""" | 
 |   296     assert self.parsed_url == None or not self.should_process, self.parsed_url | 
|   298     overriden_url = self.get_custom_deps(self.name, url) |   297     overriden_url = self.get_custom_deps(self.name, url) | 
|   299     if overriden_url != url: |   298     if overriden_url != url: | 
|   300       logging.info('%s, %s was overriden to %s' % (self.name, url, |   299       logging.info('%s, %s was overriden to %s' % (self.name, url, | 
|   301           overriden_url)) |   300           overriden_url)) | 
|   302       return overriden_url |   301       return overriden_url | 
|   303     elif isinstance(url, self.FromImpl): |   302     elif isinstance(url, self.FromImpl): | 
|   304       ref = [dep for dep in self.tree(True) if url.module_name == dep.name] |   303       ref = [dep for dep in self.tree(True) if url.module_name == dep.name] | 
|   305       if not ref: |   304       if not ref: | 
|   306         raise gclient_utils.Error('Failed to find one reference to %s. %s' % ( |   305         raise gclient_utils.Error('Failed to find one reference to %s. %s' % ( | 
|   307             url.module_name, ref)) |   306             url.module_name, ref)) | 
|   308       # It may happen that len(ref) > 1 but it's no big deal. |   307       # It may happen that len(ref) > 1 but it's no big deal. | 
|   309       ref = ref[0] |   308       ref = ref[0] | 
|   310       sub_target = url.sub_target_name or self.name |   309       sub_target = url.sub_target_name or self.name | 
|   311       # Make sure the referenced dependency DEPS file is loaded and file the |   310       # Make sure the referenced dependency DEPS file is loaded and file the | 
|   312       # inner referenced dependency. |   311       # inner referenced dependency. | 
|   313       ref.ParseDepsFile(False) |   312       ref.ParseDepsFile() | 
|   314       found_dep = None |   313       found_dep = None | 
|   315       for d in ref.dependencies: |   314       for d in ref.dependencies: | 
|   316         if d.name == sub_target: |   315         if d.name == sub_target: | 
|   317           found_dep = d |   316           found_dep = d | 
|   318           break |   317           break | 
|   319       if not found_dep: |   318       if not found_dep: | 
|   320         raise gclient_utils.Error( |   319         raise gclient_utils.Error( | 
|   321             'Couldn\'t find %s in %s, referenced by %s\n%s' % ( |   320             'Couldn\'t find %s in %s, referenced by %s\n%s' % ( | 
|   322                 sub_target, ref.name, self.name, str(self.root_parent()))) |   321                 sub_target, ref.name, self.name, str(self.root_parent()))) | 
|   323       # Call LateOverride() again. |   322       # Call LateOverride() again. | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|   344       return parsed_url |   343       return parsed_url | 
|   345     elif isinstance(url, self.FileImpl): |   344     elif isinstance(url, self.FileImpl): | 
|   346       parsed_url = url |   345       parsed_url = url | 
|   347       logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) |   346       logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) | 
|   348       return parsed_url |   347       return parsed_url | 
|   349     elif url is None: |   348     elif url is None: | 
|   350       return None |   349       return None | 
|   351     else: |   350     else: | 
|   352       raise gclient_utils.Error('Unkown url type') |   351       raise gclient_utils.Error('Unkown url type') | 
|   353  |   352  | 
|   354   def ParseDepsFile(self, direct_reference): |   353   def ParseDepsFile(self): | 
|   355     """Parses the DEPS file for this dependency.""" |   354     """Parses the DEPS file for this dependency.""" | 
|   356     if direct_reference: |   355     assert self.processed == True | 
|   357       # Maybe it was referenced earlier by a From() keyword but it's now |  | 
|   358       # directly referenced. |  | 
|   359       self.direct_reference = direct_reference |  | 
|   360     if self.deps_parsed: |   356     if self.deps_parsed: | 
|   361       logging.debug('%s was already parsed' % self.name) |   357       logging.debug('%s was already parsed' % self.name) | 
|   362       return |   358       return | 
|   363     self.deps_parsed = True |   359     self.deps_parsed = True | 
|   364     filepath = os.path.join(self.root_dir(), self.name, self.deps_file) |   360     filepath = os.path.join(self.root_dir(), self.name, self.deps_file) | 
|   365     if not os.path.isfile(filepath): |   361     if not os.path.isfile(filepath): | 
|   366       logging.info('%s: No DEPS file found at %s' % (self.name, filepath)) |   362       logging.info('%s: No DEPS file found at %s' % (self.name, filepath)) | 
|   367       return |   363       return | 
|   368     deps_content = gclient_utils.FileRead(filepath) |   364     deps_content = gclient_utils.FileRead(filepath) | 
|   369     logging.debug(deps_content) |   365     logging.debug(deps_content) | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   416         # dependency local path. |   412         # dependency local path. | 
|   417         rel_deps[os.path.normpath(os.path.join(self.name, d))] = url |   413         rel_deps[os.path.normpath(os.path.join(self.name, d))] = url | 
|   418       deps = rel_deps |   414       deps = rel_deps | 
|   419  |   415  | 
|   420     # Convert the deps into real Dependency. |   416     # Convert the deps into real Dependency. | 
|   421     for name, url in deps.iteritems(): |   417     for name, url in deps.iteritems(): | 
|   422       if name in [s.name for s in self.dependencies]: |   418       if name in [s.name for s in self.dependencies]: | 
|   423         raise gclient_utils.Error( |   419         raise gclient_utils.Error( | 
|   424             'The same name "%s" appears multiple times in the deps section' % |   420             'The same name "%s" appears multiple times in the deps section' % | 
|   425                 name) |   421                 name) | 
 |   422       should_process = self.recursion_limit() and self.should_process | 
 |   423       if should_process: | 
 |   424         tree = dict((d.name, d) for d in self.tree(False)) | 
 |   425         if name in tree: | 
 |   426           if url == tree[name].url: | 
 |   427             logging.info('Won\'t process duplicate dependency %s' % tree[name]) | 
 |   428             # In theory we could keep it as a shadow of the other one. In | 
 |   429             # practice, simply ignore it. | 
 |   430             #should_process = False | 
 |   431             continue | 
 |   432           else: | 
 |   433             raise gclient_utils.Error( | 
 |   434                 'Dependency %s specified more than once:\n  %s\nvs\n  %s' % | 
 |   435                 (name, tree[name].hierarchy(), self.hierarchy())) | 
|   426       self.dependencies.append(Dependency(self, name, url, None, None, None, |   436       self.dependencies.append(Dependency(self, name, url, None, None, None, | 
|   427           None)) |   437           None, should_process)) | 
|   428     logging.debug('Loaded: %s' % str(self)) |   438     logging.debug('Loaded: %s' % str(self)) | 
|   429  |   439  | 
|   430   def run(self, options, revision_overrides, command, args, work_queue): |   440   def run(self, options, revision_overrides, command, args, work_queue): | 
|   431     """Runs 'command' before parsing the DEPS in case it's a initial checkout |   441     """Runs 'command' before parsing the DEPS in case it's a initial checkout | 
|   432     or a revert.""" |   442     or a revert.""" | 
|   433     assert self._file_list == [] |   443     assert self._file_list == [] | 
 |   444     if not self.should_process: | 
 |   445       return | 
|   434     # When running runhooks, there's no need to consult the SCM. |   446     # When running runhooks, there's no need to consult the SCM. | 
|   435     # All known hooks are expected to run unconditionally regardless of working |   447     # All known hooks are expected to run unconditionally regardless of working | 
|   436     # copy state, so skip the SCM status check. |   448     # copy state, so skip the SCM status check. | 
|   437     run_scm = command not in ('runhooks', None) |   449     run_scm = command not in ('runhooks', None) | 
|   438     self.parsed_url = self.LateOverride(self.url) |   450     self.parsed_url = self.LateOverride(self.url) | 
|   439     if run_scm and self.parsed_url: |   451     if run_scm and self.parsed_url: | 
|   440       if isinstance(self.parsed_url, self.FileImpl): |   452       if isinstance(self.parsed_url, self.FileImpl): | 
|   441         # Special support for single-file checkout. |   453         # Special support for single-file checkout. | 
|   442         if not command in (None, 'cleanup', 'diff', 'pack', 'status'): |   454         if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 
|   443           options.revision = self.parsed_url.GetRevision() |   455           options.revision = self.parsed_url.GetRevision() | 
|   444           scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), |   456           scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), | 
|   445                                        self.root_dir(), |   457                                        self.root_dir(), | 
|   446                                        self.name) |   458                                        self.name) | 
|   447           scm.RunCommand('updatesingle', options, |   459           scm.RunCommand('updatesingle', options, | 
|   448                          args + [self.parsed_url.GetFilename()], |   460                          args + [self.parsed_url.GetFilename()], | 
|   449                          self._file_list) |   461                          self._file_list) | 
|   450       else: |   462       else: | 
|   451         options.revision = revision_overrides.get(self.name) |   463         options.revision = revision_overrides.get(self.name) | 
|   452         scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) |   464         scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) | 
|   453         scm.RunCommand(command, options, args, self._file_list) |   465         scm.RunCommand(command, options, args, self._file_list) | 
|   454         self._file_list = [os.path.join(self.name, f.strip()) |   466         self._file_list = [os.path.join(self.name, f.strip()) | 
|   455                            for f in self._file_list] |   467                            for f in self._file_list] | 
|   456       options.revision = None |   468       options.revision = None | 
|   457     self.processed = True |   469     self.processed = True | 
|   458     if self.recursion_limit(): |   470     if self.recursion_limit(): | 
|   459       # Then we can parse the DEPS file. |   471       # Then we can parse the DEPS file. | 
|   460       self.ParseDepsFile(True) |   472       self.ParseDepsFile() | 
|   461       # Adjust the implicit dependency requirement; e.g. if a DEPS file contains |   473       # Adjust the implicit dependency requirement; e.g. if a DEPS file contains | 
|   462       # both src/foo and src/foo/bar, src/foo/bar is implicitly dependent of |   474       # both src/foo and src/foo/bar, src/foo/bar is implicitly dependent of | 
|   463       # src/foo. Yes, it's O(n^2)... It's important to do that before |   475       # src/foo. Yes, it's O(n^2)... It's important to do that before | 
|   464       # enqueueing them. |   476       # enqueueing them. | 
|   465       for s in self.dependencies: |   477       for s in self.dependencies: | 
|   466         for s2 in self.dependencies: |   478         for s2 in self.dependencies: | 
|   467           if s is s2: |   479           if s is s2: | 
|   468             continue |   480             continue | 
|   469           if s.name.startswith(posixpath.join(s2.name, '')): |   481           if s.name.startswith(posixpath.join(s2.name, '')): | 
|   470             s.requirements.append(s2.name) |   482             s.requirements.append(s2.name) | 
|   471  |   483  | 
|   472       # Parse the dependencies of this dependency. |   484       # Parse the dependencies of this dependency. | 
|   473       for s in self.dependencies: |   485       for s in self.dependencies: | 
|   474         work_queue.enqueue(s) |   486         work_queue.enqueue(s) | 
|   475  |   487  | 
|   476   def RunHooksRecursively(self, options): |   488   def RunHooksRecursively(self, options): | 
|   477     """Evaluates all hooks, running actions as needed. run() |   489     """Evaluates all hooks, running actions as needed. run() | 
|   478     must have been called before to load the DEPS.""" |   490     must have been called before to load the DEPS.""" | 
 |   491     assert self.hooks_ran == False | 
 |   492     if not self.should_process: | 
 |   493       return | 
|   479     # If "--force" was specified, run all hooks regardless of what files have |   494     # If "--force" was specified, run all hooks regardless of what files have | 
|   480     # changed. |   495     # changed. | 
|   481     if self.deps_hooks and self.direct_reference: |   496     if self.deps_hooks: | 
|   482       # TODO(maruel): If the user is using git or git-svn, then we don't know |   497       # TODO(maruel): If the user is using git or git-svn, then we don't know | 
|   483       # what files have changed so we always run all hooks. It'd be nice to fix |   498       # what files have changed so we always run all hooks. It'd be nice to fix | 
|   484       # that. |   499       # that. | 
|   485       if (options.force or |   500       if (options.force or | 
|   486           isinstance(self.parsed_url, self.FileImpl) or |   501           isinstance(self.parsed_url, self.FileImpl) or | 
|   487           gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |   502           gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 
|   488           os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): |   503           os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): | 
|   489         for hook_dict in self.deps_hooks: |   504         for hook_dict in self.deps_hooks: | 
|   490           self._RunHookAction(hook_dict, []) |   505           self._RunHookAction(hook_dict, []) | 
|   491       else: |   506       else: | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
|   506                  file_list[i].startswith('/')): |   521                  file_list[i].startswith('/')): | 
|   507             file_list[i] = file_list[i][1:] |   522             file_list[i] = file_list[i][1:] | 
|   508  |   523  | 
|   509         # Run hooks on the basis of whether the files from the gclient operation |   524         # Run hooks on the basis of whether the files from the gclient operation | 
|   510         # match each hook's pattern. |   525         # match each hook's pattern. | 
|   511         for hook_dict in self.deps_hooks: |   526         for hook_dict in self.deps_hooks: | 
|   512           pattern = re.compile(hook_dict['pattern']) |   527           pattern = re.compile(hook_dict['pattern']) | 
|   513           matching_file_list = [f for f in file_list if pattern.search(f)] |   528           matching_file_list = [f for f in file_list if pattern.search(f)] | 
|   514           if matching_file_list: |   529           if matching_file_list: | 
|   515             self._RunHookAction(hook_dict, matching_file_list) |   530             self._RunHookAction(hook_dict, matching_file_list) | 
|   516     if self.recursion_limit(): |   531     for s in self.dependencies: | 
|   517       for s in self.dependencies: |   532       s.RunHooksRecursively(options) | 
|   518         s.RunHooksRecursively(options) |  | 
|   519  |   533  | 
|   520   def _RunHookAction(self, hook_dict, matching_file_list): |   534   def _RunHookAction(self, hook_dict, matching_file_list): | 
|   521     """Runs the action from a single hook.""" |   535     """Runs the action from a single hook.""" | 
|   522     # A single DEPS file can specify multiple hooks so this function can be |   536     # A single DEPS file can specify multiple hooks so this function can be | 
|   523     # called multiple times on a single Dependency. |   537     # called multiple times on a single Dependency. | 
|   524     #assert self.hooks_ran == False |   538     #assert self.hooks_ran == False | 
|   525     self.hooks_ran = True |   539     self.hooks_ran = True | 
|   526     logging.debug(hook_dict) |   540     logging.debug(hook_dict) | 
|   527     logging.debug(matching_file_list) |   541     logging.debug(matching_file_list) | 
|   528     command = hook_dict['action'][:] |   542     command = hook_dict['action'][:] | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|   547   def enforced_os(self): |   561   def enforced_os(self): | 
|   548     return self.parent.enforced_os() |   562     return self.parent.enforced_os() | 
|   549  |   563  | 
|   550   def recursion_limit(self): |   564   def recursion_limit(self): | 
|   551     return self.parent.recursion_limit() - 1 |   565     return self.parent.recursion_limit() - 1 | 
|   552  |   566  | 
|   553   def tree(self, include_all): |   567   def tree(self, include_all): | 
|   554     return self.parent.tree(include_all) |   568     return self.parent.tree(include_all) | 
|   555  |   569  | 
|   556   def subtree(self, include_all): |   570   def subtree(self, include_all): | 
 |   571     """Breadth first""" | 
|   557     result = [] |   572     result = [] | 
|   558     # Add breadth-first. |   573     for d in self.dependencies: | 
|   559     if self.direct_reference or include_all: |   574       if d.should_process or include_all: | 
|   560       for d in self.dependencies: |  | 
|   561         result.append(d) |   575         result.append(d) | 
|   562       for d in self.dependencies: |   576     for d in self.dependencies: | 
|   563         result.extend(d.subtree(include_all)) |   577       result.extend(d.subtree(include_all)) | 
|   564     return result |   578     return result | 
|   565  |   579  | 
|   566   def get_custom_deps(self, name, url): |   580   def get_custom_deps(self, name, url): | 
|   567     """Returns a custom deps if applicable.""" |   581     """Returns a custom deps if applicable.""" | 
|   568     if self.parent: |   582     if self.parent: | 
|   569       url = self.parent.get_custom_deps(name, url) |   583       url = self.parent.get_custom_deps(name, url) | 
|   570     # None is a valid return value to disable a dependency. |   584     # None is a valid return value to disable a dependency. | 
|   571     return self.custom_deps.get(name, url) |   585     return self.custom_deps.get(name, url) | 
|   572  |   586  | 
|   573   def file_list(self): |   587   def file_list(self): | 
|   574     result = self._file_list[:] |   588     result = self._file_list[:] | 
|   575     for d in self.dependencies: |   589     for d in self.dependencies: | 
|   576       result.extend(d.file_list()) |   590       result.extend(d.file_list()) | 
|   577     return result |   591     return result | 
|   578  |   592  | 
|   579   def __str__(self): |   593   def __str__(self): | 
|   580     out = [] |   594     out = [] | 
|   581     for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', |   595     for i in ('name', 'url', 'parsed_url', 'safesync_url', 'custom_deps', | 
|   582               'custom_vars', 'deps_hooks', '_file_list', 'processed', |   596               'custom_vars', 'deps_hooks', '_file_list', 'should_process', | 
|   583               'hooks_ran', 'deps_parsed', 'requirements', 'direct_reference'): |   597               'processed', 'hooks_ran', 'deps_parsed', 'requirements'): | 
|   584       # 'deps_file' |   598       # 'deps_file' | 
|   585       if self.__dict__[i]: |   599       if self.__dict__[i]: | 
|   586         out.append('%s: %s' % (i, self.__dict__[i])) |   600         out.append('%s: %s' % (i, self.__dict__[i])) | 
|   587  |   601  | 
|   588     for d in self.dependencies: |   602     for d in self.dependencies: | 
|   589       out.extend(['  ' + x for x in str(d).splitlines()]) |   603       out.extend(['  ' + x for x in str(d).splitlines()]) | 
|   590       out.append('') |   604       out.append('') | 
|   591     return '\n'.join(out) |   605     return '\n'.join(out) | 
|   592  |   606  | 
|   593   def __repr__(self): |   607   def __repr__(self): | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   648   DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ |   662   DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ | 
|   649 # Snapshot generated with gclient revinfo --snapshot |   663 # Snapshot generated with gclient revinfo --snapshot | 
|   650 solutions = [ |   664 solutions = [ | 
|   651 %(solution_list)s] |   665 %(solution_list)s] | 
|   652 """) |   666 """) | 
|   653  |   667  | 
|   654   def __init__(self, root_dir, options): |   668   def __init__(self, root_dir, options): | 
|   655     # Do not change previous behavior. Only solution level and immediate DEPS |   669     # Do not change previous behavior. Only solution level and immediate DEPS | 
|   656     # are processed. |   670     # are processed. | 
|   657     self._recursion_limit = 2 |   671     self._recursion_limit = 2 | 
|   658     Dependency.__init__(self, None, None, None, None, None, None, None) |   672     Dependency.__init__(self, None, None, None, None, None, None, None, True) | 
|   659     self._options = options |   673     self._options = options | 
|   660     if options.deps_os: |   674     if options.deps_os: | 
|   661       enforced_os = options.deps_os.split(',') |   675       enforced_os = options.deps_os.split(',') | 
|   662     else: |   676     else: | 
|   663       enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] |   677       enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] | 
|   664     if 'all' in enforced_os: |   678     if 'all' in enforced_os: | 
|   665       enforced_os = self.DEPS_OS_CHOICES.itervalues() |   679       enforced_os = self.DEPS_OS_CHOICES.itervalues() | 
|   666     self._enforced_os = list(set(enforced_os)) |   680     self._enforced_os = list(set(enforced_os)) | 
|   667     self._root_dir = root_dir |   681     self._root_dir = root_dir | 
|   668     self.config_content = None |   682     self.config_content = None | 
|   669  |   683  | 
|   670   def SetConfig(self, content): |   684   def SetConfig(self, content): | 
|   671     assert self.dependencies == [] |   685     assert self.dependencies == [] | 
|   672     config_dict = {} |   686     config_dict = {} | 
|   673     self.config_content = content |   687     self.config_content = content | 
|   674     try: |   688     try: | 
|   675       exec(content, config_dict) |   689       exec(content, config_dict) | 
|   676     except SyntaxError, e: |   690     except SyntaxError, e: | 
|   677       gclient_utils.SyntaxErrorToError('.gclient', e) |   691       gclient_utils.SyntaxErrorToError('.gclient', e) | 
|   678     for s in config_dict.get('solutions', []): |   692     for s in config_dict.get('solutions', []): | 
|   679       try: |   693       try: | 
 |   694         tree = dict((d.name, d) for d in self.tree(False)) | 
 |   695         if s['name'] in tree: | 
 |   696           raise gclient_utils.Error( | 
 |   697               'Dependency %s specified more than once in .gclient' % s['name']) | 
|   680         self.dependencies.append(Dependency( |   698         self.dependencies.append(Dependency( | 
|   681             self, s['name'], s['url'], |   699             self, s['name'], s['url'], | 
|   682             s.get('safesync_url', None), |   700             s.get('safesync_url', None), | 
|   683             s.get('custom_deps', {}), |   701             s.get('custom_deps', {}), | 
|   684             s.get('custom_vars', {}), |   702             s.get('custom_vars', {}), | 
|   685             None)) |   703             None, | 
 |   704             True)) | 
|   686       except KeyError: |   705       except KeyError: | 
|   687         raise gclient_utils.Error('Invalid .gclient file. Solution is ' |   706         raise gclient_utils.Error('Invalid .gclient file. Solution is ' | 
|   688                                   'incomplete: %s' % s) |   707                                   'incomplete: %s' % s) | 
|   689     # .gclient can have hooks. |   708     # .gclient can have hooks. | 
|   690     self.deps_hooks = config_dict.get('hooks', []) |   709     self.deps_hooks = config_dict.get('hooks', []) | 
|   691     self.direct_reference = True |   710     self.direct_reference = True | 
|   692     self.deps_parsed = True |   711     self.deps_parsed = True | 
|   693  |   712  | 
|   694   def SaveConfig(self): |   713   def SaveConfig(self): | 
|   695     gclient_utils.FileWrite(os.path.join(self.root_dir(), |   714     gclient_utils.FileWrite(os.path.join(self.root_dir(), | 
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   887       print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}) |   906       print(self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}) | 
|   888     else: |   907     else: | 
|   889       entries = {} |   908       entries = {} | 
|   890       for d in self.tree(False): |   909       for d in self.tree(False): | 
|   891         if self._options.actual: |   910         if self._options.actual: | 
|   892           entries[d.name] = GetURLAndRev(d) |   911           entries[d.name] = GetURLAndRev(d) | 
|   893         else: |   912         else: | 
|   894           entries[d.name] = d.parsed_url |   913           entries[d.name] = d.parsed_url | 
|   895       keys = sorted(entries.keys()) |   914       keys = sorted(entries.keys()) | 
|   896       for x in keys: |   915       for x in keys: | 
|   897         line = '%s: %s' % (x, entries[x]) |   916         print('%s: %s' % (x, entries[x])) | 
|   898         if x is not keys[-1]: |  | 
|   899           line += ';' |  | 
|   900         print line |  | 
|   901     logging.info(str(self)) |   917     logging.info(str(self)) | 
|   902  |   918  | 
|   903   def ParseDepsFile(self, direct_reference): |   919   def ParseDepsFile(self): | 
|   904     """No DEPS to parse for a .gclient file.""" |   920     """No DEPS to parse for a .gclient file.""" | 
|   905     raise gclient_utils.Error('Internal error') |   921     raise gclient_utils.Error('Internal error') | 
|   906  |   922  | 
|   907   def root_dir(self): |   923   def root_dir(self): | 
|   908     """Root directory of gclient checkout.""" |   924     """Root directory of gclient checkout.""" | 
|   909     return self._root_dir |   925     return self._root_dir | 
|   910  |   926  | 
|   911   def enforced_os(self): |   927   def enforced_os(self): | 
|   912     """What deps_os entries that are to be parsed.""" |   928     """What deps_os entries that are to be parsed.""" | 
|   913     return self._enforced_os |   929     return self._enforced_os | 
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1304     return CMDhelp(parser, argv) |  1320     return CMDhelp(parser, argv) | 
|  1305   except gclient_utils.Error, e: |  1321   except gclient_utils.Error, e: | 
|  1306     print >> sys.stderr, 'Error: %s' % str(e) |  1322     print >> sys.stderr, 'Error: %s' % str(e) | 
|  1307     return 1 |  1323     return 1 | 
|  1308  |  1324  | 
|  1309  |  1325  | 
|  1310 if '__main__' == __name__: |  1326 if '__main__' == __name__: | 
|  1311   sys.exit(Main(sys.argv[1:])) |  1327   sys.exit(Main(sys.argv[1:])) | 
|  1312  |  1328  | 
|  1313 # vim: ts=2:sw=2:tw=80:et: |  1329 # vim: ts=2:sw=2:tw=80:et: | 
| OLD | NEW |