| OLD | NEW |
| 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 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 # on the level higher up in an orderly way. | 204 # on the level higher up in an orderly way. |
| 205 # This becomes messy for >2 depth as the DEPS file format is a dictionary, | 205 # This becomes messy for >2 depth as the DEPS file format is a dictionary, |
| 206 # thus unsorted, while the .gclient format is a list thus sorted. | 206 # thus unsorted, while the .gclient format is a list thus sorted. |
| 207 # | 207 # |
| 208 # * _recursion_limit is hard coded 2 and there is no hope to change this | 208 # * _recursion_limit is hard coded 2 and there is no hope to change this |
| 209 # value. | 209 # value. |
| 210 # | 210 # |
| 211 # Interestingly enough, the following condition only works in the case we | 211 # Interestingly enough, the following condition only works in the case we |
| 212 # want: self is a 2nd level node. 3nd level node wouldn't need this since | 212 # want: self is a 2nd level node. 3nd level node wouldn't need this since |
| 213 # they already have their parent as a requirement. | 213 # they already have their parent as a requirement. |
| 214 if self.parent in self.root_parent().dependencies: | 214 root_deps = self.root.dependencies |
| 215 root_deps = self.root_parent().dependencies | 215 if self.parent in root_deps: |
| 216 for i in range(0, root_deps.index(self.parent)): | 216 for i in range(0, root_deps.index(self.parent)): |
| 217 value = root_deps[i] | 217 value = root_deps[i] |
| 218 if value.name: | 218 if value.name: |
| 219 self._requirements.add(value.name) | 219 self._requirements.add(value.name) |
| 220 | 220 |
| 221 if isinstance(self.url, self.FromImpl): | 221 if isinstance(self.url, self.FromImpl): |
| 222 self._requirements.add(self.url.module_name) | 222 self._requirements.add(self.url.module_name) |
| 223 | 223 |
| 224 if self.name and self.should_process: | 224 if self.name and self.should_process: |
| 225 def yield_full_tree(root): | 225 def yield_full_tree(root): |
| 226 """Depth-first recursion.""" | 226 """Depth-first recursion.""" |
| 227 yield root | 227 yield root |
| 228 for i in root.dependencies: | 228 for i in root.dependencies: |
| 229 for j in yield_full_tree(i): | 229 for j in yield_full_tree(i): |
| 230 if j.should_process: | 230 if j.should_process: |
| 231 yield j | 231 yield j |
| 232 | 232 |
| 233 for obj in yield_full_tree(self.root_parent()): | 233 for obj in yield_full_tree(self.root): |
| 234 if obj is self or not obj.name: | 234 if obj is self or not obj.name: |
| 235 continue | 235 continue |
| 236 # Step 1: Find any requirements self may need. | 236 # Step 1: Find any requirements self may need. |
| 237 if self.name.startswith(posixpath.join(obj.name, '')): | 237 if self.name.startswith(posixpath.join(obj.name, '')): |
| 238 self._requirements.add(obj.name) | 238 self._requirements.add(obj.name) |
| 239 # Step 2: Find any requirements self may impose. | 239 # Step 2: Find any requirements self may impose. |
| 240 if obj.name.startswith(posixpath.join(self.name, '')): | 240 if obj.name.startswith(posixpath.join(self.name, '')): |
| 241 try: | 241 try: |
| 242 # Access to a protected member _requirements of a client class | 242 # Access to a protected member _requirements of a client class |
| 243 # pylint: disable=W0212 | 243 # pylint: disable=W0212 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 270 ref.ParseDepsFile() | 270 ref.ParseDepsFile() |
| 271 found_dep = None | 271 found_dep = None |
| 272 for d in ref.dependencies: | 272 for d in ref.dependencies: |
| 273 if d.name == sub_target: | 273 if d.name == sub_target: |
| 274 found_dep = d | 274 found_dep = d |
| 275 break | 275 break |
| 276 if not found_dep: | 276 if not found_dep: |
| 277 raise gclient_utils.Error( | 277 raise gclient_utils.Error( |
| 278 'Couldn\'t find %s in %s, referenced by %s (parent: %s)\n%s' % ( | 278 'Couldn\'t find %s in %s, referenced by %s (parent: %s)\n%s' % ( |
| 279 sub_target, ref.name, self.name, self.parent.name, | 279 sub_target, ref.name, self.name, self.parent.name, |
| 280 str(self.root_parent()))) | 280 str(self.root))) |
| 281 | 281 |
| 282 # Call LateOverride() again. | 282 # Call LateOverride() again. |
| 283 parsed_url = found_dep.LateOverride(found_dep.url) | 283 parsed_url = found_dep.LateOverride(found_dep.url) |
| 284 logging.info('%s, %s to %s' % (self.name, url, parsed_url)) | 284 logging.info('%s, %s to %s' % (self.name, url, parsed_url)) |
| 285 return parsed_url | 285 return parsed_url |
| 286 elif isinstance(url, basestring): | 286 elif isinstance(url, basestring): |
| 287 parsed_url = urlparse.urlparse(url) | 287 parsed_url = urlparse.urlparse(url) |
| 288 if not parsed_url[0]: | 288 if not parsed_url[0]: |
| 289 # A relative url. Fetch the real base. | 289 # A relative url. Fetch the real base. |
| 290 path = parsed_url[2] | 290 path = parsed_url[2] |
| 291 if not path.startswith('/'): | 291 if not path.startswith('/'): |
| 292 raise gclient_utils.Error( | 292 raise gclient_utils.Error( |
| 293 'relative DEPS entry \'%s\' must begin with a slash' % url) | 293 'relative DEPS entry \'%s\' must begin with a slash' % url) |
| 294 # Create a scm just to query the full url. | 294 # Create a scm just to query the full url. |
| 295 parent_url = self.parent.parsed_url | 295 parent_url = self.parent.parsed_url |
| 296 if isinstance(parent_url, self.FileImpl): | 296 if isinstance(parent_url, self.FileImpl): |
| 297 parent_url = parent_url.file_location | 297 parent_url = parent_url.file_location |
| 298 scm = gclient_scm.CreateSCM(parent_url, self.root_dir(), None) | 298 scm = gclient_scm.CreateSCM(parent_url, self.root.root_dir, None) |
| 299 parsed_url = scm.FullUrlForRelativeUrl(url) | 299 parsed_url = scm.FullUrlForRelativeUrl(url) |
| 300 else: | 300 else: |
| 301 parsed_url = url | 301 parsed_url = url |
| 302 logging.info('%s, %s -> %s' % (self.name, url, parsed_url)) | 302 logging.info('%s, %s -> %s' % (self.name, url, parsed_url)) |
| 303 return parsed_url | 303 return parsed_url |
| 304 elif isinstance(url, self.FileImpl): | 304 elif isinstance(url, self.FileImpl): |
| 305 parsed_url = url | 305 parsed_url = url |
| 306 logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) | 306 logging.info('%s, %s -> %s (File)' % (self.name, url, parsed_url)) |
| 307 return parsed_url | 307 return parsed_url |
| 308 elif url is None: | 308 elif url is None: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 319 self.deps_parsed = True | 319 self.deps_parsed = True |
| 320 # One thing is unintuitive, vars= {} must happen before Var() use. | 320 # One thing is unintuitive, vars= {} must happen before Var() use. |
| 321 local_scope = {} | 321 local_scope = {} |
| 322 var = self.VarImpl(self.custom_vars, local_scope) | 322 var = self.VarImpl(self.custom_vars, local_scope) |
| 323 global_scope = { | 323 global_scope = { |
| 324 'File': self.FileImpl, | 324 'File': self.FileImpl, |
| 325 'From': self.FromImpl, | 325 'From': self.FromImpl, |
| 326 'Var': var.Lookup, | 326 'Var': var.Lookup, |
| 327 'deps_os': {}, | 327 'deps_os': {}, |
| 328 } | 328 } |
| 329 filepath = os.path.join(self.root_dir(), self.name, self.deps_file) | 329 filepath = os.path.join(self.root.root_dir, self.name, self.deps_file) |
| 330 if not os.path.isfile(filepath): | 330 if not os.path.isfile(filepath): |
| 331 logging.info('%s: No %s file found at %s' % (self.name, self.deps_file, | 331 logging.info('%s: No %s file found at %s' % (self.name, self.deps_file, |
| 332 filepath)) | 332 filepath)) |
| 333 else: | 333 else: |
| 334 deps_content = gclient_utils.FileRead(filepath) | 334 deps_content = gclient_utils.FileRead(filepath) |
| 335 logging.debug(deps_content) | 335 logging.debug(deps_content) |
| 336 # Eval the content. | 336 # Eval the content. |
| 337 try: | 337 try: |
| 338 exec(deps_content, global_scope, local_scope) | 338 exec(deps_content, global_scope, local_scope) |
| 339 except SyntaxError, e: | 339 except SyntaxError, e: |
| 340 gclient_utils.SyntaxErrorToError(filepath, e) | 340 gclient_utils.SyntaxErrorToError(filepath, e) |
| 341 deps = local_scope.get('deps', {}) | 341 deps = local_scope.get('deps', {}) |
| 342 # load os specific dependencies if defined. these dependencies may | 342 # load os specific dependencies if defined. these dependencies may |
| 343 # override or extend the values defined by the 'deps' member. | 343 # override or extend the values defined by the 'deps' member. |
| 344 if 'deps_os' in local_scope: | 344 if 'deps_os' in local_scope: |
| 345 for deps_os_key in self.enforced_os(): | 345 for deps_os_key in self.root.enforced_os: |
| 346 os_deps = local_scope['deps_os'].get(deps_os_key, {}) | 346 os_deps = local_scope['deps_os'].get(deps_os_key, {}) |
| 347 if len(self.enforced_os()) > 1: | 347 if len(self.root.enforced_os) > 1: |
| 348 # Ignore any conflict when including deps for more than one | 348 # Ignore any conflict when including deps for more than one |
| 349 # platform, so we collect the broadest set of dependencies | 349 # platform, so we collect the broadest set of dependencies |
| 350 # available. We may end up with the wrong revision of something for | 350 # available. We may end up with the wrong revision of something for |
| 351 # our platform, but this is the best we can do. | 351 # our platform, but this is the best we can do. |
| 352 deps.update([x for x in os_deps.items() if not x[0] in deps]) | 352 deps.update([x for x in os_deps.items() if not x[0] in deps]) |
| 353 else: | 353 else: |
| 354 deps.update(os_deps) | 354 deps.update(os_deps) |
| 355 | 355 |
| 356 self.deps_hooks.extend(local_scope.get('hooks', [])) | 356 self.deps_hooks.extend(local_scope.get('hooks', [])) |
| 357 | 357 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 # All known hooks are expected to run unconditionally regardless of working | 443 # All known hooks are expected to run unconditionally regardless of working |
| 444 # copy state, so skip the SCM status check. | 444 # copy state, so skip the SCM status check. |
| 445 run_scm = command not in ('runhooks', None) | 445 run_scm = command not in ('runhooks', None) |
| 446 self.parsed_url = self.LateOverride(self.url) | 446 self.parsed_url = self.LateOverride(self.url) |
| 447 if run_scm and self.parsed_url: | 447 if run_scm and self.parsed_url: |
| 448 if isinstance(self.parsed_url, self.FileImpl): | 448 if isinstance(self.parsed_url, self.FileImpl): |
| 449 # Special support for single-file checkout. | 449 # Special support for single-file checkout. |
| 450 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 450 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): |
| 451 options.revision = self.parsed_url.GetRevision() | 451 options.revision = self.parsed_url.GetRevision() |
| 452 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), | 452 scm = gclient_scm.SVNWrapper(self.parsed_url.GetPath(), |
| 453 self.root_dir(), | 453 self.root.root_dir, |
| 454 self.name) | 454 self.name) |
| 455 scm.RunCommand('updatesingle', options, | 455 scm.RunCommand('updatesingle', options, |
| 456 args + [self.parsed_url.GetFilename()], | 456 args + [self.parsed_url.GetFilename()], |
| 457 self._file_list) | 457 self._file_list) |
| 458 else: | 458 else: |
| 459 # Create a shallow copy to mutate revision. | 459 # Create a shallow copy to mutate revision. |
| 460 options = copy.copy(options) | 460 options = copy.copy(options) |
| 461 options.revision = revision_overrides.get(self.name) | 461 options.revision = revision_overrides.get(self.name) |
| 462 maybeGetParentRevision(options) | 462 maybeGetParentRevision(options) |
| 463 scm = gclient_scm.CreateSCM(self.parsed_url, self.root_dir(), self.name) | 463 scm = gclient_scm.CreateSCM( |
| 464 self.parsed_url, self.root.root_dir, self.name) |
| 464 scm.RunCommand(command, options, args, self._file_list) | 465 scm.RunCommand(command, options, args, self._file_list) |
| 465 maybeConvertToDateRevision(options) | 466 maybeConvertToDateRevision(options) |
| 466 self._file_list = [os.path.join(self.name, f.strip()) | 467 self._file_list = [os.path.join(self.name, f.strip()) |
| 467 for f in self._file_list] | 468 for f in self._file_list] |
| 468 self.processed = True | 469 self.processed = True |
| 469 if self.recursion_limit() > 0: | 470 if self.recursion_limit() > 0: |
| 470 # Then we can parse the DEPS file. | 471 # Then we can parse the DEPS file. |
| 471 self.ParseDepsFile() | 472 self.ParseDepsFile() |
| 472 | 473 |
| 473 # Parse the dependencies of this dependency. | 474 # Parse the dependencies of this dependency. |
| 474 for s in self.dependencies: | 475 for s in self.dependencies: |
| 475 work_queue.enqueue(s) | 476 work_queue.enqueue(s) |
| 476 | 477 |
| 477 def RunHooksRecursively(self, options): | 478 def RunHooksRecursively(self, options): |
| 478 """Evaluates all hooks, running actions as needed. run() | 479 """Evaluates all hooks, running actions as needed. run() |
| 479 must have been called before to load the DEPS.""" | 480 must have been called before to load the DEPS.""" |
| 480 assert self.hooks_ran == False | 481 assert self.hooks_ran == False |
| 481 if not self.should_process or self.recursion_limit() <= 0: | 482 if not self.should_process or self.recursion_limit() <= 0: |
| 482 # Don't run the hook when it is above recursion_limit. | 483 # Don't run the hook when it is above recursion_limit. |
| 483 return | 484 return |
| 484 # If "--force" was specified, run all hooks regardless of what files have | 485 # If "--force" was specified, run all hooks regardless of what files have |
| 485 # changed. | 486 # changed. |
| 486 if self.deps_hooks: | 487 if self.deps_hooks: |
| 487 # TODO(maruel): If the user is using git or git-svn, then we don't know | 488 # TODO(maruel): If the user is using git or git-svn, then we don't know |
| 488 # what files have changed so we always run all hooks. It'd be nice to fix | 489 # what files have changed so we always run all hooks. It'd be nice to fix |
| 489 # that. | 490 # that. |
| 490 if (options.force or | 491 if (options.force or |
| 491 isinstance(self.parsed_url, self.FileImpl) or | 492 isinstance(self.parsed_url, self.FileImpl) or |
| 492 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or | 493 gclient_scm.GetScmName(self.parsed_url) in ('git', None) or |
| 493 os.path.isdir(os.path.join(self.root_dir(), self.name, '.git'))): | 494 os.path.isdir(os.path.join(self.root.root_dir, self.name, '.git'))): |
| 494 for hook_dict in self.deps_hooks: | 495 for hook_dict in self.deps_hooks: |
| 495 self._RunHookAction(hook_dict, []) | 496 self._RunHookAction(hook_dict, []) |
| 496 else: | 497 else: |
| 497 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 498 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
| 498 # Convert all absolute paths to relative. | 499 # Convert all absolute paths to relative. |
| 499 file_list = self.file_list() | 500 file_list = self.file_list() |
| 500 for i in range(len(file_list)): | 501 for i in range(len(file_list)): |
| 501 # It depends on the command being executed (like runhooks vs sync). | 502 # It depends on the command being executed (like runhooks vs sync). |
| 502 if not os.path.isabs(file_list[i]): | 503 if not os.path.isabs(file_list[i]): |
| 503 continue | 504 continue |
| 504 | 505 |
| 505 prefix = os.path.commonprefix([self.root_dir().lower(), | 506 prefix = os.path.commonprefix([self.root.root_dir.lower(), |
| 506 file_list[i].lower()]) | 507 file_list[i].lower()]) |
| 507 file_list[i] = file_list[i][len(prefix):] | 508 file_list[i] = file_list[i][len(prefix):] |
| 508 | 509 |
| 509 # Strip any leading path separators. | 510 # Strip any leading path separators. |
| 510 while (file_list[i].startswith('\\') or | 511 while (file_list[i].startswith('\\') or |
| 511 file_list[i].startswith('/')): | 512 file_list[i].startswith('/')): |
| 512 file_list[i] = file_list[i][1:] | 513 file_list[i] = file_list[i][1:] |
| 513 | 514 |
| 514 # Run hooks on the basis of whether the files from the gclient operation | 515 # Run hooks on the basis of whether the files from the gclient operation |
| 515 # match each hook's pattern. | 516 # match each hook's pattern. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 535 # Python script. Run it by starting a new copy of the same | 536 # Python script. Run it by starting a new copy of the same |
| 536 # interpreter. | 537 # interpreter. |
| 537 command[0] = sys.executable | 538 command[0] = sys.executable |
| 538 | 539 |
| 539 if '$matching_files' in command: | 540 if '$matching_files' in command: |
| 540 splice_index = command.index('$matching_files') | 541 splice_index = command.index('$matching_files') |
| 541 command[splice_index:splice_index + 1] = matching_file_list | 542 command[splice_index:splice_index + 1] = matching_file_list |
| 542 | 543 |
| 543 try: | 544 try: |
| 544 gclient_utils.CheckCallAndFilterAndHeader( | 545 gclient_utils.CheckCallAndFilterAndHeader( |
| 545 command, cwd=self.root_dir(), always=True) | 546 command, cwd=self.root.root_dir, always=True) |
| 546 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 547 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 547 # Use a discrete exit status code of 2 to indicate that a hook action | 548 # Use a discrete exit status code of 2 to indicate that a hook action |
| 548 # failed. Users of this script may wish to treat hook action failures | 549 # failed. Users of this script may wish to treat hook action failures |
| 549 # differently from VC failures. | 550 # differently from VC failures. |
| 550 print >> sys.stderr, 'Error: %s' % str(e) | 551 print >> sys.stderr, 'Error: %s' % str(e) |
| 551 sys.exit(2) | 552 sys.exit(2) |
| 552 | 553 |
| 553 def root_dir(self): | |
| 554 return self.parent.root_dir() | |
| 555 | |
| 556 def enforced_os(self): | |
| 557 return self.parent.enforced_os() | |
| 558 | |
| 559 def recursion_limit(self): | 554 def recursion_limit(self): |
| 560 return self.parent.recursion_limit() - 1 | 555 return self.parent.recursion_limit() - 1 |
| 561 | 556 |
| 562 def tree(self, include_all): | 557 def tree(self, include_all): |
| 563 return self.parent.tree(include_all) | 558 return self.parent.tree(include_all) |
| 564 | 559 |
| 565 def subtree(self, include_all): | 560 def subtree(self, include_all): |
| 566 """Breadth first""" | 561 """Breadth first""" |
| 567 result = [] | 562 result = [] |
| 568 for d in self.dependencies: | 563 for d in self.dependencies: |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 | 603 |
| 609 def hierarchy(self): | 604 def hierarchy(self): |
| 610 """Returns a human-readable hierarchical reference to a Dependency.""" | 605 """Returns a human-readable hierarchical reference to a Dependency.""" |
| 611 out = '%s(%s)' % (self.name, self.url) | 606 out = '%s(%s)' % (self.name, self.url) |
| 612 i = self.parent | 607 i = self.parent |
| 613 while i and i.name: | 608 while i and i.name: |
| 614 out = '%s(%s) -> %s' % (i.name, i.url, out) | 609 out = '%s(%s) -> %s' % (i.name, i.url, out) |
| 615 i = i.parent | 610 i = i.parent |
| 616 return out | 611 return out |
| 617 | 612 |
| 618 def root_parent(self): | 613 @property |
| 619 """Returns the root object, normally a GClient object.""" | 614 def root(self): |
| 620 d = self | 615 """Returns the root node, a GClient object.""" |
| 621 while d.parent: | 616 if not self.parent: |
| 622 d = d.parent | 617 # This line is to signal pylint that it could be a GClient instance. |
| 623 return d | 618 return self or GClient(None, None) |
| 619 return self.parent.root |
| 624 | 620 |
| 625 | 621 |
| 626 class GClient(Dependency): | 622 class GClient(Dependency): |
| 627 """Object that represent a gclient checkout. A tree of Dependency(), one per | 623 """Object that represent a gclient checkout. A tree of Dependency(), one per |
| 628 solution or DEPS entry.""" | 624 solution or DEPS entry.""" |
| 629 | 625 |
| 630 DEPS_OS_CHOICES = { | 626 DEPS_OS_CHOICES = { |
| 631 "win32": "win", | 627 "win32": "win", |
| 632 "win": "win", | 628 "win": "win", |
| 633 "cygwin": "win", | 629 "cygwin": "win", |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 self._recursion_limit = 2 | 669 self._recursion_limit = 2 |
| 674 Dependency.__init__(self, None, None, None, None, None, None, 'unused', | 670 Dependency.__init__(self, None, None, None, None, None, None, 'unused', |
| 675 True) | 671 True) |
| 676 self._options = options | 672 self._options = options |
| 677 if options.deps_os: | 673 if options.deps_os: |
| 678 enforced_os = options.deps_os.split(',') | 674 enforced_os = options.deps_os.split(',') |
| 679 else: | 675 else: |
| 680 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] | 676 enforced_os = [self.DEPS_OS_CHOICES.get(sys.platform, 'unix')] |
| 681 if 'all' in enforced_os: | 677 if 'all' in enforced_os: |
| 682 enforced_os = self.DEPS_OS_CHOICES.itervalues() | 678 enforced_os = self.DEPS_OS_CHOICES.itervalues() |
| 683 self._enforced_os = list(set(enforced_os)) | 679 self._enforced_os = tuple(set(enforced_os)) |
| 684 self._root_dir = root_dir | 680 self._root_dir = root_dir |
| 685 self.config_content = None | 681 self.config_content = None |
| 686 | 682 |
| 687 def SetConfig(self, content): | 683 def SetConfig(self, content): |
| 688 assert self.dependencies == [] | 684 assert self.dependencies == [] |
| 689 config_dict = {} | 685 config_dict = {} |
| 690 self.config_content = content | 686 self.config_content = content |
| 691 try: | 687 try: |
| 692 exec(content, config_dict) | 688 exec(content, config_dict) |
| 693 except SyntaxError, e: | 689 except SyntaxError, e: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 706 s.get('deps_file', 'DEPS'), | 702 s.get('deps_file', 'DEPS'), |
| 707 True)) | 703 True)) |
| 708 except KeyError: | 704 except KeyError: |
| 709 raise gclient_utils.Error('Invalid .gclient file. Solution is ' | 705 raise gclient_utils.Error('Invalid .gclient file. Solution is ' |
| 710 'incomplete: %s' % s) | 706 'incomplete: %s' % s) |
| 711 # .gclient can have hooks. | 707 # .gclient can have hooks. |
| 712 self.deps_hooks = config_dict.get('hooks', []) | 708 self.deps_hooks = config_dict.get('hooks', []) |
| 713 self.deps_parsed = True | 709 self.deps_parsed = True |
| 714 | 710 |
| 715 def SaveConfig(self): | 711 def SaveConfig(self): |
| 716 gclient_utils.FileWrite(os.path.join(self.root_dir(), | 712 gclient_utils.FileWrite(os.path.join(self.root_dir, |
| 717 self._options.config_filename), | 713 self._options.config_filename), |
| 718 self.config_content) | 714 self.config_content) |
| 719 | 715 |
| 720 @staticmethod | 716 @staticmethod |
| 721 def LoadCurrentConfig(options): | 717 def LoadCurrentConfig(options): |
| 722 """Searches for and loads a .gclient file relative to the current working | 718 """Searches for and loads a .gclient file relative to the current working |
| 723 dir. Returns a GClient object.""" | 719 dir. Returns a GClient object.""" |
| 724 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename) | 720 path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename) |
| 725 if not path: | 721 if not path: |
| 726 return None | 722 return None |
| (...skipping 18 matching lines...) Expand all Loading... |
| 745 """ | 741 """ |
| 746 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It | 742 # Sometimes pprint.pformat will use {', sometimes it'll use { ' ... It |
| 747 # makes testing a bit too fun. | 743 # makes testing a bit too fun. |
| 748 result = 'entries = {\n' | 744 result = 'entries = {\n' |
| 749 for entry in self.tree(False): | 745 for entry in self.tree(False): |
| 750 # Skip over File() dependencies as we can't version them. | 746 # Skip over File() dependencies as we can't version them. |
| 751 if not isinstance(entry.parsed_url, self.FileImpl): | 747 if not isinstance(entry.parsed_url, self.FileImpl): |
| 752 result += ' %s: %s,\n' % (pprint.pformat(entry.name), | 748 result += ' %s: %s,\n' % (pprint.pformat(entry.name), |
| 753 pprint.pformat(entry.parsed_url)) | 749 pprint.pformat(entry.parsed_url)) |
| 754 result += '}\n' | 750 result += '}\n' |
| 755 file_path = os.path.join(self.root_dir(), self._options.entries_filename) | 751 file_path = os.path.join(self.root_dir, self._options.entries_filename) |
| 756 logging.info(result) | 752 logging.info(result) |
| 757 gclient_utils.FileWrite(file_path, result) | 753 gclient_utils.FileWrite(file_path, result) |
| 758 | 754 |
| 759 def _ReadEntries(self): | 755 def _ReadEntries(self): |
| 760 """Read the .gclient_entries file for the given client. | 756 """Read the .gclient_entries file for the given client. |
| 761 | 757 |
| 762 Returns: | 758 Returns: |
| 763 A sequence of solution names, which will be empty if there is the | 759 A sequence of solution names, which will be empty if there is the |
| 764 entries file hasn't been created yet. | 760 entries file hasn't been created yet. |
| 765 """ | 761 """ |
| 766 scope = {} | 762 scope = {} |
| 767 filename = os.path.join(self.root_dir(), self._options.entries_filename) | 763 filename = os.path.join(self.root_dir, self._options.entries_filename) |
| 768 if not os.path.exists(filename): | 764 if not os.path.exists(filename): |
| 769 return {} | 765 return {} |
| 770 try: | 766 try: |
| 771 exec(gclient_utils.FileRead(filename), scope) | 767 exec(gclient_utils.FileRead(filename), scope) |
| 772 except SyntaxError, e: | 768 except SyntaxError, e: |
| 773 gclient_utils.SyntaxErrorToError(filename, e) | 769 gclient_utils.SyntaxErrorToError(filename, e) |
| 774 return scope['entries'] | 770 return scope['entries'] |
| 775 | 771 |
| 776 def _EnforceRevisions(self): | 772 def _EnforceRevisions(self): |
| 777 """Checks for revision overrides.""" | 773 """Checks for revision overrides.""" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 # Notify the user if there is an orphaned entry in their working copy. | 831 # Notify the user if there is an orphaned entry in their working copy. |
| 836 # Only delete the directory if there are no changes in it, and | 832 # Only delete the directory if there are no changes in it, and |
| 837 # delete_unversioned_trees is set to true. | 833 # delete_unversioned_trees is set to true. |
| 838 entries = [i.name for i in self.tree(False) if i.url] | 834 entries = [i.name for i in self.tree(False) if i.url] |
| 839 for entry, prev_url in self._ReadEntries().iteritems(): | 835 for entry, prev_url in self._ReadEntries().iteritems(): |
| 840 if not prev_url: | 836 if not prev_url: |
| 841 # entry must have been overridden via .gclient custom_deps | 837 # entry must have been overridden via .gclient custom_deps |
| 842 continue | 838 continue |
| 843 # Fix path separator on Windows. | 839 # Fix path separator on Windows. |
| 844 entry_fixed = entry.replace('/', os.path.sep) | 840 entry_fixed = entry.replace('/', os.path.sep) |
| 845 e_dir = os.path.join(self.root_dir(), entry_fixed) | 841 e_dir = os.path.join(self.root_dir, entry_fixed) |
| 846 # Use entry and not entry_fixed there. | 842 # Use entry and not entry_fixed there. |
| 847 if entry not in entries and os.path.exists(e_dir): | 843 if entry not in entries and os.path.exists(e_dir): |
| 848 file_list = [] | 844 file_list = [] |
| 849 scm = gclient_scm.CreateSCM(prev_url, self.root_dir(), entry_fixed) | 845 scm = gclient_scm.CreateSCM(prev_url, self.root_dir, entry_fixed) |
| 850 scm.status(self._options, [], file_list) | 846 scm.status(self._options, [], file_list) |
| 851 modified_files = file_list != [] | 847 modified_files = file_list != [] |
| 852 if (not self._options.delete_unversioned_trees or | 848 if (not self._options.delete_unversioned_trees or |
| 853 (modified_files and not self._options.force)): | 849 (modified_files and not self._options.force)): |
| 854 # There are modified files in this entry. Keep warning until | 850 # There are modified files in this entry. Keep warning until |
| 855 # removed. | 851 # removed. |
| 856 print(('\nWARNING: \'%s\' is no longer part of this client. ' | 852 print(('\nWARNING: \'%s\' is no longer part of this client. ' |
| 857 'It is recommended that you manually remove it.\n') % | 853 'It is recommended that you manually remove it.\n') % |
| 858 entry_fixed) | 854 entry_fixed) |
| 859 else: | 855 else: |
| 860 # Delete the entry | 856 # Delete the entry |
| 861 print('\n________ deleting \'%s\' in \'%s\'' % ( | 857 print('\n________ deleting \'%s\' in \'%s\'' % ( |
| 862 entry_fixed, self.root_dir())) | 858 entry_fixed, self.root_dir)) |
| 863 gclient_utils.RemoveDirectory(e_dir) | 859 gclient_utils.RemoveDirectory(e_dir) |
| 864 # record the current list of entries for next time | 860 # record the current list of entries for next time |
| 865 self._SaveEntries() | 861 self._SaveEntries() |
| 866 return 0 | 862 return 0 |
| 867 | 863 |
| 868 def PrintRevInfo(self): | 864 def PrintRevInfo(self): |
| 869 if not self.dependencies: | 865 if not self.dependencies: |
| 870 raise gclient_utils.Error('No solution specified') | 866 raise gclient_utils.Error('No solution specified') |
| 871 # Load all the settings. | 867 # Load all the settings. |
| 872 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, None) | 868 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, None) |
| 873 for s in self.dependencies: | 869 for s in self.dependencies: |
| 874 work_queue.enqueue(s) | 870 work_queue.enqueue(s) |
| 875 work_queue.flush({}, None, [], options=self._options) | 871 work_queue.flush({}, None, [], options=self._options) |
| 876 | 872 |
| 877 def GetURLAndRev(dep): | 873 def GetURLAndRev(dep): |
| 878 """Returns the revision-qualified SCM url for a Dependency.""" | 874 """Returns the revision-qualified SCM url for a Dependency.""" |
| 879 if dep.parsed_url is None: | 875 if dep.parsed_url is None: |
| 880 return None | 876 return None |
| 881 if isinstance(dep.parsed_url, self.FileImpl): | 877 if isinstance(dep.parsed_url, self.FileImpl): |
| 882 original_url = dep.parsed_url.file_location | 878 original_url = dep.parsed_url.file_location |
| 883 else: | 879 else: |
| 884 original_url = dep.parsed_url | 880 original_url = dep.parsed_url |
| 885 url, _ = gclient_utils.SplitUrlRevision(original_url) | 881 url, _ = gclient_utils.SplitUrlRevision(original_url) |
| 886 scm = gclient_scm.CreateSCM(original_url, self.root_dir(), dep.name) | 882 scm = gclient_scm.CreateSCM(original_url, self.root_dir, dep.name) |
| 887 if not os.path.isdir(scm.checkout_path): | 883 if not os.path.isdir(scm.checkout_path): |
| 888 return None | 884 return None |
| 889 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) | 885 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) |
| 890 | 886 |
| 891 if self._options.snapshot: | 887 if self._options.snapshot: |
| 892 new_gclient = '' | 888 new_gclient = '' |
| 893 # First level at .gclient | 889 # First level at .gclient |
| 894 for d in self.dependencies: | 890 for d in self.dependencies: |
| 895 entries = {} | 891 entries = {} |
| 896 def GrabDeps(dep): | 892 def GrabDeps(dep): |
| (...skipping 27 matching lines...) Expand all Loading... |
| 924 entries[d.name] = d.parsed_url | 920 entries[d.name] = d.parsed_url |
| 925 keys = sorted(entries.keys()) | 921 keys = sorted(entries.keys()) |
| 926 for x in keys: | 922 for x in keys: |
| 927 print('%s: %s' % (x, entries[x])) | 923 print('%s: %s' % (x, entries[x])) |
| 928 logging.info(str(self)) | 924 logging.info(str(self)) |
| 929 | 925 |
| 930 def ParseDepsFile(self): | 926 def ParseDepsFile(self): |
| 931 """No DEPS to parse for a .gclient file.""" | 927 """No DEPS to parse for a .gclient file.""" |
| 932 raise gclient_utils.Error('Internal error') | 928 raise gclient_utils.Error('Internal error') |
| 933 | 929 |
| 930 @property |
| 934 def root_dir(self): | 931 def root_dir(self): |
| 935 """Root directory of gclient checkout.""" | 932 """Root directory of gclient checkout.""" |
| 936 return self._root_dir | 933 return self._root_dir |
| 937 | 934 |
| 935 @property |
| 938 def enforced_os(self): | 936 def enforced_os(self): |
| 939 """What deps_os entries that are to be parsed.""" | 937 """What deps_os entries that are to be parsed.""" |
| 940 return self._enforced_os | 938 return self._enforced_os |
| 941 | 939 |
| 942 def recursion_limit(self): | 940 def recursion_limit(self): |
| 943 """How recursive can each dependencies in DEPS file can load DEPS file.""" | 941 """How recursive can each dependencies in DEPS file can load DEPS file.""" |
| 944 return self._recursion_limit | 942 return self._recursion_limit |
| 945 | 943 |
| 946 def tree(self, include_all): | 944 def tree(self, include_all): |
| 947 """Returns a flat list of all the dependencies.""" | 945 """Returns a flat list of all the dependencies.""" |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 except (gclient_utils.Error, subprocess2.CalledProcessError), e: | 1363 except (gclient_utils.Error, subprocess2.CalledProcessError), e: |
| 1366 print >> sys.stderr, 'Error: %s' % str(e) | 1364 print >> sys.stderr, 'Error: %s' % str(e) |
| 1367 return 1 | 1365 return 1 |
| 1368 | 1366 |
| 1369 | 1367 |
| 1370 if '__main__' == __name__: | 1368 if '__main__' == __name__: |
| 1371 fix_encoding.fix_encoding() | 1369 fix_encoding.fix_encoding() |
| 1372 sys.exit(Main(sys.argv[1:])) | 1370 sys.exit(Main(sys.argv[1:])) |
| 1373 | 1371 |
| 1374 # vim: ts=2:sw=2:tw=80:et: | 1372 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |