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 |