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

Side by Side Diff: gclient.py

Issue 6598087: Fix parallelization of multiple solutions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Fix for python2.5 (verified) Created 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 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 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 elif var_name in self._local_scope.get("vars", {}): 134 elif var_name in self._local_scope.get("vars", {}):
135 return self._local_scope["vars"][var_name] 135 return self._local_scope["vars"][var_name]
136 raise gclient_utils.Error("Var is not defined: %s" % var_name) 136 raise gclient_utils.Error("Var is not defined: %s" % var_name)
137 137
138 138
139 class Dependency(GClientKeywords, gclient_utils.WorkItem): 139 class Dependency(GClientKeywords, gclient_utils.WorkItem):
140 """Object that represents a dependency checkout.""" 140 """Object that represents a dependency checkout."""
141 141
142 def __init__(self, parent, name, url, safesync_url, custom_deps, 142 def __init__(self, parent, name, url, safesync_url, custom_deps,
143 custom_vars, deps_file, should_process): 143 custom_vars, deps_file, should_process):
144 # Warning: this function can be called from any thread. Both
145 # self.dependencies and self.requirements are read and modified from
146 # multiple threads at the same time. Sad.
144 GClientKeywords.__init__(self) 147 GClientKeywords.__init__(self)
145 gclient_utils.WorkItem.__init__(self) 148 gclient_utils.WorkItem.__init__(self)
146 self.parent = parent 149 self.parent = parent
147 self.name = name 150 self.name = name
148 self.url = url 151 self.url = url
149 self.parsed_url = None 152 self.parsed_url = None
150 # These 2 are only set in .gclient and not in DEPS files. 153 # These 2 are only set in .gclient and not in DEPS files.
151 self.safesync_url = safesync_url 154 self.safesync_url = safesync_url
152 self.custom_vars = custom_vars or {} 155 self.custom_vars = custom_vars or {}
153 self.custom_deps = custom_deps or {} 156 self.custom_deps = custom_deps or {}
154 self.deps_hooks = [] 157 self.deps_hooks = []
155 self.dependencies = [] 158 self.dependencies = []
156 self.deps_file = deps_file 159 self.deps_file = deps_file
157 # A cache of the files affected by the current operation, necessary for 160 # A cache of the files affected by the current operation, necessary for
158 # hooks. 161 # hooks.
159 self._file_list = [] 162 self._file_list = []
160 # If it is not set to True, the dependency wasn't processed for its child 163 # If it is not set to True, the dependency wasn't processed for its child
161 # dependency, i.e. its DEPS wasn't read. 164 # dependency, i.e. its DEPS wasn't read.
162 self.deps_parsed = False 165 self.deps_parsed = False
163 # This dependency should be processed, i.e. checked out 166 # This dependency should be processed, i.e. checked out
164 self.should_process = should_process 167 self.should_process = should_process
165 # This dependency has been processed, i.e. checked out 168 # This dependency has been processed, i.e. checked out
166 self.processed = False 169 self.processed = False
167 # This dependency had its hook run 170 # This dependency had its hook run
168 self.hooks_ran = False 171 self.hooks_ran = False
169 # Required dependencies to run before running this one: 172 # Required dependencies to run before running this one:
170 self.requirements = [] 173 self.requirements = set()
171 if self.parent and self.parent.name: 174
172 self.requirements.append(self.parent.name) 175 self._FindDependencies()
173 if isinstance(self.url, self.FromImpl):
174 self.requirements.append(self.url.module_name)
175 176
176 # Sanity checks 177 # Sanity checks
177 if not self.name and self.parent: 178 if not self.name and self.parent:
178 raise gclient_utils.Error('Dependency without name') 179 raise gclient_utils.Error('Dependency without name')
179 if not isinstance(self.url, 180 if not isinstance(self.url,
180 (basestring, self.FromImpl, self.FileImpl, None.__class__)): 181 (basestring, self.FromImpl, self.FileImpl, None.__class__)):
181 raise gclient_utils.Error('dependency url must be either a string, None, ' 182 raise gclient_utils.Error('dependency url must be either a string, None, '
182 'File() or From() instead of %s' % 183 'File() or From() instead of %s' %
183 self.url.__class__.__name__) 184 self.url.__class__.__name__)
184 if '/' in self.deps_file or '\\' in self.deps_file: 185 if '/' in self.deps_file or '\\' in self.deps_file:
185 raise gclient_utils.Error('deps_file name must not be a path, just a ' 186 raise gclient_utils.Error('deps_file name must not be a path, just a '
186 'filename. %s' % self.deps_file) 187 'filename. %s' % self.deps_file)
187 188
189 def _FindDependencies(self):
190 """Setup self.requirements and find any other dependency who would have self
191 as a requirement.
192 """
193 # self.parent is implicitly a requirement. This will be recursive by
194 # definition.
195 if self.parent and self.parent.name:
196 self.requirements.add(self.parent.name)
197
198 # For a tree with at least 2 levels*, the leaf node needs to depend
199 # on the level higher up in an orderly way.
200 # This becomes messy for >2 depth as the DEPS file format is a dictionary,
201 # thus unsorted, while the .gclient format is a list thus sorted.
202 #
203 # * _recursion_limit is hard coded 2 and there is no hope to change this
204 # value.
205 #
206 # Interestingly enough, the following condition only works in the case we
207 # want: self is a 2nd level node. 3nd level node wouldn't need this since
208 # they already have their parent as a requirement.
209 if self.parent in self.root_parent().dependencies:
210 root_deps = self.root_parent().dependencies
211 for i in range(0, root_deps.index(self.parent)):
212 value = root_deps[i]
213 if value.name:
214 self.requirements.add(value.name)
215
216 if isinstance(self.url, self.FromImpl):
217 self.requirements.add(self.url.module_name)
218
219 if self.name:
220 def yield_full_tree(root):
221 """Depth-first recursion."""
222 yield root
223 for i in root.dependencies:
224 for j in yield_full_tree(i):
225 yield j
226
227 for obj in yield_full_tree(self.root_parent()):
228 if obj is self or not obj.name:
229 continue
230 # Step 1: Find any requirements self may need.
231 if self.name.startswith(posixpath.join(obj.name, '')):
232 self.requirements.add(obj.name)
233 # Step 2: Find any requirements self may impose.
234 if obj.name.startswith(posixpath.join(self.name, '')):
235 obj.requirements.add(self.name)
236
188 def LateOverride(self, url): 237 def LateOverride(self, url):
189 """Resolves the parsed url from url. 238 """Resolves the parsed url from url.
190 239
191 Manages From() keyword accordingly. Do not touch self.parsed_url nor 240 Manages From() keyword accordingly. Do not touch self.parsed_url nor
192 self.url because it may called with other urls due to From().""" 241 self.url because it may called with other urls due to From()."""
193 assert self.parsed_url == None or not self.should_process, self.parsed_url 242 assert self.parsed_url == None or not self.should_process, self.parsed_url
194 overriden_url = self.get_custom_deps(self.name, url) 243 overriden_url = self.get_custom_deps(self.name, url)
195 if overriden_url != url: 244 if overriden_url != url:
196 logging.info('%s, %s was overriden to %s' % (self.name, url, 245 logging.info('%s, %s was overriden to %s' % (self.name, url,
197 overriden_url)) 246 overriden_url))
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 maybeGetParentRevision(options) 448 maybeGetParentRevision(options)
400 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) 449 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name)
401 scm.RunCommand(command, options, args, self._file_list) 450 scm.RunCommand(command, options, args, self._file_list)
402 maybeConvertToDateRevision(options) 451 maybeConvertToDateRevision(options)
403 self._file_list = [os.path.join(self.name, f.strip()) 452 self._file_list = [os.path.join(self.name, f.strip())
404 for f in self._file_list] 453 for f in self._file_list]
405 self.processed = True 454 self.processed = True
406 if self.recursion_limit() > 0: 455 if self.recursion_limit() > 0:
407 # Then we can parse the DEPS file. 456 # Then we can parse the DEPS file.
408 self.ParseDepsFile() 457 self.ParseDepsFile()
409 # Adjust the implicit dependency requirement; e.g. if a DEPS file contains
410 # both src/foo and src/foo/bar, src/foo/bar is implicitly dependent of
411 # src/foo. Yes, it's O(n^2)... It's important to do that before
412 # enqueueing them.
413 for s in self.dependencies:
414 for s2 in self.dependencies:
415 if s is s2:
416 continue
417 if s.name.startswith(posixpath.join(s2.name, '')):
418 s.requirements.append(s2.name)
419 458
420 # Parse the dependencies of this dependency. 459 # Parse the dependencies of this dependency.
421 for s in self.dependencies: 460 for s in self.dependencies:
422 work_queue.enqueue(s) 461 work_queue.enqueue(s)
423 462
424 def RunHooksRecursively(self, options): 463 def RunHooksRecursively(self, options):
425 """Evaluates all hooks, running actions as needed. run() 464 """Evaluates all hooks, running actions as needed. run()
426 must have been called before to load the DEPS.""" 465 must have been called before to load the DEPS."""
427 assert self.hooks_ran == False 466 assert self.hooks_ran == False
428 if not self.should_process or self.recursion_limit() <= 0: 467 if not self.should_process or self.recursion_limit() <= 0:
(...skipping 879 matching lines...) Expand 10 before | Expand all | Expand 10 after
1308 except (gclient_utils.Error, subprocess2.CalledProcessError), e: 1347 except (gclient_utils.Error, subprocess2.CalledProcessError), e:
1309 print >> sys.stderr, 'Error: %s' % str(e) 1348 print >> sys.stderr, 'Error: %s' % str(e)
1310 return 1 1349 return 1
1311 1350
1312 1351
1313 if '__main__' == __name__: 1352 if '__main__' == __name__:
1314 fix_encoding.fix_encoding() 1353 fix_encoding.fix_encoding()
1315 sys.exit(Main(sys.argv[1:])) 1354 sys.exit(Main(sys.argv[1:]))
1316 1355
1317 # vim: ts=2:sw=2:tw=80:et: 1356 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698