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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 self.parsed_url = None | 146 self.parsed_url = None |
147 # These 2 are only set in .gclient and not in DEPS files. | 147 # These 2 are only set in .gclient and not in DEPS files. |
148 self.safesync_url = safesync_url | 148 self.safesync_url = safesync_url |
149 self.custom_vars = custom_vars or {} | 149 self.custom_vars = custom_vars or {} |
150 self.custom_deps = custom_deps or {} | 150 self.custom_deps = custom_deps or {} |
151 self.deps_hooks = [] | 151 self.deps_hooks = [] |
152 self.dependencies = [] | 152 self.dependencies = [] |
153 self.deps_file = deps_file or self.DEPS_FILE | 153 self.deps_file = deps_file or self.DEPS_FILE |
154 # A cache of the files affected by the current operation, necessary for | 154 # A cache of the files affected by the current operation, necessary for |
155 # hooks. | 155 # hooks. |
156 self.file_list = [] | 156 self._file_list = [] |
157 # If it is not set to True, the dependency wasn't processed for its child | 157 # If it is not set to True, the dependency wasn't processed for its child |
158 # dependency, i.e. its DEPS wasn't read. | 158 # dependency, i.e. its DEPS wasn't read. |
159 self.deps_parsed = False | 159 self.deps_parsed = False |
160 # A direct reference is dependency that is referenced by a deps, deps_os or | 160 # A direct reference is dependency that is referenced by a deps, deps_os or |
161 # solution. A indirect one is one that was loaded with From() or that | 161 # solution. A indirect one is one that was loaded with From() or that |
162 # exceeded recursion limit. | 162 # exceeded recursion limit. |
163 self.direct_reference = False | 163 self.direct_reference = False |
164 | 164 |
165 # Sanity checks | 165 # Sanity checks |
166 if not self.name and self.parent: | 166 if not self.name and self.parent: |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 raise | 297 raise |
298 self.dependencies.append(Dependency(self, name, url)) | 298 self.dependencies.append(Dependency(self, name, url)) |
299 # Sort by name. | 299 # Sort by name. |
300 self.dependencies.sort(key=lambda x: x.name) | 300 self.dependencies.sort(key=lambda x: x.name) |
301 logging.info('Loaded: %s' % str(self)) | 301 logging.info('Loaded: %s' % str(self)) |
302 | 302 |
303 def RunCommandRecursively(self, options, revision_overrides, | 303 def RunCommandRecursively(self, options, revision_overrides, |
304 command, args, pm): | 304 command, args, pm): |
305 """Runs 'command' before parsing the DEPS in case it's a initial checkout | 305 """Runs 'command' before parsing the DEPS in case it's a initial checkout |
306 or a revert.""" | 306 or a revert.""" |
307 assert self.file_list == [] | 307 assert self._file_list == [] |
308 # When running runhooks, there's no need to consult the SCM. | 308 # When running runhooks, there's no need to consult the SCM. |
309 # All known hooks are expected to run unconditionally regardless of working | 309 # All known hooks are expected to run unconditionally regardless of working |
310 # copy state, so skip the SCM status check. | 310 # copy state, so skip the SCM status check. |
311 run_scm = command not in ('runhooks', None) | 311 run_scm = command not in ('runhooks', None) |
312 self.LateOverride(self.url) | 312 self.LateOverride(self.url) |
313 if run_scm and self.parsed_url: | 313 if run_scm and self.parsed_url: |
314 if isinstance(self.parsed_url, self.FileImpl): | 314 if isinstance(self.parsed_url, self.FileImpl): |
315 # Special support for single-file checkout. | 315 # Special support for single-file checkout. |
316 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 316 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): |
317 options.revision = self.parsed_url.GetRevision() | 317 options.revision = self.parsed_url.GetRevision() |
318 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), | 318 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), |
319 self.root_dir(), | 319 self.root_dir(), |
320 self.name) | 320 self.name) |
321 scm.RunCommand('updatesingle', options, | 321 scm.RunCommand('updatesingle', options, |
322 args + [self.parsed_url.GetFilename()], | 322 args + [self.parsed_url.GetFilename()], |
323 self.file_list) | 323 self._file_list) |
324 else: | 324 else: |
325 options.revision = revision_overrides.get(self.name) | 325 options.revision = revision_overrides.get(self.name) |
326 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) | 326 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) |
327 scm.RunCommand(command, options, args, self.file_list) | 327 scm.RunCommand(command, options, args, self._file_list) |
328 self.file_list = [os.path.join(self.name, f.strip()) | 328 self._file_list = [os.path.join(self.name, f.strip()) |
329 for f in self.file_list] | 329 for f in self._file_list] |
330 options.revision = None | 330 options.revision = None |
331 if pm: | 331 if pm: |
332 # The + 1 comes from the fact that .gclient is considered a step in | 332 # The + 1 comes from the fact that .gclient is considered a step in |
333 # itself, .i.e. this code is called one time for the .gclient. This is not | 333 # itself, .i.e. this code is called one time for the .gclient. This is not |
334 # conceptually correct but it simplifies code. | 334 # conceptually correct but it simplifies code. |
335 pm._total = len(self.tree(False)) + 1 | 335 pm._total = len(self.tree(False)) + 1 |
336 pm.update() | 336 pm.update() |
337 if self.recursion_limit(): | 337 if self.recursion_limit(): |
338 # Then we can parse the DEPS file. | 338 # Then we can parse the DEPS file. |
339 self.ParseDepsFile(True) | 339 self.ParseDepsFile(True) |
(...skipping 18 matching lines...) Expand all Loading... |
358 # that. | 358 # that. |
359 if (options.force or | 359 if (options.force or |
360 isinstance(self.parsed_url, self.FileImpl) or | 360 isinstance(self.parsed_url, self.FileImpl) or |
361 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 361 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |
362 os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): | 362 os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): |
363 for hook_dict in self.deps_hooks: | 363 for hook_dict in self.deps_hooks: |
364 self._RunHookAction(hook_dict, []) | 364 self._RunHookAction(hook_dict, []) |
365 else: | 365 else: |
366 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 366 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
367 # Convert all absolute paths to relative. | 367 # Convert all absolute paths to relative. |
368 for i in range(len(self.file_list)): | 368 file_list = self.file_list() |
| 369 for i in range(len(file_list)): |
369 # It depends on the command being executed (like runhooks vs sync). | 370 # It depends on the command being executed (like runhooks vs sync). |
370 if not os.path.isabs(self.file_list[i]): | 371 if not os.path.isabs(file_list[i]): |
371 continue | 372 continue |
372 | 373 |
373 prefix = os.path.commonprefix([self.root_dir().lower(), | 374 prefix = os.path.commonprefix([self.root_dir().lower(), |
374 self.file_list[i].lower()]) | 375 file_list[i].lower()]) |
375 self.file_list[i] = self.file_list[i][len(prefix):] | 376 file_list[i] = file_list[i][len(prefix):] |
376 | 377 |
377 # Strip any leading path separators. | 378 # Strip any leading path separators. |
378 while (self.file_list[i].startswith('\\') or | 379 while (file_list[i].startswith('\\') or |
379 self.file_list[i].startswith('/')): | 380 file_list[i].startswith('/')): |
380 self.file_list[i] = self.file_list[i][1:] | 381 file_list[i] = file_list[i][1:] |
381 | 382 |
382 # Run hooks on the basis of whether the files from the gclient operation | 383 # Run hooks on the basis of whether the files from the gclient operation |
383 # match each hook's pattern. | 384 # match each hook's pattern. |
384 for hook_dict in self.deps_hooks: | 385 for hook_dict in self.deps_hooks: |
385 pattern = re.compile(hook_dict['pattern']) | 386 pattern = re.compile(hook_dict['pattern']) |
386 matching_file_list = [f for f in self.file_list if pattern.search(f)] | 387 matching_file_list = [f for f in file_list if pattern.search(f)] |
387 if matching_file_list: | 388 if matching_file_list: |
388 self._RunHookAction(hook_dict, matching_file_list) | 389 self._RunHookAction(hook_dict, matching_file_list) |
389 if self.recursion_limit(): | 390 if self.recursion_limit(): |
390 for s in self.dependencies: | 391 for s in self.dependencies: |
391 s.RunHooksRecursively(options) | 392 s.RunHooksRecursively(options) |
392 | 393 |
393 def _RunHookAction(self, hook_dict, matching_file_list): | 394 def _RunHookAction(self, hook_dict, matching_file_list): |
394 """Runs the action from a single hook.""" | 395 """Runs the action from a single hook.""" |
395 logging.info(hook_dict) | 396 logging.info(hook_dict) |
396 logging.info(matching_file_list) | 397 logging.info(matching_file_list) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 result.extend(d.subtree(force_all)) | 433 result.extend(d.subtree(force_all)) |
433 return result | 434 return result |
434 | 435 |
435 def get_custom_deps(self, name, url): | 436 def get_custom_deps(self, name, url): |
436 """Returns a custom deps if applicable.""" | 437 """Returns a custom deps if applicable.""" |
437 if self.parent: | 438 if self.parent: |
438 url = self.parent.get_custom_deps(name, url) | 439 url = self.parent.get_custom_deps(name, url) |
439 # None is a valid return value to disable a dependency. | 440 # None is a valid return value to disable a dependency. |
440 return self.custom_deps.get(name, url) | 441 return self.custom_deps.get(name, url) |
441 | 442 |
| 443 def file_list(self): |
| 444 result = self._file_list[:] |
| 445 for d in self.dependencies: |
| 446 result.extend(d.file_list()) |
| 447 return result |
| 448 |
442 def __str__(self): | 449 def __str__(self): |
443 out = [] | 450 out = [] |
444 for i in ('name', 'url', 'safesync_url', 'custom_deps', 'custom_vars', | 451 for i in ('name', 'url', 'safesync_url', 'custom_deps', 'custom_vars', |
445 'deps_hooks', 'file_list'): | 452 'deps_hooks', '_file_list'): |
446 # 'deps_file' | 453 # 'deps_file' |
447 if self.__dict__[i]: | 454 if self.__dict__[i]: |
448 out.append('%s: %s' % (i, self.__dict__[i])) | 455 out.append('%s: %s' % (i, self.__dict__[i])) |
449 | 456 |
450 for d in self.dependencies: | 457 for d in self.dependencies: |
451 out.extend([' ' + x for x in str(d).splitlines()]) | 458 out.extend([' ' + x for x in str(d).splitlines()]) |
452 out.append('') | 459 out.append('') |
453 return '\n'.join(out) | 460 return '\n'.join(out) |
454 | 461 |
455 def __repr__(self): | 462 def __repr__(self): |
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1151 return CMDhelp(parser, argv) | 1158 return CMDhelp(parser, argv) |
1152 except gclient_utils.Error, e: | 1159 except gclient_utils.Error, e: |
1153 print >> sys.stderr, 'Error: %s' % str(e) | 1160 print >> sys.stderr, 'Error: %s' % str(e) |
1154 return 1 | 1161 return 1 |
1155 | 1162 |
1156 | 1163 |
1157 if '__main__' == __name__: | 1164 if '__main__' == __name__: |
1158 sys.exit(Main(sys.argv[1:])) | 1165 sys.exit(Main(sys.argv[1:])) |
1159 | 1166 |
1160 # vim: ts=2:sw=2:tw=80:et: | 1167 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |