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 from __future__ import print_function | 7 from __future__ import print_function |
| 8 | 8 |
| 9 import collections | |
| 9 import errno | 10 import errno |
| 10 import logging | 11 import logging |
| 11 import os | 12 import os |
| 12 import posixpath | 13 import posixpath |
| 13 import re | 14 import re |
| 14 import shlex | 15 import shlex |
| 15 import sys | 16 import sys |
| 16 import tempfile | 17 import tempfile |
| 17 import traceback | 18 import traceback |
| 18 import urlparse | 19 import urlparse |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 if not command in commands: | 154 if not command in commands: |
| 154 raise gclient_utils.Error('Unknown command %s' % command) | 155 raise gclient_utils.Error('Unknown command %s' % command) |
| 155 | 156 |
| 156 if not command in dir(self): | 157 if not command in dir(self): |
| 157 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( | 158 raise gclient_utils.Error('Command %s not implemented in %s wrapper' % ( |
| 158 command, self.__class__.__name__)) | 159 command, self.__class__.__name__)) |
| 159 | 160 |
| 160 return getattr(self, command)(options, args, file_list) | 161 return getattr(self, command)(options, args, file_list) |
| 161 | 162 |
| 162 def GetActualRemoteURL(self, options): | 163 def GetActualRemoteURL(self, options): |
| 164 # Disable 'unused argument: options' warning | pylint: disable=W0613 | |
|
M-A Ruel
2014/06/24 21:18:11
Can you remove it instead?
dnj
2014/06/25 01:55:05
Done.
| |
| 163 """Attempt to determine the remote URL for this SCMWrapper.""" | 165 """Attempt to determine the remote URL for this SCMWrapper.""" |
| 164 # Git | |
| 165 if os.path.exists(os.path.join(self.checkout_path, '.git')): | 166 if os.path.exists(os.path.join(self.checkout_path, '.git')): |
| 166 actual_remote_url = shlex.split(scm.GIT.Capture( | 167 actual_remote_url = shlex.split(scm.GIT.Capture( |
| 167 ['config', '--local', '--get-regexp', r'remote.*.url'], | 168 ['config', '--local', '--get-regexp', r'remote.*.url'], |
| 168 cwd=self.checkout_path))[1] | 169 cwd=self.checkout_path))[1] |
| 169 | 170 |
| 170 # If a cache_dir is used, obtain the actual remote URL from the cache. | 171 # If a cache_dir is used, obtain the actual remote URL from the cache. |
| 171 if getattr(self, 'cache_dir', None): | 172 if getattr(self, 'cache_dir', None): |
| 172 url, _ = gclient_utils.SplitUrlRevision(self.url) | 173 url, _ = gclient_utils.SplitUrlRevision(self.url) |
| 173 mirror = git_cache.Mirror(url) | 174 mirror = git_cache.Mirror(url) |
| 174 if (mirror.exists() and mirror.mirror_path.replace('\\', '/') == | 175 if (mirror.exists() and mirror.mirror_path.replace('\\', '/') == |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 dest_path = tempfile.mkdtemp( | 224 dest_path = tempfile.mkdtemp( |
| 224 prefix=os.path.basename(self.relpath), | 225 prefix=os.path.basename(self.relpath), |
| 225 dir=bad_scm_dir) | 226 dir=bad_scm_dir) |
| 226 self.Print('_____ Conflicting directory found in %s. Moving to %s.' | 227 self.Print('_____ Conflicting directory found in %s. Moving to %s.' |
| 227 % (self.checkout_path, dest_path)) | 228 % (self.checkout_path, dest_path)) |
| 228 gclient_utils.AddWarning('Conflicting directory %s moved to %s.' | 229 gclient_utils.AddWarning('Conflicting directory %s moved to %s.' |
| 229 % (self.checkout_path, dest_path)) | 230 % (self.checkout_path, dest_path)) |
| 230 shutil.move(self.checkout_path, dest_path) | 231 shutil.move(self.checkout_path, dest_path) |
| 231 | 232 |
| 232 | 233 |
| 234 _GitRefishBase = collections.namedtuple('GitRef', ( | |
| 235 # The initial string that the parsed Refish came from | |
|
M-A Ruel
2014/06/24 21:18:11
+4
dnj
2014/06/24 22:10:50
Done.
| |
| 236 'source', | |
| 237 # Is this ref a branch? | |
| 238 'is_branch', | |
| 239 # The name of this ref when accessed through the local repository | |
| 240 'local_ref', | |
| 241 # The name of the remote that this refish resides on | |
| 242 'remote', | |
| 243 # The path of this refish on the remote (e.g., 'master') | |
| 244 'remote_ref', | |
| 245 # The remote-qualified path to this refish (e.g., 'origin/master') | |
| 246 'remote_refspec', | |
| 247 # If a branch, the expected name of the upstream branch that it should | |
| 248 # track; otherwise, 'None' | |
| 249 'upstream_branch', | |
| 250 )) | |
| 251 | |
|
M-A Ruel
2014/06/24 21:18:11
2 lines
dnj
2014/06/24 22:10:50
Done.
| |
| 252 class GitRefish(_GitRefishBase): | |
| 253 # Disable 'no __init__' warning | pylint: disable=W0232 | |
| 254 """Class to implement refish parsing and properties. | |
|
M-A Ruel
2014/06/24 21:18:11
No need to state a class is a class, so use someth
dnj
2014/06/24 22:10:50
Done.
| |
| 255 | |
| 256 This class is designed to concentrate and codify the assumptions made by | |
| 257 'gclient' code about refs and revisions. | |
| 258 """ | |
| 259 | |
| 260 _DEFAULT_REMOTE = 'origin' | |
| 261 | |
| 262 _GIT_SHA1_RE = re.compile('[0-9a-f]{40}', re.IGNORECASE) | |
| 263 _GIT_SHA1_SHORT_RE = re.compile('[0-9a-f]{4,40}', re.IGNORECASE) | |
| 264 | |
| 265 def __str__(self): | |
| 266 return self.source | |
| 267 | |
| 268 @classmethod | |
| 269 def Parse(cls, ref, remote=None, other_remotes=None): | |
| 270 """Parses a ref into a 'GitRefish' instance. | |
|
M-A Ruel
2014/06/24 21:18:11
"""Parses a ref into a 'GitRefish' instance."""
dnj
2014/06/24 22:10:50
Done.
| |
| 271 """ | |
| 272 # Use default set of remotes | |
| 273 if remote is None: | |
| 274 remote = cls._DEFAULT_REMOTE | |
|
M-A Ruel
2014/06/24 21:18:11
shorthand is:
remote = remote or cls._DEFAULT_REMO
dnj
2014/06/24 22:10:50
Done.
| |
| 275 remotes = {remote} | |
| 276 if other_remotes is not None: | |
|
M-A Ruel
2014/06/24 21:18:11
if other_remotes:
dnj
2014/06/24 22:10:50
Done.
| |
| 277 remotes.update(other_remotes) | |
| 278 | |
| 279 ref = ref.strip() | |
| 280 # Treat 'ref' as a '/'-delimited set of items; analyze their contents | |
| 281 ref_split = local_ref = remote_ref = tuple(ref.split('/')) | |
| 282 is_branch = True | |
| 283 if ( | |
| 284 len(ref_split) > 1 and | |
| 285 ref_split[:1] == ('refs',)): | |
| 286 if (len(ref_split) >= 3) and (ref_split[1] == 'heads'): | |
| 287 # refs/heads/foo/bar | |
| 288 # | |
| 289 # Local Ref: foo/bar | |
| 290 # Remote Ref: foo/bar | |
| 291 local_ref = remote_ref = ref_split[2:] | |
| 292 elif (len(ref_split) >= 4) and (ref_split[1] == 'remotes'): | |
| 293 # refs/remotes/<REMOTE>/foo/bar | |
| 294 # This is a bad assumption, and this logic can be improved, but it | |
| 295 # is consistent with traditional 'gclient' logic. | |
| 296 # | |
| 297 # Local Ref: refs/remotes/<REMOTE>/foo/bar | |
| 298 # Remote: <REMOTE> | |
| 299 # Remote Ref: foo/bar | |
| 300 remote = ref_split[2] | |
| 301 remote_ref = ref_split[3:] | |
| 302 else: | |
| 303 # If it's not part of the standard branch set, assume it's a remote | |
| 304 # branch. | |
| 305 # | |
| 306 # refs/foo/bar | |
| 307 # | |
| 308 # Local Ref: refs/foo/bar | |
| 309 # Remote ref: refs/foo/bar | |
| 310 pass | |
| 311 elif (len(ref_split) >= 2) and (ref_split[0] in remotes): | |
| 312 # origin/master | |
| 313 # | |
| 314 # Local Ref: refs/remotes/origin/master | |
| 315 # Remote Ref: master | |
| 316 remote = ref_split[0] | |
| 317 remote_ref = ref_split[1:] | |
| 318 local_ref = ('refs', 'remotes') + ref_split | |
| 319 else: | |
| 320 # It could be a hash, a short-hash, or a tag | |
| 321 is_branch = False | |
| 322 | |
| 323 # Determine how the ref should be referenced remotely | |
| 324 if is_branch: | |
| 325 # foo/bar/baz => origin/foo/bar/baz | |
| 326 remote_refspec = (remote,) + remote_ref | |
| 327 else: | |
| 328 # Refer to the hash/tag directly. This is actually not allowed in | |
| 329 # 'fetch', although it oftentimes works regardless. | |
| 330 # | |
| 331 # <HASH/TAG> => <HASH/TAG> | |
| 332 remote_refspec = (ref,) | |
| 333 | |
| 334 # Calculate the upstream branch | |
| 335 if is_branch: | |
| 336 # Convert '/refs/heads/...' to 'refs/remotes/REMOTE/...' | |
| 337 if ref_split[:2] == ('refs', 'heads'): | |
| 338 upstream_branch = ('refs', 'remotes', remote) + ref_split[2:] | |
| 339 else: | |
| 340 upstream_branch = ref_split | |
| 341 else: | |
| 342 upstream_branch = None | |
| 343 | |
| 344 def compose(ref_tuple): | |
| 345 if ref_tuple is not None: | |
| 346 ref_tuple = '/'.join(ref_tuple) | |
| 347 return ref_tuple | |
| 348 | |
| 349 # Instantiate | |
| 350 return cls( | |
| 351 source=ref, | |
| 352 is_branch=is_branch, | |
| 353 local_ref=compose(local_ref), | |
| 354 remote=remote, | |
| 355 remote_ref=compose(remote_ref), | |
| 356 remote_refspec=compose(remote_refspec), | |
| 357 upstream_branch=compose(upstream_branch), | |
| 358 ) | |
| 359 | |
| 360 | |
| 233 class GitWrapper(SCMWrapper): | 361 class GitWrapper(SCMWrapper): |
| 234 """Wrapper for Git""" | 362 """Wrapper for Git""" |
| 235 name = 'git' | 363 name = 'git' |
| 236 remote = 'origin' | 364 remote = 'origin' |
| 237 | 365 |
| 238 cache_dir = None | 366 cache_dir = None |
| 239 | 367 |
| 240 def __init__(self, url=None, *args): | 368 def __init__(self, url=None, *args): |
| 241 """Removes 'git+' fake prefix from git URL.""" | 369 """Removes 'git+' fake prefix from git URL.""" |
| 242 if url.startswith('git+http://') or url.startswith('git+https://'): | 370 if url.startswith('git+http://') or url.startswith('git+https://'): |
| 243 url = url[4:] | 371 url = url[4:] |
| 244 SCMWrapper.__init__(self, url, *args) | 372 SCMWrapper.__init__(self, url, *args) |
| 245 filter_kwargs = { 'time_throttle': 1, 'out_fh': self.out_fh } | 373 filter_kwargs = { 'time_throttle': 1, 'out_fh': self.out_fh } |
| 246 if self.out_cb: | 374 if self.out_cb: |
| 247 filter_kwargs['predicate'] = self.out_cb | 375 filter_kwargs['predicate'] = self.out_cb |
| 248 self.filter = gclient_utils.GitFilter(**filter_kwargs) | 376 self.filter = gclient_utils.GitFilter(**filter_kwargs) |
| 249 | 377 |
| 250 @staticmethod | 378 @staticmethod |
| 251 def BinaryExists(): | 379 def BinaryExists(): |
| 252 """Returns true if the command exists.""" | 380 """Returns true if the command exists.""" |
| 253 try: | 381 try: |
| 254 # We assume git is newer than 1.7. See: crbug.com/114483 | 382 # We assume git is newer than 1.7. See: crbug.com/114483 |
| 255 result, version = scm.GIT.AssertVersion('1.7') | 383 result, version = scm.GIT.AssertVersion('1.7') |
| 256 if not result: | 384 if not result: |
| 257 raise gclient_utils.Error('Git version is older than 1.7: %s' % version) | 385 raise gclient_utils.Error('Git version is older than 1.7: %s' % version) |
| 258 return result | 386 return result |
| 259 except OSError: | 387 except OSError: |
| 260 return False | 388 return False |
| 261 | 389 |
| 390 def ParseRefish(self, value, **kwargs): | |
| 391 kwargs.setdefault('remote', self.remote) | |
| 392 return GitRefish.Parse(value, **kwargs) | |
| 393 | |
| 262 def GetCheckoutRoot(self): | 394 def GetCheckoutRoot(self): |
| 263 return scm.GIT.GetCheckoutRoot(self.checkout_path) | 395 return scm.GIT.GetCheckoutRoot(self.checkout_path) |
| 264 | 396 |
| 265 def GetRevisionDate(self, _revision): | 397 def GetRevisionDate(self, _revision): |
| 266 """Returns the given revision's date in ISO-8601 format (which contains the | 398 """Returns the given revision's date in ISO-8601 format (which contains the |
| 267 time zone).""" | 399 time zone).""" |
| 268 # TODO(floitsch): get the time-stamp of the given revision and not just the | 400 # TODO(floitsch): get the time-stamp of the given revision and not just the |
| 269 # time-stamp of the currently checked out revision. | 401 # time-stamp of the currently checked out revision. |
| 270 return self._Capture(['log', '-n', '1', '--format=%ai']) | 402 return self._Capture(['log', '-n', '1', '--format=%ai']) |
| 271 | 403 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 286 | 418 |
| 287 The patch file is generated from a diff of the merge base of HEAD and | 419 The patch file is generated from a diff of the merge base of HEAD and |
| 288 its upstream branch. | 420 its upstream branch. |
| 289 """ | 421 """ |
| 290 merge_base = self._Capture(['merge-base', 'HEAD', self.remote]) | 422 merge_base = self._Capture(['merge-base', 'HEAD', self.remote]) |
| 291 gclient_utils.CheckCallAndFilter( | 423 gclient_utils.CheckCallAndFilter( |
| 292 ['git', 'diff', merge_base], | 424 ['git', 'diff', merge_base], |
| 293 cwd=self.checkout_path, | 425 cwd=self.checkout_path, |
| 294 filter_fn=GitDiffFilterer(self.relpath).Filter, print_func=self.Print) | 426 filter_fn=GitDiffFilterer(self.relpath).Filter, print_func=self.Print) |
| 295 | 427 |
| 296 def _FetchAndReset(self, revision, file_list, options): | 428 def _FetchAndReset(self, refish, file_list, options): |
| 297 """Equivalent to git fetch; git reset.""" | 429 """Equivalent to git fetch; git reset.""" |
| 298 quiet = [] | 430 quiet = [] |
| 299 if not options.verbose: | 431 if not options.verbose: |
| 300 quiet = ['--quiet'] | 432 quiet = ['--quiet'] |
| 301 self._UpdateBranchHeads(options, fetch=False) | 433 self._UpdateBranchHeads(options, fetch=False) |
| 302 | 434 |
| 303 self._Fetch(options, prune=True, quiet=options.verbose) | 435 self._Fetch(options, prune=True, quiet=options.verbose) |
| 304 self._Run(['reset', '--hard', revision] + quiet, options) | 436 self._Run(['reset', '--hard', refish.local_ref] + quiet, options) |
| 305 if file_list is not None: | 437 if file_list is not None: |
| 306 files = self._Capture(['ls-files']).splitlines() | 438 files = self._Capture(['ls-files']).splitlines() |
| 307 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 439 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 308 | 440 |
| 309 def update(self, options, args, file_list): | 441 def update(self, options, args, file_list): |
| 310 """Runs git to update or transparently checkout the working copy. | 442 """Runs git to update or transparently checkout the working copy. |
| 311 | 443 |
| 312 All updated files will be appended to file_list. | 444 All updated files will be appended to file_list. |
| 313 | 445 |
| 314 Raises: | 446 Raises: |
| 315 Error: if can't get URL for relative path. | 447 Error: if can't get URL for relative path. |
| 316 """ | 448 """ |
| 317 if args: | 449 if args: |
| 318 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 450 raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) |
| 319 | 451 |
| 320 self._CheckMinVersion("1.6.6") | 452 self._CheckMinVersion("1.6.6") |
| 321 | 453 |
| 322 # If a dependency is not pinned, track the default remote branch. | 454 # If a dependency is not pinned, track the default remote branch. |
| 323 default_rev = 'refs/remotes/%s/master' % self.remote | 455 default_rev = 'refs/remotes/%s/master' % (self.remote,) |
|
M-A Ruel
2014/06/24 21:18:11
Not needed.
dnj
2014/06/24 22:10:50
I think it looks cleaner to be explicit in formatt
M-A Ruel
2014/06/25 01:24:58
Please ask around to others if anyone else ever us
dnj
2014/06/25 01:55:06
I actually picked up this habit from iannucci@, wh
| |
| 324 url, deps_revision = gclient_utils.SplitUrlRevision(self.url) | 456 url, deps_revision = gclient_utils.SplitUrlRevision(self.url) |
| 325 rev_str = "" | 457 rev_str = "" |
| 326 revision = deps_revision | 458 revision = deps_revision |
| 327 managed = True | 459 managed = True |
| 328 if options.revision: | 460 if options.revision: |
| 329 # Override the revision number. | 461 # Override the revision number. |
| 330 revision = str(options.revision) | 462 revision = str(options.revision) |
| 331 if revision == 'unmanaged': | 463 if revision == 'unmanaged': |
| 332 # Check again for a revision in case an initial ref was specified | 464 # Check again for a revision in case an initial ref was specified |
| 333 # in the url, for example bla.git@refs/heads/custombranch | 465 # in the url, for example bla.git@refs/heads/custombranch |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 347 rev_str = ' at %s' % revision | 479 rev_str = ' at %s' % revision |
| 348 files = [] if file_list is not None else None | 480 files = [] if file_list is not None else None |
| 349 | 481 |
| 350 printed_path = False | 482 printed_path = False |
| 351 verbose = [] | 483 verbose = [] |
| 352 if options.verbose: | 484 if options.verbose: |
| 353 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 485 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) |
| 354 verbose = ['--verbose'] | 486 verbose = ['--verbose'] |
| 355 printed_path = True | 487 printed_path = True |
| 356 | 488 |
| 489 refish = self.ParseRefish(revision) | |
| 357 url = self._CreateOrUpdateCache(url, options) | 490 url = self._CreateOrUpdateCache(url, options) |
| 358 | 491 |
| 359 if revision.startswith('refs/'): | |
| 360 rev_type = "branch" | |
| 361 elif revision.startswith(self.remote + '/'): | |
| 362 # Rewrite remote refs to their local equivalents. | |
| 363 revision = 'refs/remotes/' + revision | |
| 364 rev_type = "branch" | |
| 365 else: | |
| 366 # hash is also a tag, only make a distinction at checkout | |
| 367 rev_type = "hash" | |
| 368 | |
| 369 if (not os.path.exists(self.checkout_path) or | 492 if (not os.path.exists(self.checkout_path) or |
| 370 (os.path.isdir(self.checkout_path) and | 493 (os.path.isdir(self.checkout_path) and |
| 371 not os.path.exists(os.path.join(self.checkout_path, '.git')))): | 494 not os.path.exists(os.path.join(self.checkout_path, '.git')))): |
| 372 try: | 495 try: |
| 373 self._Clone(revision, url, options) | 496 self._Clone(refish.local_ref, url, options) |
| 374 except subprocess2.CalledProcessError: | 497 except subprocess2.CalledProcessError: |
| 375 self._DeleteOrMove(options.force) | 498 self._DeleteOrMove(options.force) |
| 376 self._Clone(revision, url, options) | 499 self._Clone(refish.local_ref, url, options) |
| 377 if deps_revision and deps_revision.startswith('branch-heads/'): | 500 if deps_revision and deps_revision.startswith('branch-heads/'): |
| 378 deps_branch = deps_revision.replace('branch-heads/', '') | 501 deps_branch = deps_revision.replace('branch-heads/', '') |
| 379 self._Capture(['branch', deps_branch, deps_revision]) | 502 self._Capture(['branch', deps_branch, deps_revision]) |
| 380 self._Checkout(options, deps_branch, quiet=True) | 503 self._Checkout(options, deps_branch, quiet=True) |
| 381 if file_list is not None: | 504 if file_list is not None: |
| 382 files = self._Capture(['ls-files']).splitlines() | 505 files = self._Capture(['ls-files']).splitlines() |
| 383 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 506 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 384 if not verbose: | 507 if not verbose: |
| 385 # Make the output a little prettier. It's nice to have some whitespace | 508 # Make the output a little prettier. It's nice to have some whitespace |
| 386 # between projects when cloning. | 509 # between projects when cloning. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 404 if (current_url.rstrip('/') != url.rstrip('/') and | 527 if (current_url.rstrip('/') != url.rstrip('/') and |
| 405 url != 'git://foo' and | 528 url != 'git://foo' and |
| 406 subprocess2.capture( | 529 subprocess2.capture( |
| 407 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], | 530 ['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote], |
| 408 cwd=self.checkout_path).strip() != 'False'): | 531 cwd=self.checkout_path).strip() != 'False'): |
| 409 self.Print('_____ switching %s to a new upstream' % self.relpath) | 532 self.Print('_____ switching %s to a new upstream' % self.relpath) |
| 410 # Make sure it's clean | 533 # Make sure it's clean |
| 411 self._CheckClean(rev_str) | 534 self._CheckClean(rev_str) |
| 412 # Switch over to the new upstream | 535 # Switch over to the new upstream |
| 413 self._Run(['remote', 'set-url', self.remote, url], options) | 536 self._Run(['remote', 'set-url', self.remote, url], options) |
| 414 self._FetchAndReset(revision, file_list, options) | 537 self._FetchAndReset(refish, file_list, options) |
| 415 return_early = True | 538 return_early = True |
| 416 | 539 |
| 417 if return_early: | 540 if return_early: |
| 418 return self._Capture(['rev-parse', '--verify', 'HEAD']) | 541 return self._Capture(['rev-parse', '--verify', 'HEAD']) |
| 419 | 542 |
| 420 cur_branch = self._GetCurrentBranch() | 543 cur_branch = self._GetCurrentBranch() |
| 421 | 544 |
| 422 # Cases: | 545 # Cases: |
| 423 # 0) HEAD is detached. Probably from our initial clone. | 546 # 0) HEAD is detached. Probably from our initial clone. |
| 424 # - make sure HEAD is contained by a named ref, then update. | 547 # - make sure HEAD is contained by a named ref, then update. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 447 upstream_branch = scm.GIT.GetUpstreamBranch(self.checkout_path) | 570 upstream_branch = scm.GIT.GetUpstreamBranch(self.checkout_path) |
| 448 if not upstream_branch or not upstream_branch.startswith('refs/remotes'): | 571 if not upstream_branch or not upstream_branch.startswith('refs/remotes'): |
| 449 current_type = "hash" | 572 current_type = "hash" |
| 450 logging.debug("Current branch is not tracking an upstream (remote)" | 573 logging.debug("Current branch is not tracking an upstream (remote)" |
| 451 " branch.") | 574 " branch.") |
| 452 elif upstream_branch.startswith('refs/remotes'): | 575 elif upstream_branch.startswith('refs/remotes'): |
| 453 current_type = "branch" | 576 current_type = "branch" |
| 454 else: | 577 else: |
| 455 raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) | 578 raise gclient_utils.Error('Invalid Upstream: %s' % upstream_branch) |
| 456 | 579 |
| 457 if not scm.GIT.IsValidRevision(self.checkout_path, revision, sha_only=True): | 580 if not scm.GIT.IsValidRevision(self.checkout_path, refish.local_ref, |
| 581 sha_only=True): | |
| 458 # Update the remotes first so we have all the refs. | 582 # Update the remotes first so we have all the refs. |
| 459 remote_output = scm.GIT.Capture(['remote'] + verbose + ['update'], | 583 remote_output = scm.GIT.Capture(['remote'] + verbose + ['update'], |
| 460 cwd=self.checkout_path) | 584 cwd=self.checkout_path) |
| 461 if verbose: | 585 if verbose: |
| 462 self.Print(remote_output) | 586 self.Print(remote_output) |
| 463 | 587 |
| 464 self._UpdateBranchHeads(options, fetch=True) | 588 self._UpdateBranchHeads(options, fetch=True) |
| 465 | 589 |
| 466 # This is a big hammer, debatable if it should even be here... | 590 # This is a big hammer, debatable if it should even be here... |
| 467 if options.force or options.reset: | 591 if options.force or options.reset: |
| 468 target = 'HEAD' | 592 target = 'HEAD' |
| 469 if options.upstream and upstream_branch: | 593 if options.upstream and upstream_branch: |
| 470 target = upstream_branch | 594 target = upstream_branch |
| 471 self._Run(['reset', '--hard', target], options) | 595 self._Run(['reset', '--hard', target], options) |
| 472 | 596 |
| 473 if current_type == 'detached': | 597 if current_type == 'detached': |
| 474 # case 0 | 598 # case 0 |
| 475 self._CheckClean(rev_str) | 599 self._CheckClean(rev_str) |
| 476 self._CheckDetachedHead(rev_str, options) | 600 self._CheckDetachedHead(rev_str, options) |
| 477 if self._Capture(['rev-list', '-n', '1', 'HEAD']) == revision: | 601 if self._Capture(['rev-list', '-n', '1', 'HEAD']) == refish.local_ref: |
| 478 self.Print('Up-to-date; skipping checkout.') | 602 self.Print('Up-to-date; skipping checkout.') |
| 479 else: | 603 else: |
| 480 self._Checkout(options, revision, quiet=True) | 604 self._Checkout(options, refish.local_ref, quiet=True) |
| 481 if not printed_path: | 605 if not printed_path: |
| 482 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 606 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) |
| 483 elif current_type == 'hash': | 607 elif current_type == 'hash': |
| 484 # case 1 | 608 # case 1 |
| 485 if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None: | 609 if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None: |
| 486 # Our git-svn branch (upstream_branch) is our upstream | 610 # Our git-svn branch (upstream_branch) is our upstream |
| 487 self._AttemptRebase(upstream_branch, files, options, | 611 self._AttemptRebase(upstream_branch, files, options, |
| 488 newbase=revision, printed_path=printed_path, | 612 newbase=refish.local_ref, |
| 489 merge=options.merge) | 613 printed_path=printed_path, merge=options.merge) |
| 490 printed_path = True | 614 printed_path = True |
| 491 else: | 615 else: |
| 492 # Can't find a merge-base since we don't know our upstream. That makes | 616 # Can't find a merge-base since we don't know our upstream. That makes |
| 493 # this command VERY likely to produce a rebase failure. For now we | 617 # this command VERY likely to produce a rebase failure. For now we |
| 494 # assume origin is our upstream since that's what the old behavior was. | 618 # assume origin is our upstream since that's what the old behavior was. |
| 495 upstream_branch = self.remote | 619 upstream_branch = self.remote |
| 496 if options.revision or deps_revision: | 620 if options.revision or deps_revision: |
| 497 upstream_branch = revision | 621 upstream_branch = refish.local_ref |
| 498 self._AttemptRebase(upstream_branch, files, options, | 622 self._AttemptRebase(upstream_branch, files, options, |
| 499 printed_path=printed_path, merge=options.merge) | 623 printed_path=printed_path, merge=options.merge) |
| 500 printed_path = True | 624 printed_path = True |
| 501 elif rev_type == 'hash': | 625 elif not refish.is_branch: |
| 502 # case 2 | 626 # case 2 |
| 503 self._AttemptRebase(upstream_branch, files, options, | 627 self._AttemptRebase(upstream_branch, files, options, |
| 504 newbase=revision, printed_path=printed_path, | 628 newbase=refish.local_ref, printed_path=printed_path, |
| 505 merge=options.merge) | 629 merge=options.merge) |
| 506 printed_path = True | 630 printed_path = True |
| 507 elif revision.replace('heads', 'remotes/' + self.remote) != upstream_branch: | 631 elif refish.upstream_branch != upstream_branch: |
| 508 # case 4 | 632 # case 4 |
| 509 new_base = revision.replace('heads', 'remotes/' + self.remote) | 633 new_base = refish.upstream_branch |
| 510 if not printed_path: | 634 if not printed_path: |
| 511 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 635 self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) |
| 512 switch_error = ("Switching upstream branch from %s to %s\n" | 636 switch_error = ("Switching upstream branch from %s to %s\n" |
| 513 % (upstream_branch, new_base) + | 637 % (upstream_branch, new_base) + |
| 514 "Please merge or rebase manually:\n" + | 638 "Please merge or rebase manually:\n" + |
| 515 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + | 639 "cd %s; git rebase %s\n" % (self.checkout_path, new_base) + |
| 516 "OR git checkout -b <some new branch> %s" % new_base) | 640 "OR git checkout -b <some new branch> %s" % new_base) |
| 517 raise gclient_utils.Error(switch_error) | 641 raise gclient_utils.Error(switch_error) |
| 518 else: | 642 else: |
| 519 # case 3 - the default case | 643 # case 3 - the default case |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 630 return self.update(options, [], file_list) | 754 return self.update(options, [], file_list) |
| 631 | 755 |
| 632 default_rev = "refs/heads/master" | 756 default_rev = "refs/heads/master" |
| 633 if options.upstream: | 757 if options.upstream: |
| 634 if self._GetCurrentBranch(): | 758 if self._GetCurrentBranch(): |
| 635 upstream_branch = scm.GIT.GetUpstreamBranch(self.checkout_path) | 759 upstream_branch = scm.GIT.GetUpstreamBranch(self.checkout_path) |
| 636 default_rev = upstream_branch or default_rev | 760 default_rev = upstream_branch or default_rev |
| 637 _, deps_revision = gclient_utils.SplitUrlRevision(self.url) | 761 _, deps_revision = gclient_utils.SplitUrlRevision(self.url) |
| 638 if not deps_revision: | 762 if not deps_revision: |
| 639 deps_revision = default_rev | 763 deps_revision = default_rev |
| 640 if deps_revision.startswith('refs/heads/'): | 764 refish = self.ParseRefish(deps_revision) |
| 641 deps_revision = deps_revision.replace('refs/heads/', self.remote + '/') | 765 deps_revision = self.GetUsableRev(refish.remote_refspec, options) |
| 642 deps_revision = self.GetUsableRev(deps_revision, options) | |
| 643 | 766 |
| 644 if file_list is not None: | 767 if file_list is not None: |
| 645 files = self._Capture(['diff', deps_revision, '--name-only']).split() | 768 files = self._Capture(['diff', deps_revision, '--name-only']).split() |
| 646 | 769 |
| 647 self._Run(['reset', '--hard', deps_revision], options) | 770 self._Run(['reset', '--hard', deps_revision], options) |
| 648 self._Run(['clean', '-f', '-d'], options) | 771 self._Run(['clean', '-f', '-d'], options) |
| 649 | 772 |
| 650 if file_list is not None: | 773 if file_list is not None: |
| 651 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 774 file_list.extend([os.path.join(self.checkout_path, f) for f in files]) |
| 652 | 775 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 812 gclient_utils.safe_rename(os.path.join(tmp_dir, '.git'), | 935 gclient_utils.safe_rename(os.path.join(tmp_dir, '.git'), |
| 813 os.path.join(self.checkout_path, '.git')) | 936 os.path.join(self.checkout_path, '.git')) |
| 814 except: | 937 except: |
| 815 traceback.print_exc(file=self.out_fh) | 938 traceback.print_exc(file=self.out_fh) |
| 816 raise | 939 raise |
| 817 finally: | 940 finally: |
| 818 if os.listdir(tmp_dir): | 941 if os.listdir(tmp_dir): |
| 819 self.Print('_____ removing non-empty tmp dir %s' % tmp_dir) | 942 self.Print('_____ removing non-empty tmp dir %s' % tmp_dir) |
| 820 gclient_utils.rmtree(tmp_dir) | 943 gclient_utils.rmtree(tmp_dir) |
| 821 self._UpdateBranchHeads(options, fetch=True) | 944 self._UpdateBranchHeads(options, fetch=True) |
| 822 self._Checkout(options, revision.replace('refs/heads/', ''), quiet=True) | 945 |
| 946 refish = self.ParseRefish(revision) | |
| 947 self._Checkout(options, refish.local_ref, quiet=True) | |
| 823 if self._GetCurrentBranch() is None: | 948 if self._GetCurrentBranch() is None: |
| 824 # Squelch git's very verbose detached HEAD warning and use our own | 949 # Squelch git's very verbose detached HEAD warning and use our own |
| 825 self.Print( | 950 self.Print("""\ |
| 826 ('Checked out %s to a detached HEAD. Before making any commits\n' | 951 Checked out %s to a detached HEAD. Before making any commits |
|
M-A Ruel
2014/06/24 21:18:11
It really breaks vim collapsing when using indent
dnj
2014/06/24 22:10:50
Done.
| |
| 827 'in this repo, you should use \'git checkout <branch>\' to switch to\n' | 952 in this repo, you should use 'git checkout <branch>' to switch to |
| 828 'an existing branch or use \'git checkout %s -b <branch>\' to\n' | 953 an existing branch or use 'git checkout %s -b <branch>' to |
| 829 'create a new branch for your work.') % (revision, self.remote)) | 954 create a new branch for your work.""" % (revision, self.remote)) |
| 830 | 955 |
| 831 def _AskForData(self, prompt, options): | 956 def _AskForData(self, prompt, options): |
| 832 if options.jobs > 1: | 957 if options.jobs > 1: |
| 833 self.Print(prompt) | 958 self.Print(prompt) |
| 834 raise gclient_utils.Error("Background task requires input. Rerun " | 959 raise gclient_utils.Error("Background task requires input. Rerun " |
| 835 "gclient with --jobs=1 so that\n" | 960 "gclient with --jobs=1 so that\n" |
| 836 "interaction is possible.") | 961 "interaction is possible.") |
| 837 try: | 962 try: |
| 838 return raw_input(prompt) | 963 return raw_input(prompt) |
| 839 except KeyboardInterrupt: | 964 except KeyboardInterrupt: |
| (...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1513 new_command.append('--force') | 1638 new_command.append('--force') |
| 1514 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1639 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1515 new_command.extend(('--accept', 'theirs-conflict')) | 1640 new_command.extend(('--accept', 'theirs-conflict')) |
| 1516 elif options.manually_grab_svn_rev: | 1641 elif options.manually_grab_svn_rev: |
| 1517 new_command.append('--force') | 1642 new_command.append('--force') |
| 1518 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1643 if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1519 new_command.extend(('--accept', 'postpone')) | 1644 new_command.extend(('--accept', 'postpone')) |
| 1520 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 1645 elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: |
| 1521 new_command.extend(('--accept', 'postpone')) | 1646 new_command.extend(('--accept', 'postpone')) |
| 1522 return new_command | 1647 return new_command |
| OLD | NEW |