Chromium Code Reviews| 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 self.parent = parent | 159 self.parent = parent |
| 160 self.name = name | 160 self.name = name |
| 161 self.url = url | 161 self.url = url |
| 162 # These 2 are only set in .gclient and not in DEPS files. | 162 # These 2 are only set in .gclient and not in DEPS files. |
| 163 self.safesync_url = safesync_url | 163 self.safesync_url = safesync_url |
| 164 self.custom_vars = custom_vars or {} | 164 self.custom_vars = custom_vars or {} |
| 165 self.custom_deps = custom_deps or {} | 165 self.custom_deps = custom_deps or {} |
| 166 self.deps_hooks = [] | 166 self.deps_hooks = [] |
| 167 self.dependencies = [] | 167 self.dependencies = [] |
| 168 self.deps_file = deps_file or self.DEPS_FILE | 168 self.deps_file = deps_file or self.DEPS_FILE |
| 169 self.deps_parsed = False | |
| 170 self.direct_reference = False | |
| 171 | 169 |
| 172 # Sanity checks | 170 # Sanity checks |
| 173 if not self.name and self.parent: | 171 if not self.name and self.parent: |
| 174 raise gclient_utils.Error('Dependency without name') | 172 raise gclient_utils.Error('Dependency without name') |
| 175 if not isinstance(self.url, | 173 if not isinstance(self.url, |
| 176 (basestring, self.FromImpl, self.FileImpl, None.__class__)): | 174 (basestring, self.FromImpl, self.FileImpl, None.__class__)): |
| 177 raise gclient_utils.Error('dependency url must be either a string, None, ' | 175 raise gclient_utils.Error('dependency url must be either a string, None, ' |
| 178 'File() or From() instead of %s' % | 176 'File() or From() instead of %s' % |
| 179 self.url.__class__.__name__) | 177 self.url.__class__.__name__) |
| 180 if '/' in self.deps_file or '\\' in self.deps_file: | 178 if '/' in self.deps_file or '\\' in self.deps_file: |
| 181 raise gclient_utils.Error('deps_file name must not be a path, just a ' | 179 raise gclient_utils.Error('deps_file name must not be a path, just a ' |
| 182 'filename. %s' % self.deps_file) | 180 'filename. %s' % self.deps_file) |
| 183 | 181 |
| 184 def ParseDepsFile(self, direct_reference): | 182 def _ParseSolutionDeps(self, solution_name, solution_deps_content, |
| 185 """Parses the DEPS file for this dependency.""" | 183 custom_vars, parse_hooks): |
| 186 if direct_reference: | 184 """Parses the DEPS file for the specified solution. |
| 187 # Maybe it was referenced earlier by a From() keyword but it's now | |
| 188 # directly referenced. | |
| 189 self.direct_reference = direct_reference | |
| 190 if self.deps_parsed: | |
| 191 return | |
| 192 self.deps_parsed = True | |
| 193 filepath = os.path.join(self.root_dir(), self.name, self.deps_file) | |
| 194 if not os.path.isfile(filepath): | |
| 195 return | |
| 196 deps_content = gclient_utils.FileRead(filepath) | |
| 197 | 185 |
| 198 # Eval the content. | 186 Args: |
| 199 # One thing is unintuitive, vars= {} must happen before Var() use. | 187 solution_name: The name of the solution to query. |
| 188 solution_deps_content: Content of the DEPS file for the solution | |
| 189 custom_vars: A dict of vars to override any vars defined in the DEPS file. | |
|
bradn
2010/06/22 04:51:00
Missing some args here.
M-A Ruel
2010/06/22 14:29:11
Well, the goal is to delete this code if I can sto
| |
| 190 | |
| 191 Returns: | |
| 192 A dict mapping module names (as relative paths) to URLs or an empty | |
| 193 dict if the solution does not have a DEPS file. | |
| 194 """ | |
| 195 # Skip empty | |
| 196 if not solution_deps_content: | |
| 197 return {} | |
| 198 # Eval the content | |
| 200 local_scope = {} | 199 local_scope = {} |
| 201 var = self.VarImpl(self.custom_vars, local_scope) | 200 var = self.VarImpl(custom_vars, local_scope) |
| 202 global_scope = { | 201 global_scope = { |
| 203 'File': self.FileImpl, | 202 "File": self.FileImpl, |
| 204 'From': self.FromImpl, | 203 "From": self.FromImpl, |
| 205 'Var': var.Lookup, | 204 "Var": var.Lookup, |
| 206 'deps_os': {}, | 205 "deps_os": {}, |
| 207 } | 206 } |
| 208 exec(deps_content, global_scope, local_scope) | 207 exec(solution_deps_content, global_scope, local_scope) |
| 209 deps = local_scope.get('deps', {}) | 208 deps = local_scope.get("deps", {}) |
| 209 | |
| 210 # load os specific dependencies if defined. these dependencies may | 210 # load os specific dependencies if defined. these dependencies may |
| 211 # override or extend the values defined by the 'deps' member. | 211 # override or extend the values defined by the 'deps' member. |
| 212 if 'deps_os' in local_scope: | 212 if "deps_os" in local_scope: |
| 213 for deps_os_key in self.enforced_os(): | 213 if self._options.deps_os is not None: |
| 214 os_deps = local_scope['deps_os'].get(deps_os_key, {}) | 214 deps_to_include = self._options.deps_os.split(",") |
| 215 if len(self.enforced_os()) > 1: | 215 if "all" in deps_to_include: |
| 216 # Ignore any conflict when including deps for more than one | 216 deps_to_include = list(set(self.DEPS_OS_CHOICES.itervalues())) |
| 217 else: | |
| 218 deps_to_include = [self.DEPS_OS_CHOICES.get(sys.platform, "unix")] | |
| 219 | |
| 220 deps_to_include = set(deps_to_include) | |
| 221 for deps_os_key in deps_to_include: | |
| 222 os_deps = local_scope["deps_os"].get(deps_os_key, {}) | |
| 223 if len(deps_to_include) > 1: | |
| 224 # Ignore any overrides when including deps for more than one | |
| 217 # platform, so we collect the broadest set of dependencies available. | 225 # platform, so we collect the broadest set of dependencies available. |
| 218 # We may end up with the wrong revision of something for our | 226 # We may end up with the wrong revision of something for our |
| 219 # platform, but this is the best we can do. | 227 # platform, but this is the best we can do. |
| 220 deps.update([x for x in os_deps.items() if not x[0] in deps]) | 228 deps.update([x for x in os_deps.items() if not x[0] in deps]) |
| 221 else: | 229 else: |
| 222 deps.update(os_deps) | 230 deps.update(os_deps) |
| 223 | 231 |
| 224 self.deps_hooks.extend(local_scope.get('hooks', [])) | 232 if 'hooks' in local_scope and parse_hooks: |
| 225 | 233 # TODO(maruel): Temporary Hack. Since this function is misplaced, find the |
| 226 # If a line is in custom_deps, but not in the solution, we want to append | 234 # right 'self' to add the hooks. |
| 227 # this line to the solution. | 235 for d in self.dependencies: |
| 228 for d in self.custom_deps: | 236 if d.name == solution_name: |
| 229 if d not in deps: | 237 d.deps_hooks.extend(local_scope['hooks']) |
| 230 deps[d] = self.custom_deps[d] | 238 break |
| 231 | 239 |
| 232 # If use_relative_paths is set in the DEPS file, regenerate | 240 # If use_relative_paths is set in the DEPS file, regenerate |
| 233 # the dictionary using paths relative to the directory containing | 241 # the dictionary using paths relative to the directory containing |
| 234 # the DEPS file. | 242 # the DEPS file. |
| 235 use_relative_paths = local_scope.get('use_relative_paths', False) | 243 if local_scope.get('use_relative_paths'): |
| 236 if use_relative_paths: | |
| 237 rel_deps = {} | 244 rel_deps = {} |
| 238 for d, url in deps.items(): | 245 for d, url in deps.items(): |
| 239 # normpath is required to allow DEPS to use .. in their | 246 # normpath is required to allow DEPS to use .. in their |
| 240 # dependency local path. | 247 # dependency local path. |
| 241 rel_deps[os.path.normpath(os.path.join(self.name, d))] = url | 248 rel_deps[os.path.normpath(os.path.join(solution_name, d))] = url |
| 242 deps = rel_deps | 249 return rel_deps |
| 243 # TODO(maruel): Add these dependencies into self.dependencies. | 250 else: |
| 244 return deps | 251 return deps |
| 245 | 252 |
| 246 def _ParseAllDeps(self, solution_urls): | 253 def _ParseAllDeps(self, solution_urls, solution_deps_content): |
| 247 """Parse the complete list of dependencies for the client. | 254 """Parse the complete list of dependencies for the client. |
| 248 | 255 |
| 249 Args: | 256 Args: |
| 250 solution_urls: A dict mapping module names (as relative paths) to URLs | 257 solution_urls: A dict mapping module names (as relative paths) to URLs |
| 251 corresponding to the solutions specified by the client. This parameter | 258 corresponding to the solutions specified by the client. This parameter |
| 252 is passed as an optimization. | 259 is passed as an optimization. |
| 260 solution_deps_content: A dict mapping module names to the content | |
| 261 of their DEPS files | |
| 253 | 262 |
| 254 Returns: | 263 Returns: |
| 255 A dict mapping module names (as relative paths) to URLs corresponding | 264 A dict mapping module names (as relative paths) to URLs corresponding |
| 256 to the entire set of dependencies to checkout for the given client. | 265 to the entire set of dependencies to checkout for the given client. |
| 257 | 266 |
| 258 Raises: | 267 Raises: |
| 259 Error: If a dependency conflicts with another dependency or of a solution. | 268 Error: If a dependency conflicts with another dependency or of a solution. |
| 260 """ | 269 """ |
| 261 deps = {} | 270 deps = {} |
| 262 for solution in self.dependencies: | 271 for solution in self.dependencies: |
| 263 solution_deps = solution.ParseDepsFile(True) | 272 solution_deps = self._ParseSolutionDeps( |
| 273 solution.name, | |
| 274 solution_deps_content[solution.name], | |
| 275 solution.custom_vars, | |
| 276 True) | |
| 264 | 277 |
| 265 # If a line is in custom_deps, but not in the solution, we want to append | 278 # If a line is in custom_deps, but not in the solution, we want to append |
| 266 # this line to the solution. | 279 # this line to the solution. |
| 267 for d in solution.custom_deps: | 280 for d in solution.custom_deps: |
| 268 if d not in solution_deps: | 281 if d not in solution_deps: |
| 269 solution_deps[d] = solution.custom_deps[d] | 282 solution_deps[d] = solution.custom_deps[d] |
| 270 | 283 |
| 271 for d in solution_deps: | 284 for d in solution_deps: |
| 272 if d in solution.custom_deps: | 285 if d in solution.custom_deps: |
| 273 # Dependency is overriden. | 286 # Dependency is overriden. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 return | 372 return |
| 360 | 373 |
| 361 # Run hooks on the basis of whether the files from the gclient operation | 374 # Run hooks on the basis of whether the files from the gclient operation |
| 362 # match each hook's pattern. | 375 # match each hook's pattern. |
| 363 for hook_dict in hooks: | 376 for hook_dict in hooks: |
| 364 pattern = re.compile(hook_dict['pattern']) | 377 pattern = re.compile(hook_dict['pattern']) |
| 365 matching_file_list = [f for f in file_list if pattern.search(f)] | 378 matching_file_list = [f for f in file_list if pattern.search(f)] |
| 366 if matching_file_list: | 379 if matching_file_list: |
| 367 self._RunHookAction(hook_dict, matching_file_list) | 380 self._RunHookAction(hook_dict, matching_file_list) |
| 368 | 381 |
| 369 def root_dir(self): | |
| 370 return self.parent.root_dir() | |
| 371 | |
| 372 def enforced_os(self): | |
| 373 return self.parent.enforced_os() | |
| 374 | |
| 375 | 382 |
| 376 class GClient(Dependency): | 383 class GClient(Dependency): |
| 377 """Main gclient checkout root where .gclient resides.""" | 384 """Main gclient checkout root where .gclient resides.""" |
| 378 SUPPORTED_COMMANDS = [ | 385 SUPPORTED_COMMANDS = [ |
| 379 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update', | 386 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update', |
| 380 'runhooks' | 387 'runhooks' |
| 381 ] | 388 ] |
| 382 | 389 |
| 383 DEPS_OS_CHOICES = { | 390 DEPS_OS_CHOICES = { |
| 384 "win32": "win", | 391 "win32": "win", |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 414 | 421 |
| 415 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ | 422 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\ |
| 416 # Snapshot generated with gclient revinfo --snapshot | 423 # Snapshot generated with gclient revinfo --snapshot |
| 417 solutions = [ | 424 solutions = [ |
| 418 %(solution_list)s | 425 %(solution_list)s |
| 419 ] | 426 ] |
| 420 """) | 427 """) |
| 421 | 428 |
| 422 def __init__(self, root_dir, options): | 429 def __init__(self, root_dir, options): |
| 423 Dependency.__init__(self, None, None, None) | 430 Dependency.__init__(self, None, None, None) |
| 431 self._root_dir = root_dir | |
| 424 self._options = options | 432 self._options = options |
| 425 if options.deps_os: | |
| 426 enforced_os = options.deps_os.split(',') | |
| 427 else: | |
| 428 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] | |
| 429 if 'all' in enforced_os: | |
| 430 enforced_os = self.DEPS_OS_CHOICES.itervalues() | |
| 431 self._enforced_os = list(set(enforced_os)) | |
| 432 self._root_dir = root_dir | |
| 433 self.config_content = None | 433 self.config_content = None |
| 434 | 434 |
| 435 def SetConfig(self, content): | 435 def SetConfig(self, content): |
| 436 assert self.dependencies == [] | 436 assert self.dependencies == [] |
| 437 config_dict = {} | 437 config_dict = {} |
| 438 self.config_content = content | 438 self.config_content = content |
| 439 try: | 439 try: |
| 440 exec(content, config_dict) | 440 exec(content, config_dict) |
| 441 except SyntaxError, e: | 441 except SyntaxError, e: |
| 442 try: | 442 try: |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 if not self.dependencies: | 560 if not self.dependencies: |
| 561 raise gclient_utils.Error("No solution specified") | 561 raise gclient_utils.Error("No solution specified") |
| 562 revision_overrides = self._EnforceRevisions() | 562 revision_overrides = self._EnforceRevisions() |
| 563 | 563 |
| 564 # When running runhooks --force, there's no need to consult the SCM. | 564 # When running runhooks --force, there's no need to consult the SCM. |
| 565 # All known hooks are expected to run unconditionally regardless of working | 565 # All known hooks are expected to run unconditionally regardless of working |
| 566 # copy state, so skip the SCM status check. | 566 # copy state, so skip the SCM status check. |
| 567 run_scm = not (command == 'runhooks' and self._options.force) | 567 run_scm = not (command == 'runhooks' and self._options.force) |
| 568 | 568 |
| 569 entries = {} | 569 entries = {} |
| 570 entries_deps_content = {} | |
| 570 file_list = [] | 571 file_list = [] |
| 571 # Run on the base solutions first. | 572 # Run on the base solutions first. |
| 572 for solution in self.dependencies: | 573 for solution in self.dependencies: |
| 573 name = solution.name | 574 name = solution.name |
| 574 if name in entries: | 575 if name in entries: |
| 575 raise gclient_utils.Error("solution %s specified more than once" % name) | 576 raise gclient_utils.Error("solution %s specified more than once" % name) |
| 576 url = solution.url | 577 url = solution.url |
| 577 entries[name] = url | 578 entries[name] = url |
| 578 if run_scm and url: | 579 if run_scm and url: |
| 579 self._options.revision = revision_overrides.get(name) | 580 self._options.revision = revision_overrides.get(name) |
| 580 scm = gclient_scm.CreateSCM(url, self.root_dir(), name) | 581 scm = gclient_scm.CreateSCM(url, self.root_dir(), name) |
| 581 scm.RunCommand(command, self._options, args, file_list) | 582 scm.RunCommand(command, self._options, args, file_list) |
| 582 file_list = [os.path.join(name, f.strip()) for f in file_list] | 583 file_list = [os.path.join(name, f.strip()) for f in file_list] |
| 583 self._options.revision = None | 584 self._options.revision = None |
| 585 try: | |
| 586 deps_content = gclient_utils.FileRead( | |
| 587 os.path.join(self.root_dir(), name, solution.deps_file)) | |
| 588 except IOError, e: | |
| 589 if e.errno != errno.ENOENT: | |
| 590 raise | |
| 591 deps_content = "" | |
| 592 entries_deps_content[name] = deps_content | |
| 584 | 593 |
| 585 # Process the dependencies next (sort alphanumerically to ensure that | 594 # Process the dependencies next (sort alphanumerically to ensure that |
| 586 # containing directories get populated first and for readability) | 595 # containing directories get populated first and for readability) |
| 587 deps = self._ParseAllDeps(entries) | 596 deps = self._ParseAllDeps(entries, entries_deps_content) |
| 588 deps_to_process = deps.keys() | 597 deps_to_process = deps.keys() |
| 589 deps_to_process.sort() | 598 deps_to_process.sort() |
| 590 | 599 |
| 591 # First pass for direct dependencies. | 600 # First pass for direct dependencies. |
| 592 if command == 'update' and not self._options.verbose: | 601 if command == 'update' and not self._options.verbose: |
| 593 pm = Progress('Syncing projects', len(deps_to_process)) | 602 pm = Progress('Syncing projects', len(deps_to_process)) |
| 594 for d in deps_to_process: | 603 for d in deps_to_process: |
| 595 if command == 'update' and not self._options.verbose: | 604 if command == 'update' and not self._options.verbose: |
| 596 pm.update() | 605 pm.update() |
| 597 if type(deps[d]) == str: | 606 if type(deps[d]) == str: |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 609 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self.root_dir(), d) | 618 scm = gclient_scm.CreateSCM(file_dep.GetPath(), self.root_dir(), d) |
| 610 scm.RunCommand("updatesingle", self._options, | 619 scm.RunCommand("updatesingle", self._options, |
| 611 args + [file_dep.GetFilename()], file_list) | 620 args + [file_dep.GetFilename()], file_list) |
| 612 | 621 |
| 613 if command == 'update' and not self._options.verbose: | 622 if command == 'update' and not self._options.verbose: |
| 614 pm.end() | 623 pm.end() |
| 615 | 624 |
| 616 # Second pass for inherited deps (via the From keyword) | 625 # Second pass for inherited deps (via the From keyword) |
| 617 for d in deps_to_process: | 626 for d in deps_to_process: |
| 618 if isinstance(deps[d], self.FromImpl): | 627 if isinstance(deps[d], self.FromImpl): |
| 628 filename = os.path.join(self.root_dir(), | |
| 629 deps[d].module_name, | |
| 630 self.DEPS_FILE) | |
| 631 content = gclient_utils.FileRead(filename) | |
| 632 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, | |
| 633 False) | |
| 619 # Getting the URL from the sub_deps file can involve having to resolve | 634 # Getting the URL from the sub_deps file can involve having to resolve |
| 620 # a File() or having to resolve a relative URL. To resolve relative | 635 # a File() or having to resolve a relative URL. To resolve relative |
| 621 # URLs, we need to pass in the orignal sub deps URL. | 636 # URLs, we need to pass in the orignal sub deps URL. |
| 622 sub_deps_base_url = deps[deps[d].module_name] | 637 sub_deps_base_url = deps[deps[d].module_name] |
| 623 sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url | |
| 624 ).ParseDepsFile(False) | |
| 625 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) | 638 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) |
| 626 entries[d] = url | 639 entries[d] = url |
| 627 if run_scm: | 640 if run_scm: |
| 628 self._options.revision = revision_overrides.get(d) | 641 self._options.revision = revision_overrides.get(d) |
| 629 scm = gclient_scm.CreateSCM(url, self.root_dir(), d) | 642 scm = gclient_scm.CreateSCM(url, self.root_dir(), d) |
| 630 scm.RunCommand(command, self._options, args, file_list) | 643 scm.RunCommand(command, self._options, args, file_list) |
| 631 self._options.revision = None | 644 self._options.revision = None |
| 632 | 645 |
| 633 # Convert all absolute paths to relative. | 646 # Convert all absolute paths to relative. |
| 634 for i in range(len(file_list)): | 647 for i in range(len(file_list)): |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 702 def GetURLAndRev(name, original_url): | 715 def GetURLAndRev(name, original_url): |
| 703 url, _ = gclient_utils.SplitUrlRevision(original_url) | 716 url, _ = gclient_utils.SplitUrlRevision(original_url) |
| 704 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), name) | 717 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), name) |
| 705 return (url, scm.revinfo(self._options, [], None)) | 718 return (url, scm.revinfo(self._options, [], None)) |
| 706 | 719 |
| 707 # text of the snapshot gclient file | 720 # text of the snapshot gclient file |
| 708 new_gclient = "" | 721 new_gclient = "" |
| 709 # Dictionary of { path : SCM url } to ensure no duplicate solutions | 722 # Dictionary of { path : SCM url } to ensure no duplicate solutions |
| 710 solution_names = {} | 723 solution_names = {} |
| 711 entries = {} | 724 entries = {} |
| 725 entries_deps_content = {} | |
| 712 # Run on the base solutions first. | 726 # Run on the base solutions first. |
| 713 for solution in self.dependencies: | 727 for solution in self.dependencies: |
| 714 # Dictionary of { path : SCM url } to describe the gclient checkout | 728 # Dictionary of { path : SCM url } to describe the gclient checkout |
| 715 name = solution.name | 729 name = solution.name |
| 716 if name in solution_names: | 730 if name in solution_names: |
| 717 raise gclient_utils.Error("solution %s specified more than once" % name) | 731 raise gclient_utils.Error("solution %s specified more than once" % name) |
| 718 (url, rev) = GetURLAndRev(name, solution.url) | 732 (url, rev) = GetURLAndRev(name, solution.url) |
| 719 entries[name] = "%s@%s" % (url, rev) | 733 entries[name] = "%s@%s" % (url, rev) |
| 720 solution_names[name] = "%s@%s" % (url, rev) | 734 solution_names[name] = "%s@%s" % (url, rev) |
| 735 deps_file = solution.deps_file | |
| 736 if '/' in deps_file or '\\' in deps_file: | |
| 737 raise gclient_utils.Error('deps_file name must not be a path, just a ' | |
| 738 'filename.') | |
| 739 try: | |
| 740 deps_content = gclient_utils.FileRead( | |
| 741 os.path.join(self.root_dir(), name, deps_file)) | |
| 742 except IOError, e: | |
| 743 if e.errno != errno.ENOENT: | |
| 744 raise | |
| 745 deps_content = "" | |
| 746 entries_deps_content[name] = deps_content | |
| 721 | 747 |
| 722 # Process the dependencies next (sort alphanumerically to ensure that | 748 # Process the dependencies next (sort alphanumerically to ensure that |
| 723 # containing directories get populated first and for readability) | 749 # containing directories get populated first and for readability) |
| 724 deps = self._ParseAllDeps(entries) | 750 deps = self._ParseAllDeps(entries, entries_deps_content) |
| 725 deps_to_process = deps.keys() | 751 deps_to_process = deps.keys() |
| 726 deps_to_process.sort() | 752 deps_to_process.sort() |
| 727 | 753 |
| 728 # First pass for direct dependencies. | 754 # First pass for direct dependencies. |
| 729 for d in deps_to_process: | 755 for d in deps_to_process: |
| 730 if type(deps[d]) == str: | 756 if type(deps[d]) == str: |
| 731 (url, rev) = GetURLAndRev(d, deps[d]) | 757 (url, rev) = GetURLAndRev(d, deps[d]) |
| 732 entries[d] = "%s@%s" % (url, rev) | 758 entries[d] = "%s@%s" % (url, rev) |
| 733 | 759 |
| 734 # Second pass for inherited deps (via the From keyword) | 760 # Second pass for inherited deps (via the From keyword) |
| 735 for d in deps_to_process: | 761 for d in deps_to_process: |
| 736 if isinstance(deps[d], self.FromImpl): | 762 if isinstance(deps[d], self.FromImpl): |
| 737 deps_parent_url = entries[deps[d].module_name] | 763 deps_parent_url = entries[deps[d].module_name] |
| 738 if deps_parent_url.find("@") < 0: | 764 if deps_parent_url.find("@") < 0: |
| 739 raise gclient_utils.Error("From %s missing revisioned url" % | 765 raise gclient_utils.Error("From %s missing revisioned url" % |
| 740 deps[d].module_name) | 766 deps[d].module_name) |
| 741 sub_deps_base_url = deps[deps[d].module_name] | 767 content = gclient_utils.FileRead(os.path.join( |
| 742 sub_deps = Dependency(self, deps[d].module_name, sub_deps_base_url | 768 self.root_dir(), |
| 743 ).ParseDepsFile(False) | 769 deps[d].module_name, |
| 744 url = deps[d].GetUrl(d, sub_deps_base_url, self.root_dir(), sub_deps) | 770 self.DEPS_FILE)) |
| 745 (url, rev) = GetURLAndRev(d, url) | 771 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}, |
| 772 False) | |
| 773 (url, rev) = GetURLAndRev(d, sub_deps[d]) | |
| 746 entries[d] = "%s@%s" % (url, rev) | 774 entries[d] = "%s@%s" % (url, rev) |
| 747 | 775 |
| 748 # Build the snapshot configuration string | 776 # Build the snapshot configuration string |
| 749 if self._options.snapshot: | 777 if self._options.snapshot: |
| 750 url = entries.pop(name) | 778 url = entries.pop(name) |
| 751 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x]) | 779 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x]) |
| 752 for x in sorted(entries.keys())]) | 780 for x in sorted(entries.keys())]) |
| 753 | 781 |
| 754 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { | 782 new_gclient += self.DEFAULT_SNAPSHOT_SOLUTION_TEXT % { |
| 755 'solution_name': name, | 783 'solution_name': name, |
| 756 'solution_url': url, | 784 'solution_url': url, |
| 757 'safesync_url' : "", | 785 'safesync_url' : "", |
| 758 'solution_deps': custom_deps, | 786 'solution_deps': custom_deps, |
| 759 } | 787 } |
| 760 else: | 788 else: |
| 761 print(";\n".join(["%s: %s" % (x, entries[x]) | 789 print(";\n".join(["%s: %s" % (x, entries[x]) |
| 762 for x in sorted(entries.keys())])) | 790 for x in sorted(entries.keys())])) |
| 763 | 791 |
| 764 # Print the snapshot configuration file | 792 # Print the snapshot configuration file |
| 765 if self._options.snapshot: | 793 if self._options.snapshot: |
| 766 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} | 794 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} |
| 767 snapclient = GClient(self.root_dir(), self._options) | 795 snapclient = GClient(self.root_dir(), self._options) |
| 768 snapclient.SetConfig(config) | 796 snapclient.SetConfig(config) |
| 769 print(snapclient.config_content) | 797 print(snapclient.config_content) |
| 770 | 798 |
| 771 def root_dir(self): | 799 def root_dir(self): |
| 772 return self._root_dir | 800 return self._root_dir |
| 773 | 801 |
| 774 def enforced_os(self): | |
| 775 return self._enforced_os | |
| 776 | |
| 777 | 802 |
| 778 #### gclient commands. | 803 #### gclient commands. |
| 779 | 804 |
| 780 | 805 |
| 781 def CMDcleanup(parser, args): | 806 def CMDcleanup(parser, args): |
| 782 """Cleans up all working copies. | 807 """Cleans up all working copies. |
| 783 | 808 |
| 784 Mostly svn-specific. Simply runs 'svn cleanup' for each module. | 809 Mostly svn-specific. Simply runs 'svn cleanup' for each module. |
| 785 """ | 810 """ |
| 786 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', | 811 parser.add_option('--deps', dest='deps_os', metavar='OS_LIST', |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1120 return CMDhelp(parser, argv) | 1145 return CMDhelp(parser, argv) |
| 1121 except gclient_utils.Error, e: | 1146 except gclient_utils.Error, e: |
| 1122 print >> sys.stderr, 'Error: %s' % str(e) | 1147 print >> sys.stderr, 'Error: %s' % str(e) |
| 1123 return 1 | 1148 return 1 |
| 1124 | 1149 |
| 1125 | 1150 |
| 1126 if '__main__' == __name__: | 1151 if '__main__' == __name__: |
| 1127 sys.exit(Main(sys.argv[1:])) | 1152 sys.exit(Main(sys.argv[1:])) |
| 1128 | 1153 |
| 1129 # vim: ts=2:sw=2:tw=80:et: | 1154 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |