Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Gclient-specific SCM-specific operations.""" | 5 """Gclient-specific SCM-specific operations.""" |
| 6 | 6 |
| 7 import collections | 7 import collections |
| 8 import logging | 8 import logging |
| 9 import os | 9 import os |
| 10 import posixpath | 10 import posixpath |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 result, version = scm.GIT.AssertVersion('1.7') | 208 result, version = scm.GIT.AssertVersion('1.7') |
| 209 if not result: | 209 if not result: |
| 210 raise gclient_utils.Error('Git version is older than 1.7: %s' % version) | 210 raise gclient_utils.Error('Git version is older than 1.7: %s' % version) |
| 211 return result | 211 return result |
| 212 except OSError: | 212 except OSError: |
| 213 return False | 213 return False |
| 214 | 214 |
| 215 def GetCheckoutRoot(self): | 215 def GetCheckoutRoot(self): |
| 216 return scm.GIT.GetCheckoutRoot(self.checkout_path) | 216 return scm.GIT.GetCheckoutRoot(self.checkout_path) |
| 217 | 217 |
| 218 def GetRemoteURL(self, options, cwd=None): | |
| 219 try: | |
| 220 return self._Capture(['config', 'remote.origin.url'], | |
| 221 cwd=cwd or self.checkout_path).rstrip() | |
| 222 except (OSError, subprocess2.CalledProcessError): | |
| 223 return None | |
| 224 | |
| 218 def GetRevisionDate(self, _revision): | 225 def GetRevisionDate(self, _revision): |
| 219 """Returns the given revision's date in ISO-8601 format (which contains the | 226 """Returns the given revision's date in ISO-8601 format (which contains the |
| 220 time zone).""" | 227 time zone).""" |
| 221 # TODO(floitsch): get the time-stamp of the given revision and not just the | 228 # TODO(floitsch): get the time-stamp of the given revision and not just the |
| 222 # time-stamp of the currently checked out revision. | 229 # time-stamp of the currently checked out revision. |
| 223 return self._Capture(['log', '-n', '1', '--format=%ai']) | 230 return self._Capture(['log', '-n', '1', '--format=%ai']) |
| 224 | 231 |
| 225 @staticmethod | 232 @staticmethod |
| 226 def cleanup(options, args, file_list): | 233 def cleanup(options, args, file_list): |
| 227 """'Cleanup' the repo. | 234 """'Cleanup' the repo. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 265 # Not a fatal error, or even very interesting in a non-git-submodule | 272 # Not a fatal error, or even very interesting in a non-git-submodule |
| 266 # world. So just keep it quiet. | 273 # world. So just keep it quiet. |
| 267 pass | 274 pass |
| 268 try: | 275 try: |
| 269 gclient_utils.CheckCallAndFilter(cmd3, **kwargs) | 276 gclient_utils.CheckCallAndFilter(cmd3, **kwargs) |
| 270 except subprocess2.CalledProcessError: | 277 except subprocess2.CalledProcessError: |
| 271 gclient_utils.CheckCallAndFilter(cmd3 + ['always'], **kwargs) | 278 gclient_utils.CheckCallAndFilter(cmd3 + ['always'], **kwargs) |
| 272 | 279 |
| 273 gclient_utils.CheckCallAndFilter(cmd4, **kwargs) | 280 gclient_utils.CheckCallAndFilter(cmd4, **kwargs) |
| 274 | 281 |
| 275 def _FetchAndReset(self, revision, file_list, options): | |
| 276 """Equivalent to git fetch; git reset.""" | |
| 277 quiet = [] | |
| 278 if not options.verbose: | |
| 279 quiet = ['--quiet'] | |
| 280 self._UpdateBranchHeads(options, fetch=False) | |
| 281 | |
| 282 fetch_cmd = [ | |
| 283 '-c', 'core.deltaBaseCacheLimit=2g', 'fetch', 'origin', '--prune'] | |
| 284 self._Run(fetch_cmd + quiet, options, retry=True) | |
| 285 self._Run(['reset', '--hard', revision] + quiet, options) | |
| 286 self.UpdateSubmoduleConfig() | |
| 287 if file_list is not None: | |
| 288 files = self._Capture(['ls-files']).splitlines() | |
| 289 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | |
| 290 | |
| 291 def update(self, options, args, file_list): | 282 def update(self, options, args, file_list): |
| 292 """Runs git to update or transparently checkout the working copy. | 283 """Runs git to update or transparently checkout the working copy. |
| 293 | 284 |
| 294 All updated files will be appended to file_list. | 285 All updated files will be appended to file_list. |
| 295 | 286 |
| 296 Raises: | 287 Raises: |
| 297 Error: if can't get URL for relative path. | 288 Error: if can't get URL for relative path. |
| 298 """ | 289 """ |
| 299 if args: | 290 if args: |
| 300 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 291 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 357 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 367 | 358 |
| 368 if not os.path.exists(os.path.join(self.checkout_path, '.git')): | 359 if not os.path.exists(os.path.join(self.checkout_path, '.git')): |
| 369 raise gclient_utils.Error('\n____ %s%s\n' | 360 raise gclient_utils.Error('\n____ %s%s\n' |
| 370 '\tPath is not a git repo. No .git dir.\n' | 361 '\tPath is not a git repo. No .git dir.\n' |
| 371 '\tTo resolve:\n' | 362 '\tTo resolve:\n' |
| 372 '\t\trm -rf %s\n' | 363 '\t\trm -rf %s\n' |
| 373 '\tAnd run gclient sync again\n' | 364 '\tAnd run gclient sync again\n' |
| 374 % (self.relpath, rev_str, self.relpath)) | 365 % (self.relpath, rev_str, self.relpath)) |
| 375 | 366 |
| 376 # See if the url has changed (the unittests use git://foo for the url, let | |
| 377 # that through). | |
| 378 current_url = self._Capture(['config', 'remote.origin.url']) | |
| 379 return_early = False | |
| 380 # TODO(maruel): Delete url != 'git://foo' since it's just to make the | |
| 381 # unit test pass. (and update the comment above) | |
| 382 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set. | |
| 383 # This allows devs to use experimental repos which have a different url | |
| 384 # but whose branch(s) are the same as official repos. | |
| 385 if (current_url != url and | |
| 386 url != 'git://foo' and | |
| 387 subprocess2.capture( | |
| 388 ['git', 'config', 'remote.origin.gclient-auto-fix-url'], | |
| 389 cwd=self.checkout_path).strip() != 'False'): | |
| 390 print('_____ switching %s to a new upstream' % self.relpath) | |
| 391 # Make sure it's clean | |
| 392 self._CheckClean(rev_str) | |
| 393 # Switch over to the new upstream | |
| 394 self._Run(['remote', 'set-url', 'origin', url], options) | |
| 395 self._FetchAndReset(revision, file_list, options) | |
| 396 return_early = True | |
| 397 | |
| 398 # Need to do this in the normal path as well as in the post-remote-switch | 367 # Need to do this in the normal path as well as in the post-remote-switch |
| 399 # path. | 368 # path. |
| 400 self._PossiblySwitchCache(url, options) | 369 self._PossiblySwitchCache(url, options) |
| 401 | 370 |
| 402 if return_early: | |
| 403 return self._Capture(['rev-parse', '--verify', 'HEAD']) | |
| 404 | |
| 405 cur_branch = self._GetCurrentBranch() | 371 cur_branch = self._GetCurrentBranch() |
| 406 | 372 |
| 407 # Cases: | 373 # Cases: |
| 408 # 0) HEAD is detached. Probably from our initial clone. | 374 # 0) HEAD is detached. Probably from our initial clone. |
| 409 # - make sure HEAD is contained by a named ref, then update. | 375 # - make sure HEAD is contained by a named ref, then update. |
| 410 # Cases 1-4. HEAD is a branch. | 376 # Cases 1-4. HEAD is a branch. |
| 411 # 1) current branch is not tracking a remote branch (could be git-svn) | 377 # 1) current branch is not tracking a remote branch (could be git-svn) |
| 412 # - try to rebase onto the new hash or branch | 378 # - try to rebase onto the new hash or branch |
| 413 # 2) current branch is tracking a remote branch with local committed | 379 # 2) current branch is tracking a remote branch with local committed |
| 414 # changes, but the DEPS file switched to point to a hash | 380 # changes, but the DEPS file switched to point to a hash |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 800 if use_reference: | 766 if use_reference: |
| 801 cmd += ['--reference', os.path.abspath(self.checkout_path)] | 767 cmd += ['--reference', os.path.abspath(self.checkout_path)] |
| 802 | 768 |
| 803 self._Run(cmd + [url, folder], | 769 self._Run(cmd + [url, folder], |
| 804 options, filter_fn=filter_fn, cwd=self.cache_dir, retry=True) | 770 options, filter_fn=filter_fn, cwd=self.cache_dir, retry=True) |
| 805 else: | 771 else: |
| 806 # For now, assert that host/path/to/repo.git is identical. We may want | 772 # For now, assert that host/path/to/repo.git is identical. We may want |
| 807 # to relax this restriction in the future to allow for smarter cache | 773 # to relax this restriction in the future to allow for smarter cache |
| 808 # repo update schemes (such as pulling the same repo, but from a | 774 # repo update schemes (such as pulling the same repo, but from a |
| 809 # different host). | 775 # different host). |
| 810 existing_url = self._Capture(['config', 'remote.origin.url'], | 776 existing_url = self.GetRemoteURL(options, cwd=folder) |
| 811 cwd=folder) | |
| 812 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) | 777 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) |
| 813 | 778 |
| 814 if use_reference: | 779 if use_reference: |
| 815 with open(altfile, 'w') as f: | 780 with open(altfile, 'w') as f: |
| 816 f.write(os.path.abspath(checkout_objects)) | 781 f.write(os.path.abspath(checkout_objects)) |
| 817 | 782 |
| 818 # Would normally use `git remote update`, but it doesn't support | 783 # Would normally use `git remote update`, but it doesn't support |
| 819 # --progress, so use fetch instead. | 784 # --progress, so use fetch instead. |
| 820 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], | 785 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], |
| 821 options, filter_fn=filter_fn, cwd=folder, retry=True) | 786 options, filter_fn=filter_fn, cwd=folder, retry=True) |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1070 result, version = scm.SVN.AssertVersion('1.4') | 1035 result, version = scm.SVN.AssertVersion('1.4') |
| 1071 if not result: | 1036 if not result: |
| 1072 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) | 1037 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) |
| 1073 return result | 1038 return result |
| 1074 except OSError: | 1039 except OSError: |
| 1075 return False | 1040 return False |
| 1076 | 1041 |
| 1077 def GetCheckoutRoot(self): | 1042 def GetCheckoutRoot(self): |
| 1078 return scm.SVN.GetCheckoutRoot(self.checkout_path) | 1043 return scm.SVN.GetCheckoutRoot(self.checkout_path) |
| 1079 | 1044 |
| 1045 def GetRemoteURL(self, options): | |
| 1046 try: | |
| 1047 local_info = scm.SVN.CaptureLocalInfo([os.curdir], self.checkout_path) | |
| 1048 except (OSError, subprocess2.CalledProcessError): | |
| 1049 return None | |
| 1050 return local_info.get('URL') | |
| 1051 | |
| 1080 def GetRevisionDate(self, revision): | 1052 def GetRevisionDate(self, revision): |
| 1081 """Returns the given revision's date in ISO-8601 format (which contains the | 1053 """Returns the given revision's date in ISO-8601 format (which contains the |
| 1082 time zone).""" | 1054 time zone).""" |
| 1083 date = scm.SVN.Capture( | 1055 date = scm.SVN.Capture( |
| 1084 ['propget', '--revprop', 'svn:date', '-r', revision], | 1056 ['propget', '--revprop', 'svn:date', '-r', revision], |
| 1085 os.path.join(self.checkout_path, '.')) | 1057 os.path.join(self.checkout_path, '.')) |
| 1086 return date.strip() | 1058 return date.strip() |
| 1087 | 1059 |
| 1088 def cleanup(self, options, args, _file_list): | 1060 def cleanup(self, options, args, _file_list): |
| 1089 """Cleanup working copy.""" | 1061 """Cleanup working copy.""" |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1213 print 'Not removing troublesome path %s automatically.' % d[1] | 1185 print 'Not removing troublesome path %s automatically.' % d[1] |
| 1214 if d[0][0] == '!': | 1186 if d[0][0] == '!': |
| 1215 print 'You can pass --force to enable automatic removal.' | 1187 print 'You can pass --force to enable automatic removal.' |
| 1216 raise e | 1188 raise e |
| 1217 | 1189 |
| 1218 # Retrieve the current HEAD version because svn is slow at null updates. | 1190 # Retrieve the current HEAD version because svn is slow at null updates. |
| 1219 if options.manually_grab_svn_rev and not revision: | 1191 if options.manually_grab_svn_rev and not revision: |
| 1220 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) | 1192 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) |
| 1221 revision = str(from_info_live['Revision']) | 1193 revision = str(from_info_live['Revision']) |
| 1222 rev_str = ' at %s' % revision | 1194 rev_str = ' at %s' % revision |
| 1223 | 1195 |
|
borenet
2013/12/10 18:48:27
I missed this section before - Isaac, this URL rew
Isaac (away)
2013/12/11 03:17:33
I'm not very familiar with this, having essentiall
borenet
2013/12/11 20:42:19
It does conflict. When I overrode the googlecode_
iannucci
2014/01/07 22:23:28
So IIUC, the new behavior will simply nuke the con
borenet
2014/01/08 18:25:33
Exactly.
| |
| 1224 if from_info['URL'] != base_url: | |
| 1225 # The repository url changed, need to switch. | |
| 1226 try: | |
| 1227 to_info = scm.SVN.CaptureRemoteInfo(url) | |
| 1228 except (gclient_utils.Error, subprocess2.CalledProcessError): | |
| 1229 # The url is invalid or the server is not accessible, it's safer to bail | |
| 1230 # out right now. | |
| 1231 raise gclient_utils.Error('This url is unreachable: %s' % url) | |
| 1232 can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) | |
| 1233 and (from_info['UUID'] == to_info['UUID'])) | |
| 1234 if can_switch: | |
| 1235 print('\n_____ relocating %s to a new checkout' % self.relpath) | |
| 1236 # We have different roots, so check if we can switch --relocate. | |
| 1237 # Subversion only permits this if the repository UUIDs match. | |
| 1238 # Perform the switch --relocate, then rewrite the from_url | |
| 1239 # to reflect where we "are now." (This is the same way that | |
| 1240 # Subversion itself handles the metadata when switch --relocate | |
| 1241 # is used.) This makes the checks below for whether we | |
| 1242 # can update to a revision or have to switch to a different | |
| 1243 # branch work as expected. | |
| 1244 # TODO(maruel): TEST ME ! | |
| 1245 command = ['switch', '--relocate', | |
| 1246 from_info['Repository Root'], | |
| 1247 to_info['Repository Root'], | |
| 1248 self.relpath] | |
| 1249 self._Run(command, options, cwd=self._root_dir) | |
| 1250 from_info['URL'] = from_info['URL'].replace( | |
| 1251 from_info['Repository Root'], | |
| 1252 to_info['Repository Root']) | |
| 1253 else: | |
| 1254 if not options.force and not options.reset: | |
| 1255 # Look for local modifications but ignore unversioned files. | |
| 1256 for status in scm.SVN.CaptureStatus(None, self.checkout_path): | |
| 1257 if status[0][0] != '?': | |
| 1258 raise gclient_utils.Error( | |
| 1259 ('Can\'t switch the checkout to %s; UUID don\'t match and ' | |
| 1260 'there is local changes in %s. Delete the directory and ' | |
| 1261 'try again.') % (url, self.checkout_path)) | |
| 1262 # Ok delete it. | |
| 1263 print('\n_____ switching %s to a new checkout' % self.relpath) | |
| 1264 gclient_utils.rmtree(self.checkout_path) | |
| 1265 # We need to checkout. | |
| 1266 command = ['checkout', url, self.checkout_path] | |
| 1267 command = self._AddAdditionalUpdateFlags(command, options, revision) | |
| 1268 self._RunAndGetFileList(command, options, file_list, self._root_dir) | |
| 1269 return self.Svnversion() | |
| 1270 | |
| 1271 # If the provided url has a revision number that matches the revision | 1196 # If the provided url has a revision number that matches the revision |
| 1272 # number of the existing directory, then we don't need to bother updating. | 1197 # number of the existing directory, then we don't need to bother updating. |
| 1273 if not options.force and str(from_info['Revision']) == revision: | 1198 if not options.force and str(from_info['Revision']) == revision: |
| 1274 if options.verbose or not forced_revision: | 1199 if options.verbose or not forced_revision: |
| 1275 print('\n_____ %s%s' % (self.relpath, rev_str)) | 1200 print('\n_____ %s%s' % (self.relpath, rev_str)) |
| 1276 else: | 1201 else: |
| 1277 command = ['update', self.checkout_path] | 1202 command = ['update', self.checkout_path] |
| 1278 command = self._AddAdditionalUpdateFlags(command, options, revision) | 1203 command = self._AddAdditionalUpdateFlags(command, options, revision) |
| 1279 self._RunAndGetFileList(command, options, file_list, self._root_dir) | 1204 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
| 1280 | 1205 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1450 new_command.append('--force') | 1375 new_command.append('--force') |
| 1451 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1376 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1452 new_command.extend(('--accept', 'theirs-conflict')) | 1377 new_command.extend(('--accept', 'theirs-conflict')) |
| 1453 elif options.manually_grab_svn_rev: | 1378 elif options.manually_grab_svn_rev: |
| 1454 new_command.append('--force') | 1379 new_command.append('--force') |
| 1455 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1380 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1456 new_command.extend(('--accept', 'postpone')) | 1381 new_command.extend(('--accept', 'postpone')) |
| 1457 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1382 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1458 new_command.extend(('--accept', 'postpone')) | 1383 new_command.extend(('--accept', 'postpone')) |
| 1459 return new_command | 1384 return new_command |
| OLD | NEW |