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

Side by Side Diff: gclient_scm.py

Issue 61623008: 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: Address comments from meeting (first upload failed) Created 7 years 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
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 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
OLDNEW
« gclient.py ('K') | « gclient.py ('k') | tests/gclient_scm_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698