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

Side by Side Diff: gclient_scm.py

Issue 141633005: Revert of If the destination directory doesn't contain the desired repo, delete it (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years, 11 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
« no previous file with comments | « gclient.py ('k') | tests/gclient_scm_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 result, version = scm.GIT.AssertVersion('1.7') 215 result, version = scm.GIT.AssertVersion('1.7')
216 if not result: 216 if not result:
217 raise gclient_utils.Error('Git version is older than 1.7: %s' % version) 217 raise gclient_utils.Error('Git version is older than 1.7: %s' % version)
218 return result 218 return result
219 except OSError: 219 except OSError:
220 return False 220 return False
221 221
222 def GetCheckoutRoot(self): 222 def GetCheckoutRoot(self):
223 return scm.GIT.GetCheckoutRoot(self.checkout_path) 223 return scm.GIT.GetCheckoutRoot(self.checkout_path)
224 224
225 def GetRemoteURL(self, options, cwd=None):
226 try:
227 return self._Capture(['config', 'remote.%s.url' % self.remote],
228 cwd=cwd or self.checkout_path).rstrip()
229 except (OSError, subprocess2.CalledProcessError):
230 return None
231
232 def GetRevisionDate(self, _revision): 225 def GetRevisionDate(self, _revision):
233 """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
234 time zone).""" 227 time zone)."""
235 # 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
236 # time-stamp of the currently checked out revision. 229 # time-stamp of the currently checked out revision.
237 return self._Capture(['log', '-n', '1', '--format=%ai']) 230 return self._Capture(['log', '-n', '1', '--format=%ai'])
238 231
239 @staticmethod 232 @staticmethod
240 def cleanup(options, args, file_list): 233 def cleanup(options, args, file_list):
241 """'Cleanup' the repo. 234 """'Cleanup' the repo.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 # 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
280 # world. So just keep it quiet. 273 # world. So just keep it quiet.
281 pass 274 pass
282 try: 275 try:
283 gclient_utils.CheckCallAndFilter(cmd3, **kwargs) 276 gclient_utils.CheckCallAndFilter(cmd3, **kwargs)
284 except subprocess2.CalledProcessError: 277 except subprocess2.CalledProcessError:
285 gclient_utils.CheckCallAndFilter(cmd3 + ['always'], **kwargs) 278 gclient_utils.CheckCallAndFilter(cmd3 + ['always'], **kwargs)
286 279
287 gclient_utils.CheckCallAndFilter(cmd4, **kwargs) 280 gclient_utils.CheckCallAndFilter(cmd4, **kwargs)
288 281
282 def _FetchAndReset(self, revision, file_list, options):
283 """Equivalent to git fetch; git reset."""
284 quiet = []
285 if not options.verbose:
286 quiet = ['--quiet']
287 self._UpdateBranchHeads(options, fetch=False)
288
289 fetch_cmd = [
290 '-c', 'core.deltaBaseCacheLimit=2g', 'fetch', self.remote, '--prune']
291 self._Run(fetch_cmd + quiet, options, retry=True)
292 self._Run(['reset', '--hard', revision] + quiet, options)
293 self.UpdateSubmoduleConfig()
294 if file_list is not None:
295 files = self._Capture(['ls-files']).splitlines()
296 file_list.extend([os.path.join(self.checkout_path, f) for f in files])
297
289 def update(self, options, args, file_list): 298 def update(self, options, args, file_list):
290 """Runs git to update or transparently checkout the working copy. 299 """Runs git to update or transparently checkout the working copy.
291 300
292 All updated files will be appended to file_list. 301 All updated files will be appended to file_list.
293 302
294 Raises: 303 Raises:
295 Error: if can't get URL for relative path. 304 Error: if can't get URL for relative path.
296 """ 305 """
297 if args: 306 if args:
298 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) 307 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 return self._Capture(['rev-parse', '--verify', 'HEAD']) 374 return self._Capture(['rev-parse', '--verify', 'HEAD'])
366 375
367 if not os.path.exists(os.path.join(self.checkout_path, '.git')): 376 if not os.path.exists(os.path.join(self.checkout_path, '.git')):
368 raise gclient_utils.Error('\n____ %s%s\n' 377 raise gclient_utils.Error('\n____ %s%s\n'
369 '\tPath is not a git repo. No .git dir.\n' 378 '\tPath is not a git repo. No .git dir.\n'
370 '\tTo resolve:\n' 379 '\tTo resolve:\n'
371 '\t\trm -rf %s\n' 380 '\t\trm -rf %s\n'
372 '\tAnd run gclient sync again\n' 381 '\tAnd run gclient sync again\n'
373 % (self.relpath, rev_str, self.relpath)) 382 % (self.relpath, rev_str, self.relpath))
374 383
384 # See if the url has changed (the unittests use git://foo for the url, let
385 # that through).
386 current_url = self._Capture(['config', 'remote.%s.url' % self.remote])
387 return_early = False
388 # TODO(maruel): Delete url != 'git://foo' since it's just to make the
389 # unit test pass. (and update the comment above)
390 # Skip url auto-correction if remote.origin.gclient-auto-fix-url is set.
391 # This allows devs to use experimental repos which have a different url
392 # but whose branch(s) are the same as official repos.
393 if (current_url != url and
394 url != 'git://foo' and
395 subprocess2.capture(
396 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote],
397 cwd=self.checkout_path).strip() != 'False'):
398 print('_____ switching %s to a new upstream' % self.relpath)
399 # Make sure it's clean
400 self._CheckClean(rev_str)
401 # Switch over to the new upstream
402 self._Run(['remote', 'set-url', self.remote, url], options)
403 self._FetchAndReset(revision, file_list, options)
404 return_early = True
405
375 # Need to do this in the normal path as well as in the post-remote-switch 406 # Need to do this in the normal path as well as in the post-remote-switch
376 # path. 407 # path.
377 self._PossiblySwitchCache(url, options) 408 self._PossiblySwitchCache(url, options)
378 409
410 if return_early:
411 return self._Capture(['rev-parse', '--verify', 'HEAD'])
412
379 cur_branch = self._GetCurrentBranch() 413 cur_branch = self._GetCurrentBranch()
380 414
381 # Cases: 415 # Cases:
382 # 0) HEAD is detached. Probably from our initial clone. 416 # 0) HEAD is detached. Probably from our initial clone.
383 # - make sure HEAD is contained by a named ref, then update. 417 # - make sure HEAD is contained by a named ref, then update.
384 # Cases 1-4. HEAD is a branch. 418 # Cases 1-4. HEAD is a branch.
385 # 1) current branch is not tracking a remote branch (could be git-svn) 419 # 1) current branch is not tracking a remote branch (could be git-svn)
386 # - try to rebase onto the new hash or branch 420 # - try to rebase onto the new hash or branch
387 # 2) current branch is tracking a remote branch with local committed 421 # 2) current branch is tracking a remote branch with local committed
388 # changes, but the DEPS file switched to point to a hash 422 # changes, but the DEPS file switched to point to a hash
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after
774 if use_reference: 808 if use_reference:
775 cmd += ['--reference', os.path.abspath(self.checkout_path)] 809 cmd += ['--reference', os.path.abspath(self.checkout_path)]
776 810
777 self._Run(cmd + [url, folder], 811 self._Run(cmd + [url, folder],
778 options, filter_fn=filter_fn, cwd=self.cache_dir, retry=True) 812 options, filter_fn=filter_fn, cwd=self.cache_dir, retry=True)
779 else: 813 else:
780 # For now, assert that host/path/to/repo.git is identical. We may want 814 # For now, assert that host/path/to/repo.git is identical. We may want
781 # to relax this restriction in the future to allow for smarter cache 815 # to relax this restriction in the future to allow for smarter cache
782 # repo update schemes (such as pulling the same repo, but from a 816 # repo update schemes (such as pulling the same repo, but from a
783 # different host). 817 # different host).
784 existing_url = self.GetRemoteURL(options, cwd=folder) 818 existing_url = self._Capture(['config', 'remote.%s.url' % self.remote],
819 cwd=folder)
785 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url) 820 assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url)
786 821
787 if use_reference: 822 if use_reference:
788 with open(altfile, 'w') as f: 823 with open(altfile, 'w') as f:
789 f.write(os.path.abspath(checkout_objects)) 824 f.write(os.path.abspath(checkout_objects))
790 825
791 # Would normally use `git remote update`, but it doesn't support 826 # Would normally use `git remote update`, but it doesn't support
792 # --progress, so use fetch instead. 827 # --progress, so use fetch instead.
793 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'], 828 self._Run(['fetch'] + v + ['--multiple', '--progress', '--all'],
794 options, filter_fn=filter_fn, cwd=folder, retry=True) 829 options, filter_fn=filter_fn, cwd=folder, retry=True)
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 result, version = scm.SVN.AssertVersion('1.4') 1078 result, version = scm.SVN.AssertVersion('1.4')
1044 if not result: 1079 if not result:
1045 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) 1080 raise gclient_utils.Error('SVN version is older than 1.4: %s' % version)
1046 return result 1081 return result
1047 except OSError: 1082 except OSError:
1048 return False 1083 return False
1049 1084
1050 def GetCheckoutRoot(self): 1085 def GetCheckoutRoot(self):
1051 return scm.SVN.GetCheckoutRoot(self.checkout_path) 1086 return scm.SVN.GetCheckoutRoot(self.checkout_path)
1052 1087
1053 def GetRemoteURL(self, options):
1054 try:
1055 local_info = scm.SVN.CaptureLocalInfo([os.curdir], self.checkout_path)
1056 except (OSError, subprocess2.CalledProcessError):
1057 return None
1058 return local_info.get('URL')
1059
1060 def GetRevisionDate(self, revision): 1088 def GetRevisionDate(self, revision):
1061 """Returns the given revision's date in ISO-8601 format (which contains the 1089 """Returns the given revision's date in ISO-8601 format (which contains the
1062 time zone).""" 1090 time zone)."""
1063 date = scm.SVN.Capture( 1091 date = scm.SVN.Capture(
1064 ['propget', '--revprop', 'svn:date', '-r', revision], 1092 ['propget', '--revprop', 'svn:date', '-r', revision],
1065 os.path.join(self.checkout_path, '.')) 1093 os.path.join(self.checkout_path, '.'))
1066 return date.strip() 1094 return date.strip()
1067 1095
1068 def cleanup(self, options, args, _file_list): 1096 def cleanup(self, options, args, _file_list):
1069 """Cleanup working copy.""" 1097 """Cleanup working copy."""
(...skipping 19 matching lines...) Expand all
1089 filter_fn=SvnDiffFilterer(self.relpath).Filter) 1117 filter_fn=SvnDiffFilterer(self.relpath).Filter)
1090 1118
1091 def update(self, options, args, file_list): 1119 def update(self, options, args, file_list):
1092 """Runs svn to update or transparently checkout the working copy. 1120 """Runs svn to update or transparently checkout the working copy.
1093 1121
1094 All updated files will be appended to file_list. 1122 All updated files will be appended to file_list.
1095 1123
1096 Raises: 1124 Raises:
1097 Error: if can't get URL for relative path. 1125 Error: if can't get URL for relative path.
1098 """ 1126 """
1127 # Only update if git or hg is not controlling the directory.
1128 git_path = os.path.join(self.checkout_path, '.git')
1129 if os.path.exists(git_path):
1130 print('________ found .git directory; skipping %s' % self.relpath)
1131 return
1132
1133 hg_path = os.path.join(self.checkout_path, '.hg')
1134 if os.path.exists(hg_path):
1135 print('________ found .hg directory; skipping %s' % self.relpath)
1136 return
1137
1099 if args: 1138 if args:
1100 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) 1139 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))
1101 1140
1102 # revision is the revision to match. It is None if no revision is specified, 1141 # revision is the revision to match. It is None if no revision is specified,
1103 # i.e. the 'deps ain't pinned'. 1142 # i.e. the 'deps ain't pinned'.
1104 url, revision = gclient_utils.SplitUrlRevision(self.url) 1143 url, revision = gclient_utils.SplitUrlRevision(self.url)
1144 # Keep the original unpinned url for reference in case the repo is switched.
1145 base_url = url
1105 managed = True 1146 managed = True
1106 if options.revision: 1147 if options.revision:
1107 # Override the revision number. 1148 # Override the revision number.
1108 revision = str(options.revision) 1149 revision = str(options.revision)
1109 if revision: 1150 if revision:
1110 if revision != 'unmanaged': 1151 if revision != 'unmanaged':
1111 forced_revision = True 1152 forced_revision = True
1112 # Reconstruct the url. 1153 # Reconstruct the url.
1113 url = '%s@%s' % (url, revision) 1154 url = '%s@%s' % (url, revision)
1114 rev_str = ' at %s' % revision 1155 rev_str = ' at %s' % revision
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1241 if d[0][0] == '!': 1282 if d[0][0] == '!':
1242 print 'You can pass --force to enable automatic removal.' 1283 print 'You can pass --force to enable automatic removal.'
1243 raise e 1284 raise e
1244 1285
1245 # Retrieve the current HEAD version because svn is slow at null updates. 1286 # Retrieve the current HEAD version because svn is slow at null updates.
1246 if options.manually_grab_svn_rev and not revision: 1287 if options.manually_grab_svn_rev and not revision:
1247 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL']) 1288 from_info_live = scm.SVN.CaptureRemoteInfo(from_info['URL'])
1248 revision = str(from_info_live['Revision']) 1289 revision = str(from_info_live['Revision'])
1249 rev_str = ' at %s' % revision 1290 rev_str = ' at %s' % revision
1250 1291
1292 if from_info['URL'] != base_url:
1293 # The repository url changed, need to switch.
1294 try:
1295 to_info = scm.SVN.CaptureRemoteInfo(url)
1296 except (gclient_utils.Error, subprocess2.CalledProcessError):
1297 # The url is invalid or the server is not accessible, it's safer to bail
1298 # out right now.
1299 raise gclient_utils.Error('This url is unreachable: %s' % url)
1300 can_switch = ((from_info['Repository Root'] != to_info['Repository Root'])
1301 and (from_info['UUID'] == to_info['UUID']))
1302 if can_switch:
1303 print('\n_____ relocating %s to a new checkout' % self.relpath)
1304 # We have different roots, so check if we can switch --relocate.
1305 # Subversion only permits this if the repository UUIDs match.
1306 # Perform the switch --relocate, then rewrite the from_url
1307 # to reflect where we "are now." (This is the same way that
1308 # Subversion itself handles the metadata when switch --relocate
1309 # is used.) This makes the checks below for whether we
1310 # can update to a revision or have to switch to a different
1311 # branch work as expected.
1312 # TODO(maruel): TEST ME !
1313 command = ['switch', '--relocate',
1314 from_info['Repository Root'],
1315 to_info['Repository Root'],
1316 self.relpath]
1317 self._Run(command, options, cwd=self._root_dir)
1318 from_info['URL'] = from_info['URL'].replace(
1319 from_info['Repository Root'],
1320 to_info['Repository Root'])
1321 else:
1322 if not options.force and not options.reset:
1323 # Look for local modifications but ignore unversioned files.
1324 for status in scm.SVN.CaptureStatus(None, self.checkout_path):
1325 if status[0][0] != '?':
1326 raise gclient_utils.Error(
1327 ('Can\'t switch the checkout to %s; UUID don\'t match and '
1328 'there is local changes in %s. Delete the directory and '
1329 'try again.') % (url, self.checkout_path))
1330 # Ok delete it.
1331 print('\n_____ switching %s to a new checkout' % self.relpath)
1332 gclient_utils.rmtree(self.checkout_path)
1333 # We need to checkout.
1334 command = ['checkout', url, self.checkout_path]
1335 command = self._AddAdditionalUpdateFlags(command, options, revision)
1336 self._RunAndGetFileList(command, options, file_list, self._root_dir)
1337 return self.Svnversion()
1338
1251 # If the provided url has a revision number that matches the revision 1339 # If the provided url has a revision number that matches the revision
1252 # number of the existing directory, then we don't need to bother updating. 1340 # number of the existing directory, then we don't need to bother updating.
1253 if not options.force and str(from_info['Revision']) == revision: 1341 if not options.force and str(from_info['Revision']) == revision:
1254 if options.verbose or not forced_revision: 1342 if options.verbose or not forced_revision:
1255 print('\n_____ %s%s' % (self.relpath, rev_str)) 1343 print('\n_____ %s%s' % (self.relpath, rev_str))
1256 else: 1344 else:
1257 command = ['update', self.checkout_path] 1345 command = ['update', self.checkout_path]
1258 command = self._AddAdditionalUpdateFlags(command, options, revision) 1346 command = self._AddAdditionalUpdateFlags(command, options, revision)
1259 self._RunAndGetFileList(command, options, file_list, self._root_dir) 1347 self._RunAndGetFileList(command, options, file_list, self._root_dir)
1260 1348
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1307 if not os.path.isdir(self.checkout_path): 1395 if not os.path.isdir(self.checkout_path):
1308 if os.path.exists(self.checkout_path): 1396 if os.path.exists(self.checkout_path):
1309 gclient_utils.rmtree(self.checkout_path) 1397 gclient_utils.rmtree(self.checkout_path)
1310 # svn revert won't work if the directory doesn't exist. It needs to 1398 # svn revert won't work if the directory doesn't exist. It needs to
1311 # checkout instead. 1399 # checkout instead.
1312 print('\n_____ %s is missing, synching instead' % self.relpath) 1400 print('\n_____ %s is missing, synching instead' % self.relpath)
1313 # Don't reuse the args. 1401 # Don't reuse the args.
1314 return self.update(options, [], file_list) 1402 return self.update(options, [], file_list)
1315 1403
1316 if not os.path.isdir(os.path.join(self.checkout_path, '.svn')): 1404 if not os.path.isdir(os.path.join(self.checkout_path, '.svn')):
1405 if os.path.isdir(os.path.join(self.checkout_path, '.git')):
1406 print('________ found .git directory; skipping %s' % self.relpath)
1407 return
1408 if os.path.isdir(os.path.join(self.checkout_path, '.hg')):
1409 print('________ found .hg directory; skipping %s' % self.relpath)
1410 return
1317 if not options.force: 1411 if not options.force:
1318 raise gclient_utils.Error('Invalid checkout path, aborting') 1412 raise gclient_utils.Error('Invalid checkout path, aborting')
1319 print( 1413 print(
1320 '\n_____ %s is not a valid svn checkout, synching instead' % 1414 '\n_____ %s is not a valid svn checkout, synching instead' %
1321 self.relpath) 1415 self.relpath)
1322 gclient_utils.rmtree(self.checkout_path) 1416 gclient_utils.rmtree(self.checkout_path)
1323 # Don't reuse the args. 1417 # Don't reuse the args.
1324 return self.update(options, [], file_list) 1418 return self.update(options, [], file_list)
1325 1419
1326 def printcb(file_status): 1420 def printcb(file_status):
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1424 new_command.append('--force') 1518 new_command.append('--force')
1425 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1519 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1426 new_command.extend(('--accept', 'theirs-conflict')) 1520 new_command.extend(('--accept', 'theirs-conflict'))
1427 elif options.manually_grab_svn_rev: 1521 elif options.manually_grab_svn_rev:
1428 new_command.append('--force') 1522 new_command.append('--force')
1429 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1523 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1430 new_command.extend(('--accept', 'postpone')) 1524 new_command.extend(('--accept', 'postpone'))
1431 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: 1525 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]:
1432 new_command.extend(('--accept', 'postpone')) 1526 new_command.extend(('--accept', 'postpone'))
1433 return new_command 1527 return new_command
OLDNEW
« no previous file with comments | « gclient.py ('k') | tests/gclient_scm_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698