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

Side by Side Diff: gclient.py

Issue 7889047: Use properties for more members that do not change (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: rebase against head Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Meta checkout manager supporting both Subversion and GIT. 6 """Meta checkout manager supporting both Subversion and GIT.
7 7
8 Files 8 Files
9 .gclient : Current client configuration, written by 'config' command. 9 .gclient : Current client configuration, written by 'config' command.
10 Format is a Python script defining 'solutions', a list whose 10 Format is a Python script defining 'solutions', a list whose
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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
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
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:
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698