OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 # Files | 7 # Files |
8 # .gclient : Current client configuration, written by 'config' command. | 8 # .gclient : Current client configuration, written by 'config' command. |
9 # Format is a Python script defining 'solutions', a list whose | 9 # Format is a Python script defining 'solutions', a list whose |
10 # entries each are maps binding the strings "name" and "url" | 10 # entries each are maps binding the strings "name" and "url" |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 if not parsed_url[0]: | 437 if not parsed_url[0]: |
438 # A relative url. Fetch the real base. | 438 # A relative url. Fetch the real base. |
439 path = parsed_url[2] | 439 path = parsed_url[2] |
440 if not path.startswith('/'): | 440 if not path.startswith('/'): |
441 raise gclient_utils.Error( | 441 raise gclient_utils.Error( |
442 'relative DEPS entry \'%s\' must begin with a slash' % url) | 442 'relative DEPS entry \'%s\' must begin with a slash' % url) |
443 # Create a scm just to query the full url. | 443 # Create a scm just to query the full url. |
444 parent_url = self.parent.parsed_url | 444 parent_url = self.parent.parsed_url |
445 if isinstance(parent_url, self.FileImpl): | 445 if isinstance(parent_url, self.FileImpl): |
446 parent_url = parent_url.file_location | 446 parent_url = parent_url.file_location |
447 scm = gclient_scm.CreateSCM(parent_url, self.root.root_dir, None) | 447 scm = gclient_scm.CreateSCM( |
| 448 parent_url, self.root.root_dir, None, self.outbuf) |
448 parsed_url = scm.FullUrlForRelativeUrl(url) | 449 parsed_url = scm.FullUrlForRelativeUrl(url) |
449 else: | 450 else: |
450 parsed_url = url | 451 parsed_url = url |
451 logging.info( | 452 logging.info( |
452 'Dependency(%s).LateOverride(%s) -> %s' % | 453 'Dependency(%s).LateOverride(%s) -> %s' % |
453 (self.name, url, parsed_url)) | 454 (self.name, url, parsed_url)) |
454 return parsed_url | 455 return parsed_url |
455 | 456 |
456 if isinstance(url, self.FileImpl): | 457 if isinstance(url, self.FileImpl): |
457 logging.info( | 458 logging.info( |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
650 parsed_url = self.LateOverride(self.url) | 651 parsed_url = self.LateOverride(self.url) |
651 file_list = [] if not options.nohooks else None | 652 file_list = [] if not options.nohooks else None |
652 if run_scm and parsed_url: | 653 if run_scm and parsed_url: |
653 if isinstance(parsed_url, self.FileImpl): | 654 if isinstance(parsed_url, self.FileImpl): |
654 # Special support for single-file checkout. | 655 # Special support for single-file checkout. |
655 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): | 656 if not command in (None, 'cleanup', 'diff', 'pack', 'status'): |
656 # Sadly, pylint doesn't realize that parsed_url is of FileImpl. | 657 # Sadly, pylint doesn't realize that parsed_url is of FileImpl. |
657 # pylint: disable=E1103 | 658 # pylint: disable=E1103 |
658 options.revision = parsed_url.GetRevision() | 659 options.revision = parsed_url.GetRevision() |
659 self._used_scm = gclient_scm.SVNWrapper( | 660 self._used_scm = gclient_scm.SVNWrapper( |
660 parsed_url.GetPath(), self.root.root_dir, self.name) | 661 parsed_url.GetPath(), self.root.root_dir, self.name, |
| 662 out_cb=work_queue.out_cb) |
661 self._used_scm.RunCommand('updatesingle', | 663 self._used_scm.RunCommand('updatesingle', |
662 options, args + [parsed_url.GetFilename()], file_list) | 664 options, args + [parsed_url.GetFilename()], file_list) |
663 else: | 665 else: |
664 # Create a shallow copy to mutate revision. | 666 # Create a shallow copy to mutate revision. |
665 options = copy.copy(options) | 667 options = copy.copy(options) |
666 options.revision = revision_overrides.get(self.name) | 668 options.revision = revision_overrides.get(self.name) |
667 self.maybeGetParentRevision( | 669 self.maybeGetParentRevision( |
668 command, options, parsed_url, self.parent.name, revision_overrides) | 670 command, options, parsed_url, self.parent.name, revision_overrides) |
669 self._used_scm = gclient_scm.CreateSCM( | 671 self._used_scm = gclient_scm.CreateSCM( |
670 parsed_url, self.root.root_dir, self.name) | 672 parsed_url, self.root.root_dir, self.name, self.outbuf, |
| 673 out_cb=work_queue.out_cb) |
671 self._got_revision = self._used_scm.RunCommand(command, options, args, | 674 self._got_revision = self._used_scm.RunCommand(command, options, args, |
672 file_list) | 675 file_list) |
673 if file_list: | 676 if file_list: |
674 file_list = [os.path.join(self.name, f.strip()) for f in file_list] | 677 file_list = [os.path.join(self.name, f.strip()) for f in file_list] |
675 | 678 |
676 # TODO(phajdan.jr): We should know exactly when the paths are absolute. | 679 # TODO(phajdan.jr): We should know exactly when the paths are absolute. |
677 # Convert all absolute paths to relative. | 680 # Convert all absolute paths to relative. |
678 for i in range(len(file_list or [])): | 681 for i in range(len(file_list or [])): |
679 # It depends on the command being executed (like runhooks vs sync). | 682 # It depends on the command being executed (like runhooks vs sync). |
680 if not os.path.isabs(file_list[i]): | 683 if not os.path.isabs(file_list[i]): |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 """Git-specific path marshaling. It is optimized for git-grep.""" | 720 """Git-specific path marshaling. It is optimized for git-grep.""" |
718 | 721 |
719 def mod_path(git_pathspec): | 722 def mod_path(git_pathspec): |
720 match = re.match('^(\\S+?:)?([^\0]+)$', git_pathspec) | 723 match = re.match('^(\\S+?:)?([^\0]+)$', git_pathspec) |
721 modified_path = os.path.join(self.name, match.group(2)) | 724 modified_path = os.path.join(self.name, match.group(2)) |
722 branch = match.group(1) or '' | 725 branch = match.group(1) or '' |
723 return '%s%s' % (branch, modified_path) | 726 return '%s%s' % (branch, modified_path) |
724 | 727 |
725 match = re.match('^Binary file ([^\0]+) matches$', line) | 728 match = re.match('^Binary file ([^\0]+) matches$', line) |
726 if match: | 729 if match: |
727 print 'Binary file %s matches' % mod_path(match.group(1)) | 730 print 'Binary file %s matches\n' % mod_path(match.group(1)) |
728 return | 731 return |
729 | 732 |
730 items = line.split('\0') | 733 items = line.split('\0') |
731 if len(items) == 2 and items[1]: | 734 if len(items) == 2 and items[1]: |
732 print '%s : %s' % (mod_path(items[0]), items[1]) | 735 print '%s : %s' % (mod_path(items[0]), items[1]) |
733 elif len(items) >= 2: | 736 elif len(items) >= 2: |
734 # Multiple null bytes or a single trailing null byte indicate | 737 # Multiple null bytes or a single trailing null byte indicate |
735 # git is likely displaying filenames only (such as with -l) | 738 # git is likely displaying filenames only (such as with -l) |
736 print '\n'.join(mod_path(path) for path in items if path) | 739 print '\n'.join(mod_path(path) for path in items if path) |
737 else: | 740 else: |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 enforced_os = self.DEPS_OS_CHOICES.itervalues() | 1046 enforced_os = self.DEPS_OS_CHOICES.itervalues() |
1044 self._enforced_os = tuple(set(enforced_os)) | 1047 self._enforced_os = tuple(set(enforced_os)) |
1045 self._root_dir = root_dir | 1048 self._root_dir = root_dir |
1046 self.config_content = None | 1049 self.config_content = None |
1047 | 1050 |
1048 def _CheckConfig(self): | 1051 def _CheckConfig(self): |
1049 """Verify that the config matches the state of the existing checked-out | 1052 """Verify that the config matches the state of the existing checked-out |
1050 solutions.""" | 1053 solutions.""" |
1051 for dep in self.dependencies: | 1054 for dep in self.dependencies: |
1052 if dep.managed and dep.url: | 1055 if dep.managed and dep.url: |
1053 scm = gclient_scm.CreateSCM(dep.url, self.root_dir, dep.name) | 1056 scm = gclient_scm.CreateSCM( |
| 1057 dep.url, self.root_dir, dep.name, self.outbuf) |
1054 actual_url = scm.GetActualRemoteURL() | 1058 actual_url = scm.GetActualRemoteURL() |
1055 if actual_url and not scm.DoesRemoteURLMatch(): | 1059 if actual_url and not scm.DoesRemoteURLMatch(): |
1056 raise gclient_utils.Error(''' | 1060 raise gclient_utils.Error(''' |
1057 Your .gclient file seems to be broken. The requested URL is different from what | 1061 Your .gclient file seems to be broken. The requested URL is different from what |
1058 is actually checked out in %(checkout_path)s. | 1062 is actually checked out in %(checkout_path)s. |
1059 | 1063 |
1060 Expected: %(expected_url)s (%(expected_scm)s) | 1064 Expected: %(expected_url)s (%(expected_scm)s) |
1061 Actual: %(actual_url)s (%(actual_scm)s) | 1065 Actual: %(actual_url)s (%(actual_scm)s) |
1062 | 1066 |
1063 You should ensure that the URL listed in .gclient is correct and either change | 1067 You should ensure that the URL listed in .gclient is correct and either change |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 be invalid for the given |dep|.""" | 1228 be invalid for the given |dep|.""" |
1225 assert len(dep.safesync_url) > 0 | 1229 assert len(dep.safesync_url) > 0 |
1226 handle = urllib.urlopen(dep.safesync_url) | 1230 handle = urllib.urlopen(dep.safesync_url) |
1227 rev = handle.read().strip() | 1231 rev = handle.read().strip() |
1228 handle.close() | 1232 handle.close() |
1229 if not rev: | 1233 if not rev: |
1230 raise gclient_utils.Error( | 1234 raise gclient_utils.Error( |
1231 'It appears your safesync_url (%s) is not working properly\n' | 1235 'It appears your safesync_url (%s) is not working properly\n' |
1232 '(as it returned an empty response). Check your config.' % | 1236 '(as it returned an empty response). Check your config.' % |
1233 dep.safesync_url) | 1237 dep.safesync_url) |
1234 scm = gclient_scm.CreateSCM(dep.url, dep.root.root_dir, dep.name) | 1238 scm = gclient_scm.CreateSCM( |
| 1239 dep.url, dep.root.root_dir, dep.name, self.outbuf) |
1235 safe_rev = scm.GetUsableRev(rev, self._options) | 1240 safe_rev = scm.GetUsableRev(rev, self._options) |
1236 if self._options.verbose: | 1241 if self._options.verbose: |
1237 print('Using safesync_url revision: %s.\n' % safe_rev) | 1242 print('Using safesync_url revision: %s.\n' % safe_rev) |
1238 self._options.revisions.append('%s@%s' % (dep.name, safe_rev)) | 1243 self._options.revisions.append('%s@%s' % (dep.name, safe_rev)) |
1239 | 1244 |
1240 def RunOnDeps(self, command, args, ignore_requirements=False, progress=True): | 1245 def RunOnDeps(self, command, args, ignore_requirements=False, progress=True): |
1241 """Runs a command on each dependency in a client and its dependencies. | 1246 """Runs a command on each dependency in a client and its dependencies. |
1242 | 1247 |
1243 Args: | 1248 Args: |
1244 command: The command to use (e.g., 'status' or 'diff') | 1249 command: The command to use (e.g., 'status' or 'diff') |
(...skipping 10 matching lines...) Expand all Loading... |
1255 if command not in ('diff', 'recurse', 'runhooks', 'status'): | 1260 if command not in ('diff', 'recurse', 'runhooks', 'status'): |
1256 revision_overrides = self._EnforceRevisions() | 1261 revision_overrides = self._EnforceRevisions() |
1257 pm = None | 1262 pm = None |
1258 # Disable progress for non-tty stdout. | 1263 # Disable progress for non-tty stdout. |
1259 if (sys.stdout.isatty() and not self._options.verbose and progress): | 1264 if (sys.stdout.isatty() and not self._options.verbose and progress): |
1260 if command in ('update', 'revert'): | 1265 if command in ('update', 'revert'): |
1261 pm = Progress('Syncing projects', 1) | 1266 pm = Progress('Syncing projects', 1) |
1262 elif command == 'recurse': | 1267 elif command == 'recurse': |
1263 pm = Progress(' '.join(args), 1) | 1268 pm = Progress(' '.join(args), 1) |
1264 work_queue = gclient_utils.ExecutionQueue( | 1269 work_queue = gclient_utils.ExecutionQueue( |
1265 self._options.jobs, pm, ignore_requirements=ignore_requirements) | 1270 self._options.jobs, pm, ignore_requirements=ignore_requirements, |
| 1271 verbose=self._options.verbose) |
1266 for s in self.dependencies: | 1272 for s in self.dependencies: |
1267 work_queue.enqueue(s) | 1273 work_queue.enqueue(s) |
1268 work_queue.flush(revision_overrides, command, args, options=self._options) | 1274 work_queue.flush(revision_overrides, command, args, options=self._options) |
1269 | 1275 |
1270 # Once all the dependencies have been processed, it's now safe to run the | 1276 # Once all the dependencies have been processed, it's now safe to run the |
1271 # hooks. | 1277 # hooks. |
1272 if not self._options.nohooks: | 1278 if not self._options.nohooks: |
1273 self.RunHooksRecursively(self._options) | 1279 self.RunHooksRecursively(self._options) |
1274 | 1280 |
1275 if command == 'update': | 1281 if command == 'update': |
(...skipping 15 matching lines...) Expand all Loading... |
1291 def _IsParentOfAny(parent, path_list): | 1297 def _IsParentOfAny(parent, path_list): |
1292 parent_plus_slash = parent + '/' | 1298 parent_plus_slash = parent + '/' |
1293 return any( | 1299 return any( |
1294 path[:len(parent_plus_slash)] == parent_plus_slash | 1300 path[:len(parent_plus_slash)] == parent_plus_slash |
1295 for path in path_list) | 1301 for path in path_list) |
1296 | 1302 |
1297 # Use entry and not entry_fixed there. | 1303 # Use entry and not entry_fixed there. |
1298 if (entry not in entries and | 1304 if (entry not in entries and |
1299 (not any(path.startswith(entry + '/') for path in entries)) and | 1305 (not any(path.startswith(entry + '/') for path in entries)) and |
1300 os.path.exists(e_dir)): | 1306 os.path.exists(e_dir)): |
1301 scm = gclient_scm.CreateSCM(prev_url, self.root_dir, entry_fixed) | 1307 scm = gclient_scm.CreateSCM( |
| 1308 prev_url, self.root_dir, entry_fixed, self.outbuf) |
1302 | 1309 |
1303 # Check to see if this directory is now part of a higher-up checkout. | 1310 # Check to see if this directory is now part of a higher-up checkout. |
1304 if scm.GetCheckoutRoot() in full_entries: | 1311 if scm.GetCheckoutRoot() in full_entries: |
1305 logging.info('%s is part of a higher level checkout, not ' | 1312 logging.info('%s is part of a higher level checkout, not ' |
1306 'removing.', scm.GetCheckoutRoot()) | 1313 'removing.', scm.GetCheckoutRoot()) |
1307 continue | 1314 continue |
1308 | 1315 |
1309 file_list = [] | 1316 file_list = [] |
1310 scm.status(self._options, [], file_list) | 1317 scm.status(self._options, [], file_list) |
1311 modified_files = file_list != [] | 1318 modified_files = file_list != [] |
(...skipping 10 matching lines...) Expand all Loading... |
1322 entry_fixed, self.root_dir)) | 1329 entry_fixed, self.root_dir)) |
1323 gclient_utils.rmtree(e_dir) | 1330 gclient_utils.rmtree(e_dir) |
1324 # record the current list of entries for next time | 1331 # record the current list of entries for next time |
1325 self._SaveEntries() | 1332 self._SaveEntries() |
1326 return 0 | 1333 return 0 |
1327 | 1334 |
1328 def PrintRevInfo(self): | 1335 def PrintRevInfo(self): |
1329 if not self.dependencies: | 1336 if not self.dependencies: |
1330 raise gclient_utils.Error('No solution specified') | 1337 raise gclient_utils.Error('No solution specified') |
1331 # Load all the settings. | 1338 # Load all the settings. |
1332 work_queue = gclient_utils.ExecutionQueue(self._options.jobs, None, False) | 1339 work_queue = gclient_utils.ExecutionQueue( |
| 1340 self._options.jobs, None, False, verbose=self._options.verbose) |
1333 for s in self.dependencies: | 1341 for s in self.dependencies: |
1334 work_queue.enqueue(s) | 1342 work_queue.enqueue(s) |
1335 work_queue.flush({}, None, [], options=self._options) | 1343 work_queue.flush({}, None, [], options=self._options) |
1336 | 1344 |
1337 def GetURLAndRev(dep): | 1345 def GetURLAndRev(dep): |
1338 """Returns the revision-qualified SCM url for a Dependency.""" | 1346 """Returns the revision-qualified SCM url for a Dependency.""" |
1339 if dep.parsed_url is None: | 1347 if dep.parsed_url is None: |
1340 return None | 1348 return None |
1341 if isinstance(dep.parsed_url, self.FileImpl): | 1349 if isinstance(dep.parsed_url, self.FileImpl): |
1342 original_url = dep.parsed_url.file_location | 1350 original_url = dep.parsed_url.file_location |
1343 else: | 1351 else: |
1344 original_url = dep.parsed_url | 1352 original_url = dep.parsed_url |
1345 url, _ = gclient_utils.SplitUrlRevision(original_url) | 1353 url, _ = gclient_utils.SplitUrlRevision(original_url) |
1346 scm = gclient_scm.CreateSCM(original_url, self.root_dir, dep.name) | 1354 scm = gclient_scm.CreateSCM( |
| 1355 original_url, self.root_dir, dep.name, self.outbuf) |
1347 if not os.path.isdir(scm.checkout_path): | 1356 if not os.path.isdir(scm.checkout_path): |
1348 return None | 1357 return None |
1349 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) | 1358 return '%s@%s' % (url, scm.revinfo(self._options, [], None)) |
1350 | 1359 |
1351 if self._options.snapshot: | 1360 if self._options.snapshot: |
1352 new_gclient = '' | 1361 new_gclient = '' |
1353 # First level at .gclient | 1362 # First level at .gclient |
1354 for d in self.dependencies: | 1363 for d in self.dependencies: |
1355 entries = {} | 1364 entries = {} |
1356 def GrabDeps(dep): | 1365 def GrabDeps(dep): |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1952 print >> sys.stderr, 'Error: %s' % str(e) | 1961 print >> sys.stderr, 'Error: %s' % str(e) |
1953 return 1 | 1962 return 1 |
1954 finally: | 1963 finally: |
1955 gclient_utils.PrintWarnings() | 1964 gclient_utils.PrintWarnings() |
1956 | 1965 |
1957 | 1966 |
1958 if '__main__' == __name__: | 1967 if '__main__' == __name__: |
1959 sys.exit(Main(sys.argv[1:])) | 1968 sys.exit(Main(sys.argv[1:])) |
1960 | 1969 |
1961 # vim: ts=2:sw=2:tw=80:et: | 1970 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |