| Index: gclient_scm.py | 
| diff --git a/gclient_scm.py b/gclient_scm.py | 
| index cb8e6f31746403e63f9f3fa17e16102cc23cacfd..d46d47eef0c514a72b30da7e159822fafd40c034 100644 | 
| --- a/gclient_scm.py | 
| +++ b/gclient_scm.py | 
| @@ -37,14 +37,14 @@ class NoUsableRevError(gclient_utils.Error): | 
| class DiffFiltererWrapper(object): | 
| """Simple base class which tracks which file is being diffed and | 
| replaces instances of its file name in the original and | 
| -  working copy lines of the svn/git diff output.""" | 
| +  working copy lines of the git diff output.""" | 
| index_string = None | 
| original_prefix = "--- " | 
| working_prefix = "+++ " | 
|  | 
| def __init__(self, relpath, print_func): | 
| # Note that we always use '/' as the path separator to be | 
| -    # consistent with svn's cygwin-style output on Windows | 
| +    # consistent with cygwin-style output on Windows | 
| self._relpath = relpath.replace("\\", "/") | 
| self._current_file = None | 
| self._print_func = print_func | 
| @@ -70,10 +70,6 @@ class DiffFiltererWrapper(object): | 
| self._print_func(line) | 
|  | 
|  | 
| -class SvnDiffFilterer(DiffFiltererWrapper): | 
| -  index_string = "Index: " | 
| - | 
| - | 
| class GitDiffFilterer(DiffFiltererWrapper): | 
| index_string = "diff --git " | 
|  | 
| @@ -90,26 +86,20 @@ class GitDiffFilterer(DiffFiltererWrapper): | 
| # Factory Method for SCM wrapper creation | 
|  | 
| def GetScmName(url): | 
| -  if url: | 
| -    url, _ = gclient_utils.SplitUrlRevision(url) | 
| -    if (url.startswith('git://') or url.startswith('ssh://') or | 
| -        url.startswith('git+http://') or url.startswith('git+https://') or | 
| -        url.endswith('.git') or url.startswith('sso://') or | 
| -        'googlesource' in url): | 
| -      return 'git' | 
| -    elif (url.startswith('http://') or url.startswith('https://') or | 
| -          url.startswith('svn://') or url.startswith('svn+ssh://')): | 
| -      return 'svn' | 
| -    elif url.startswith('file://'): | 
| -      if url.endswith('.git'): | 
| -        return 'git' | 
| -      return 'svn' | 
| +  if not url: | 
| +    return None | 
| +  url, _ = gclient_utils.SplitUrlRevision(url) | 
| +  if url.endswith('.git'): | 
| +    return 'git' | 
| +  protocol = url.split('://')[0] | 
| +  if protocol in ( | 
| +      'file', 'git', 'git+http', 'git+https', 'http', 'https', 'ssh', 'sso'): | 
| +    return 'git' | 
| return None | 
|  | 
|  | 
| def CreateSCM(url, root_dir=None, relpath=None, out_fh=None, out_cb=None): | 
| SCM_MAP = { | 
| -    'svn' : SVNWrapper, | 
| 'git' : GitWrapper, | 
| } | 
|  | 
| @@ -192,10 +182,6 @@ class SCMWrapper(object): | 
| actual_remote_url.replace('\\', '/')): | 
| actual_remote_url = self._get_first_remote_url(mirror.mirror_path) | 
| return actual_remote_url | 
| - | 
| -    # Svn | 
| -    if os.path.exists(os.path.join(self.checkout_path, '.svn')): | 
| -      return scm.SVN.CaptureLocalInfo([], self.checkout_path)['URL'] | 
| return None | 
|  | 
| def DoesRemoteURLMatch(self, options): | 
| @@ -210,7 +196,7 @@ class SCMWrapper(object): | 
| == gclient_utils.SplitUrlRevision(self.url)[0].rstrip('/')) | 
| else: | 
| # This may occur if the self.checkout_path exists but does not contain a | 
| -      # valid git or svn checkout. | 
| +      # valid git checkout. | 
| return False | 
|  | 
| def _DeleteOrMove(self, force): | 
| @@ -503,7 +489,7 @@ class GitWrapper(SCMWrapper): | 
| # 0) HEAD is detached. Probably from our initial clone. | 
| #   - make sure HEAD is contained by a named ref, then update. | 
| # Cases 1-4. HEAD is a branch. | 
| -    # 1) current branch is not tracking a remote branch (could be git-svn) | 
| +    # 1) current branch is not tracking a remote branch | 
| #   - try to rebase onto the new hash or branch | 
| # 2) current branch is tracking a remote branch with local committed | 
| #    changes, but the DEPS file switched to point to a hash | 
| @@ -573,22 +559,15 @@ class GitWrapper(SCMWrapper): | 
| self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 
| elif current_type == 'hash': | 
| # case 1 | 
| -      if scm.GIT.IsGitSvn(self.checkout_path) and upstream_branch is not None: | 
| -        # Our git-svn branch (upstream_branch) is our upstream | 
| -        self._AttemptRebase(upstream_branch, files, options, | 
| -                            newbase=revision, printed_path=printed_path, | 
| -                            merge=options.merge) | 
| -        printed_path = True | 
| -      else: | 
| -        # Can't find a merge-base since we don't know our upstream. That makes | 
| -        # this command VERY likely to produce a rebase failure. For now we | 
| -        # assume origin is our upstream since that's what the old behavior was. | 
| -        upstream_branch = self.remote | 
| -        if options.revision or deps_revision: | 
| -          upstream_branch = revision | 
| -        self._AttemptRebase(upstream_branch, files, options, | 
| -                            printed_path=printed_path, merge=options.merge) | 
| -        printed_path = True | 
| +      # Can't find a merge-base since we don't know our upstream. That makes | 
| +      # this command VERY likely to produce a rebase failure. For now we | 
| +      # assume origin is our upstream since that's what the old behavior was. | 
| +      upstream_branch = self.remote | 
| +      if options.revision or deps_revision: | 
| +        upstream_branch = revision | 
| +      self._AttemptRebase(upstream_branch, files, options, | 
| +                          printed_path=printed_path, merge=options.merge) | 
| +      printed_path = True | 
| elif rev_type == 'hash': | 
| # case 2 | 
| self._AttemptRebase(upstream_branch, files, options, | 
| @@ -788,16 +767,13 @@ class GitWrapper(SCMWrapper): | 
| except subprocess2.CalledProcessError: | 
| merge_base = [] | 
| self._Run(['diff', '--name-status'] + merge_base, options, | 
| -                stdout=self.out_fh) | 
| +                stdout=self.out_fh, always=options.verbose) | 
| if file_list is not None: | 
| files = self._Capture(['diff', '--name-only'] + merge_base).split() | 
| file_list.extend([os.path.join(self.checkout_path, f) for f in files]) | 
|  | 
| def GetUsableRev(self, rev, options): | 
| -    """Finds a useful revision for this repository. | 
| - | 
| -    If SCM is git-svn and the head revision is less than |rev|, git svn fetch | 
| -    will be called on the source.""" | 
| +    """Finds a useful revision for this repository.""" | 
| sha1 = None | 
| if not os.path.isdir(self.checkout_path): | 
| raise NoUsableRevError( | 
| @@ -807,56 +783,23 @@ class GitWrapper(SCMWrapper): | 
| 'For more info, see: ' | 
| 'http://code.google.com/p/chromium/wiki/UsingNewGit' | 
| '#Initial_checkout' ) % rev) | 
| -    elif rev.isdigit() and len(rev) < 7: | 
| -      # Handles an SVN rev.  As an optimization, only verify an SVN revision as | 
| -      # [0-9]{1,6} for now to avoid making a network request. | 
| -      if scm.GIT.IsGitSvn(cwd=self.checkout_path): | 
| -        local_head = scm.GIT.GetGitSvnHeadRev(cwd=self.checkout_path) | 
| -        if not local_head or local_head < int(rev): | 
| -          try: | 
| -            logging.debug('Looking for git-svn configuration optimizations.') | 
| -            if scm.GIT.Capture(['config', '--get', 'svn-remote.svn.fetch'], | 
| -                             cwd=self.checkout_path): | 
| -              self._Fetch(options) | 
| -          except subprocess2.CalledProcessError: | 
| -            logging.debug('git config --get svn-remote.svn.fetch failed, ' | 
| -                          'ignoring possible optimization.') | 
| -          if options.verbose: | 
| -            self.Print('Running git svn fetch. This might take a while.\n') | 
| -          scm.GIT.Capture(['svn', 'fetch'], cwd=self.checkout_path) | 
| -        try: | 
| -          sha1 = scm.GIT.GetBlessedSha1ForSvnRev( | 
| -              cwd=self.checkout_path, rev=rev) | 
| -        except gclient_utils.Error, e: | 
| -          sha1 = e.message | 
| -          self.Print('Warning: Could not find a git revision with accurate\n' | 
| -                 '.DEPS.git that maps to SVN revision %s.  Sync-ing to\n' | 
| -                 'the closest sane git revision, which is:\n' | 
| -                 '  %s\n' % (rev, e.message)) | 
| -        if not sha1: | 
| -          raise NoUsableRevError( | 
| -              ( 'It appears that either your git-svn remote is incorrectly\n' | 
| -                'configured or the revision in your safesync_url is\n' | 
| -                'higher than git-svn remote\'s HEAD as we couldn\'t find a\n' | 
| -                'corresponding git hash for SVN rev %s.' ) % rev) | 
| + | 
| +    if scm.GIT.IsValidRevision(cwd=self.checkout_path, rev=rev): | 
| +      sha1 = rev | 
| else: | 
| +      # May exist in origin, but we don't have it yet, so fetch and look | 
| +      # again. | 
| +      self._Fetch(options) | 
| if scm.GIT.IsValidRevision(cwd=self.checkout_path, rev=rev): | 
| sha1 = rev | 
| -      else: | 
| -        # May exist in origin, but we don't have it yet, so fetch and look | 
| -        # again. | 
| -        self._Fetch(options) | 
| -        if scm.GIT.IsValidRevision(cwd=self.checkout_path, rev=rev): | 
| -          sha1 = rev | 
|  | 
| if not sha1: | 
| raise NoUsableRevError( | 
| -          ( 'We could not find a valid hash for safesync_url response "%s".\n' | 
| -            'Safesync URLs with a git checkout currently require a git-svn\n' | 
| -            'remote or a safesync_url that provides git sha1s. Please add a\n' | 
| -            'git-svn remote or change your safesync_url. For more info, see:\n' | 
| -            'http://code.google.com/p/chromium/wiki/UsingNewGit' | 
| -            '#Initial_checkout' ) % rev) | 
| +          ('We could not find a valid hash for safesync_url response "%s".\n' | 
| +           'Please ensure that your safesync_url provides git sha1 hashes.\n' | 
| +           'For more info, see:\n' | 
| +           'http://code.google.com/p/chromium/wiki/UsingNewGit#Initial_checkout' | 
| +          ) % rev) | 
|  | 
| return sha1 | 
|  | 
| @@ -1239,480 +1182,3 @@ class GitWrapper(SCMWrapper): | 
| gclient_utils.CheckCallAndFilterAndHeader(cmd, env=env, **kwargs) | 
| else: | 
| gclient_utils.CheckCallAndFilter(cmd, env=env, **kwargs) | 
| - | 
| - | 
| -class SVNWrapper(SCMWrapper): | 
| -  """ Wrapper for SVN """ | 
| -  name = 'svn' | 
| -  _PRINTED_DEPRECATION = False | 
| - | 
| -  _MESSAGE = ( | 
| -    'Oh hai! You are using subversion. Chrome infra is eager to get rid of', | 
| -    'svn support so please switch to git.', | 
| -    'Tracking bug: http://crbug.com/475320', | 
| -    'If you are a project owner, you may request git migration assistance at: ', | 
| -    '  https://code.google.com/p/chromium/issues/entry?template=Infra-Git') | 
| - | 
| -  def __init__(self, *args, **kwargs): | 
| -    super(SVNWrapper, self).__init__(*args, **kwargs) | 
| -    suppress_deprecated_notice = os.environ.get( | 
| -        'SUPPRESS_DEPRECATED_SVN_NOTICE', False) | 
| -    if not SVNWrapper._PRINTED_DEPRECATION and not suppress_deprecated_notice: | 
| -      SVNWrapper._PRINTED_DEPRECATION = True | 
| -      sys.stderr.write('\n'.join(self._MESSAGE) + '\n') | 
| - | 
| -  @staticmethod | 
| -  def BinaryExists(): | 
| -    """Returns true if the command exists.""" | 
| -    try: | 
| -      result, version = scm.SVN.AssertVersion('1.4') | 
| -      if not result: | 
| -        raise gclient_utils.Error('SVN version is older than 1.4: %s' % version) | 
| -      return result | 
| -    except OSError: | 
| -      return False | 
| - | 
| -  def GetCheckoutRoot(self): | 
| -    return scm.SVN.GetCheckoutRoot(self.checkout_path) | 
| - | 
| -  def GetRevisionDate(self, revision): | 
| -    """Returns the given revision's date in ISO-8601 format (which contains the | 
| -    time zone).""" | 
| -    date = scm.SVN.Capture( | 
| -        ['propget', '--revprop', 'svn:date', '-r', revision], | 
| -        os.path.join(self.checkout_path, '.')) | 
| -    return date.strip() | 
| - | 
| -  def cleanup(self, options, args, _file_list): | 
| -    """Cleanup working copy.""" | 
| -    self._Run(['cleanup'] + args, options) | 
| - | 
| -  def diff(self, options, args, _file_list): | 
| -    # NOTE: This function does not currently modify file_list. | 
| -    if not os.path.isdir(self.checkout_path): | 
| -      raise gclient_utils.Error('Directory %s is not present.' % | 
| -          self.checkout_path) | 
| -    self._Run(['diff'] + args, options) | 
| - | 
| -  def pack(self, _options, args, _file_list): | 
| -    """Generates a patch file which can be applied to the root of the | 
| -    repository.""" | 
| -    if not os.path.isdir(self.checkout_path): | 
| -      raise gclient_utils.Error('Directory %s is not present.' % | 
| -          self.checkout_path) | 
| -    gclient_utils.CheckCallAndFilter( | 
| -        ['svn', 'diff', '-x', '--ignore-eol-style'] + args, | 
| -        cwd=self.checkout_path, | 
| -        print_stdout=False, | 
| -        filter_fn=SvnDiffFilterer(self.relpath, print_func=self.Print).Filter) | 
| - | 
| -  def update(self, options, args, file_list): | 
| -    """Runs svn to update or transparently checkout the working copy. | 
| - | 
| -    All updated files will be appended to file_list. | 
| - | 
| -    Raises: | 
| -      Error: if can't get URL for relative path. | 
| -    """ | 
| -    # Only update if hg is not controlling the directory. | 
| -    hg_path = os.path.join(self.checkout_path, '.hg') | 
| -    if os.path.exists(hg_path): | 
| -      self.Print('________ found .hg directory; skipping %s' % self.relpath) | 
| -      return | 
| - | 
| -    if args: | 
| -      raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args)) | 
| - | 
| -    # revision is the revision to match. It is None if no revision is specified, | 
| -    # i.e. the 'deps ain't pinned'. | 
| -    url, revision = gclient_utils.SplitUrlRevision(self.url) | 
| -    # Keep the original unpinned url for reference in case the repo is switched. | 
| -    base_url = url | 
| -    managed = True | 
| -    if options.revision: | 
| -      # Override the revision number. | 
| -      revision = str(options.revision) | 
| -    if revision: | 
| -      if revision != 'unmanaged': | 
| -        forced_revision = True | 
| -        # Reconstruct the url. | 
| -        url = '%s@%s' % (url, revision) | 
| -        rev_str = ' at %s' % revision | 
| -      else: | 
| -        managed = False | 
| -        revision = None | 
| -    else: | 
| -      forced_revision = False | 
| -      rev_str = '' | 
| - | 
| -    exists = os.path.exists(self.checkout_path) | 
| -    if exists and managed: | 
| -      # Git is only okay if it's a git-svn checkout of the right repo. | 
| -      if scm.GIT.IsGitSvn(self.checkout_path): | 
| -        remote_url = scm.GIT.Capture(['config', '--local', '--get', | 
| -                                      'svn-remote.svn.url'], | 
| -                                     cwd=self.checkout_path).rstrip() | 
| -        if remote_url.rstrip('/') == base_url.rstrip('/'): | 
| -          self.Print('\n_____ %s looks like a git-svn checkout. Skipping.' | 
| -                     % self.relpath) | 
| -          return # TODO(borenet): Get the svn revision number? | 
| - | 
| -    # Get the existing scm url and the revision number of the current checkout. | 
| -    if exists and managed: | 
| -      try: | 
| -        from_info = scm.SVN.CaptureLocalInfo( | 
| -            [], os.path.join(self.checkout_path, '.')) | 
| -      except (gclient_utils.Error, subprocess2.CalledProcessError): | 
| -        self._DeleteOrMove(options.force) | 
| -        exists = False | 
| - | 
| -    BASE_URLS = { | 
| -        '/chrome/trunk/src': 'gs://chromium-svn-checkout/chrome/', | 
| -        '/blink/trunk': 'gs://chromium-svn-checkout/blink/', | 
| -    } | 
| -    WHITELISTED_ROOTS = [ | 
| -        'svn://svn.chromium.org', | 
| -        'svn://svn-mirror.golo.chromium.org', | 
| -    ] | 
| -    if not exists: | 
| -      try: | 
| -        # Split out the revision number since it's not useful for us. | 
| -        base_path = urlparse.urlparse(url).path.split('@')[0] | 
| -        # Check to see if we're on a whitelisted root.  We do this because | 
| -        # only some svn servers have matching UUIDs. | 
| -        local_parsed = urlparse.urlparse(url) | 
| -        local_root = '%s://%s' % (local_parsed.scheme, local_parsed.netloc) | 
| -        if ('CHROME_HEADLESS' in os.environ | 
| -            and sys.platform == 'linux2'  # TODO(hinoka): Enable for win/mac. | 
| -            and base_path in BASE_URLS | 
| -            and local_root in WHITELISTED_ROOTS): | 
| - | 
| -          # Use a tarball for initial sync if we are on a bot. | 
| -          # Get an unauthenticated gsutil instance. | 
| -          gsutil = download_from_google_storage.Gsutil( | 
| -              GSUTIL_DEFAULT_PATH, boto_path=os.devnull) | 
| - | 
| -          gs_path = BASE_URLS[base_path] | 
| -          _, out, _ = gsutil.check_call('ls', gs_path) | 
| -          # So that we can get the most recent revision. | 
| -          sorted_items = sorted(out.splitlines()) | 
| -          latest_checkout = sorted_items[-1] | 
| - | 
| -          tempdir = tempfile.mkdtemp() | 
| -          self.Print('Downloading %s...' % latest_checkout) | 
| -          code, out, err = gsutil.check_call('cp', latest_checkout, tempdir) | 
| -          if code: | 
| -            self.Print('%s\n%s' % (out, err)) | 
| -            raise Exception() | 
| -          filename = latest_checkout.split('/')[-1] | 
| -          tarball = os.path.join(tempdir, filename) | 
| -          self.Print('Unpacking into %s...' % self.checkout_path) | 
| -          gclient_utils.safe_makedirs(self.checkout_path) | 
| -          # TODO(hinoka): Use 7z for windows. | 
| -          cmd = ['tar', '--extract', '--ungzip', | 
| -                  '--directory', self.checkout_path, | 
| -                  '--file', tarball] | 
| -          gclient_utils.CheckCallAndFilter( | 
| -              cmd, stdout=sys.stdout, print_stdout=True) | 
| - | 
| -          self.Print('Deleting temp file') | 
| -          gclient_utils.rmtree(tempdir) | 
| - | 
| -          # Rewrite the repository root to match. | 
| -          tarball_url = scm.SVN.CaptureLocalInfo( | 
| -              ['.'], self.checkout_path)['Repository Root'] | 
| -          tarball_parsed = urlparse.urlparse(tarball_url) | 
| -          tarball_root = '%s://%s' % (tarball_parsed.scheme, | 
| -                                      tarball_parsed.netloc) | 
| - | 
| -          if tarball_root != local_root: | 
| -            self.Print('Switching repository root to %s' % local_root) | 
| -            self._Run(['switch', '--relocate', tarball_root, | 
| -                       local_root, self.checkout_path], | 
| -                      options) | 
| -      except Exception as e: | 
| -        self.Print('We tried to get a source tarball but failed.') | 
| -        self.Print('Resuming normal operations.') | 
| -        self.Print(str(e)) | 
| - | 
| -      gclient_utils.safe_makedirs(os.path.dirname(self.checkout_path)) | 
| -      # We need to checkout. | 
| -      command = ['checkout', url, self.checkout_path] | 
| -      command = self._AddAdditionalUpdateFlags(command, options, revision) | 
| -      self._RunAndGetFileList(command, options, file_list, self._root_dir) | 
| -      return self.Svnversion() | 
| - | 
| -    if not managed: | 
| -      self.Print(('________ unmanaged solution; skipping %s' % self.relpath)) | 
| -      if os.path.exists(os.path.join(self.checkout_path, '.svn')): | 
| -        return self.Svnversion() | 
| -      return | 
| - | 
| -    if 'URL' not in from_info: | 
| -      raise gclient_utils.Error( | 
| -          ('gclient is confused. Couldn\'t get the url for %s.\n' | 
| -           'Try using @unmanaged.\n%s') % ( | 
| -            self.checkout_path, from_info)) | 
| - | 
| -    # Look for locked directories. | 
| -    dir_info = scm.SVN.CaptureStatus( | 
| -        None, os.path.join(self.checkout_path, '.')) | 
| -    if any(d[0][2] == 'L' for d in dir_info): | 
| -      try: | 
| -        self._Run(['cleanup', self.checkout_path], options) | 
| -      except subprocess2.CalledProcessError, e: | 
| -        # Get the status again, svn cleanup may have cleaned up at least | 
| -        # something. | 
| -        dir_info = scm.SVN.CaptureStatus( | 
| -            None, os.path.join(self.checkout_path, '.')) | 
| - | 
| -        # Try to fix the failures by removing troublesome files. | 
| -        for d in dir_info: | 
| -          if d[0][2] == 'L': | 
| -            if d[0][0] == '!' and options.force: | 
| -              # We don't pass any files/directories to CaptureStatus and set | 
| -              # cwd=self.checkout_path, so we should get relative paths here. | 
| -              assert not os.path.isabs(d[1]) | 
| -              path_to_remove = os.path.normpath( | 
| -                  os.path.join(self.checkout_path, d[1])) | 
| -              self.Print('Removing troublesome path %s' % path_to_remove) | 
| -              gclient_utils.rmtree(path_to_remove) | 
| -            else: | 
| -              self.Print( | 
| -                  'Not removing troublesome path %s automatically.' % d[1]) | 
| -              if d[0][0] == '!': | 
| -                self.Print('You can pass --force to enable automatic removal.') | 
| -              raise e | 
| - | 
| -    if from_info['URL'].rstrip('/') != base_url.rstrip('/'): | 
| -      # The repository url changed, need to switch. | 
| -      try: | 
| -        to_info = scm.SVN.CaptureRemoteInfo(url) | 
| -      except (gclient_utils.Error, subprocess2.CalledProcessError): | 
| -        # The url is invalid or the server is not accessible, it's safer to bail | 
| -        # out right now. | 
| -        raise gclient_utils.Error('This url is unreachable: %s' % url) | 
| -      can_switch = ((from_info['Repository Root'] != to_info['Repository Root']) | 
| -                    and (from_info['UUID'] == to_info['UUID'])) | 
| -      if can_switch: | 
| -        self.Print('_____ relocating %s to a new checkout' % self.relpath) | 
| -        # We have different roots, so check if we can switch --relocate. | 
| -        # Subversion only permits this if the repository UUIDs match. | 
| -        # Perform the switch --relocate, then rewrite the from_url | 
| -        # to reflect where we "are now."  (This is the same way that | 
| -        # Subversion itself handles the metadata when switch --relocate | 
| -        # is used.)  This makes the checks below for whether we | 
| -        # can update to a revision or have to switch to a different | 
| -        # branch work as expected. | 
| -        # TODO(maruel):  TEST ME ! | 
| -        command = ['switch', '--relocate', | 
| -                   from_info['Repository Root'], | 
| -                   to_info['Repository Root'], | 
| -                   self.relpath] | 
| -        self._Run(command, options, cwd=self._root_dir) | 
| -        from_info['URL'] = from_info['URL'].replace( | 
| -            from_info['Repository Root'], | 
| -            to_info['Repository Root']) | 
| -      else: | 
| -        if not options.force and not options.reset: | 
| -          # Look for local modifications but ignore unversioned files. | 
| -          for status in scm.SVN.CaptureStatus(None, self.checkout_path): | 
| -            if status[0][0] != '?': | 
| -              raise gclient_utils.Error( | 
| -                  ('Can\'t switch the checkout to %s; UUID don\'t match and ' | 
| -                   'there is local changes in %s. Delete the directory and ' | 
| -                   'try again.') % (url, self.checkout_path)) | 
| -        # Ok delete it. | 
| -        self.Print('_____ switching %s to a new checkout' % self.relpath) | 
| -        gclient_utils.rmtree(self.checkout_path) | 
| -        # We need to checkout. | 
| -        command = ['checkout', url, self.checkout_path] | 
| -        command = self._AddAdditionalUpdateFlags(command, options, revision) | 
| -        self._RunAndGetFileList(command, options, file_list, self._root_dir) | 
| -        return self.Svnversion() | 
| - | 
| -    # If the provided url has a revision number that matches the revision | 
| -    # number of the existing directory, then we don't need to bother updating. | 
| -    if not options.force and str(from_info['Revision']) == revision: | 
| -      if options.verbose or not forced_revision: | 
| -        self.Print('_____ %s%s' % (self.relpath, rev_str), timestamp=False) | 
| -    else: | 
| -      command = ['update', self.checkout_path] | 
| -      command = self._AddAdditionalUpdateFlags(command, options, revision) | 
| -      self._RunAndGetFileList(command, options, file_list, self._root_dir) | 
| - | 
| -    # If --reset and --delete_unversioned_trees are specified, remove any | 
| -    # untracked files and directories. | 
| -    if options.reset and options.delete_unversioned_trees: | 
| -      for status in scm.SVN.CaptureStatus(None, self.checkout_path): | 
| -        full_path = os.path.join(self.checkout_path, status[1]) | 
| -        if (status[0][0] == '?' | 
| -            and os.path.isdir(full_path) | 
| -            and not os.path.islink(full_path)): | 
| -          self.Print('_____ removing unversioned directory %s' % status[1]) | 
| -          gclient_utils.rmtree(full_path) | 
| -    return self.Svnversion() | 
| - | 
| -  def updatesingle(self, options, args, file_list): | 
| -    filename = args.pop() | 
| -    if scm.SVN.AssertVersion("1.5")[0]: | 
| -      if not os.path.exists(os.path.join(self.checkout_path, '.svn')): | 
| -        # Create an empty checkout and then update the one file we want.  Future | 
| -        # operations will only apply to the one file we checked out. | 
| -        command = ["checkout", "--depth", "empty", self.url, self.checkout_path] | 
| -        self._Run(command, options, cwd=self._root_dir) | 
| -        if os.path.exists(os.path.join(self.checkout_path, filename)): | 
| -          os.remove(os.path.join(self.checkout_path, filename)) | 
| -        command = ["update", filename] | 
| -        self._RunAndGetFileList(command, options, file_list) | 
| -      # After the initial checkout, we can use update as if it were any other | 
| -      # dep. | 
| -      self.update(options, args, file_list) | 
| -    else: | 
| -      # If the installed version of SVN doesn't support --depth, fallback to | 
| -      # just exporting the file.  This has the downside that revision | 
| -      # information is not stored next to the file, so we will have to | 
| -      # re-export the file every time we sync. | 
| -      if not os.path.exists(self.checkout_path): | 
| -        gclient_utils.safe_makedirs(self.checkout_path) | 
| -      command = ["export", os.path.join(self.url, filename), | 
| -                 os.path.join(self.checkout_path, filename)] | 
| -      command = self._AddAdditionalUpdateFlags(command, options, | 
| -          options.revision) | 
| -      self._Run(command, options, cwd=self._root_dir) | 
| - | 
| -  def revert(self, options, _args, file_list): | 
| -    """Reverts local modifications. Subversion specific. | 
| - | 
| -    All reverted files will be appended to file_list, even if Subversion | 
| -    doesn't know about them. | 
| -    """ | 
| -    if not os.path.isdir(self.checkout_path): | 
| -      if os.path.exists(self.checkout_path): | 
| -        gclient_utils.rmtree(self.checkout_path) | 
| -      # svn revert won't work if the directory doesn't exist. It needs to | 
| -      # checkout instead. | 
| -      self.Print('_____ %s is missing, synching instead' % self.relpath) | 
| -      # Don't reuse the args. | 
| -      return self.update(options, [], file_list) | 
| - | 
| -    if not os.path.isdir(os.path.join(self.checkout_path, '.svn')): | 
| -      if os.path.isdir(os.path.join(self.checkout_path, '.git')): | 
| -        self.Print('________ found .git directory; skipping %s' % self.relpath) | 
| -        return | 
| -      if os.path.isdir(os.path.join(self.checkout_path, '.hg')): | 
| -        self.Print('________ found .hg directory; skipping %s' % self.relpath) | 
| -        return | 
| -      if not options.force: | 
| -        raise gclient_utils.Error('Invalid checkout path, aborting') | 
| -      self.Print( | 
| -          '\n_____ %s is not a valid svn checkout, synching instead' % | 
| -          self.relpath) | 
| -      gclient_utils.rmtree(self.checkout_path) | 
| -      # Don't reuse the args. | 
| -      return self.update(options, [], file_list) | 
| - | 
| -    def printcb(file_status): | 
| -      if file_list is not None: | 
| -        file_list.append(file_status[1]) | 
| -      if logging.getLogger().isEnabledFor(logging.INFO): | 
| -        logging.info('%s%s' % (file_status[0], file_status[1])) | 
| -      else: | 
| -        self.Print(os.path.join(self.checkout_path, file_status[1])) | 
| -    scm.SVN.Revert(self.checkout_path, callback=printcb) | 
| - | 
| -    # Revert() may delete the directory altogether. | 
| -    if not os.path.isdir(self.checkout_path): | 
| -      # Don't reuse the args. | 
| -      return self.update(options, [], file_list) | 
| - | 
| -    try: | 
| -      # svn revert is so broken we don't even use it. Using | 
| -      # "svn up --revision BASE" achieve the same effect. | 
| -      # file_list will contain duplicates. | 
| -      self._RunAndGetFileList(['update', '--revision', 'BASE'], options, | 
| -          file_list) | 
| -    except OSError, e: | 
| -      # Maybe the directory disappeared meanwhile. Do not throw an exception. | 
| -      logging.error('Failed to update:\n%s' % str(e)) | 
| - | 
| -  def revinfo(self, _options, _args, _file_list): | 
| -    """Display revision""" | 
| -    try: | 
| -      return scm.SVN.CaptureRevision(self.checkout_path) | 
| -    except (gclient_utils.Error, subprocess2.CalledProcessError): | 
| -      return None | 
| - | 
| -  def runhooks(self, options, args, file_list): | 
| -    self.status(options, args, file_list) | 
| - | 
| -  def status(self, options, args, file_list): | 
| -    """Display status information.""" | 
| -    command = ['status'] + args | 
| -    if not os.path.isdir(self.checkout_path): | 
| -      # svn status won't work if the directory doesn't exist. | 
| -      self.Print(('\n________ couldn\'t run \'%s\' in \'%s\':\n' | 
| -             'The directory does not exist.') % | 
| -                (' '.join(command), self.checkout_path)) | 
| -      # There's no file list to retrieve. | 
| -    else: | 
| -      self._RunAndGetFileList(command, options, file_list) | 
| - | 
| -  def GetUsableRev(self, rev, _options): | 
| -    """Verifies the validity of the revision for this repository.""" | 
| -    if not scm.SVN.IsValidRevision(url='%s@%s' % (self.url, rev)): | 
| -      raise NoUsableRevError( | 
| -        ( '%s isn\'t a valid revision. Please check that your safesync_url is\n' | 
| -          'correct.') % rev) | 
| -    return rev | 
| - | 
| -  def FullUrlForRelativeUrl(self, url): | 
| -    # Find the forth '/' and strip from there. A bit hackish. | 
| -    return '/'.join(self.url.split('/')[:4]) + url | 
| - | 
| -  def _Run(self, args, options, **kwargs): | 
| -    """Runs a commands that goes to stdout.""" | 
| -    kwargs.setdefault('cwd', self.checkout_path) | 
| -    gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, | 
| -        always=options.verbose, **kwargs) | 
| - | 
| -  def Svnversion(self): | 
| -    """Runs the lowest checked out revision in the current project.""" | 
| -    info = scm.SVN.CaptureLocalInfo([], os.path.join(self.checkout_path, '.')) | 
| -    return info['Revision'] | 
| - | 
| -  def _RunAndGetFileList(self, args, options, file_list, cwd=None): | 
| -    """Runs a commands that goes to stdout and grabs the file listed.""" | 
| -    cwd = cwd or self.checkout_path | 
| -    scm.SVN.RunAndGetFileList( | 
| -        options.verbose, | 
| -        args + ['--ignore-externals'], | 
| -        cwd=cwd, | 
| -        file_list=file_list) | 
| - | 
| -  @staticmethod | 
| -  def _AddAdditionalUpdateFlags(command, options, revision): | 
| -    """Add additional flags to command depending on what options are set. | 
| -    command should be a list of strings that represents an svn command. | 
| - | 
| -    This method returns a new list to be used as a command.""" | 
| -    new_command = command[:] | 
| -    if revision: | 
| -      new_command.extend(['--revision', str(revision).strip()]) | 
| -    # We don't want interaction when jobs are used. | 
| -    if options.jobs > 1: | 
| -      new_command.append('--non-interactive') | 
| -    # --force was added to 'svn update' in svn 1.5. | 
| -    # --accept was added to 'svn update' in svn 1.6. | 
| -    if not scm.SVN.AssertVersion('1.5')[0]: | 
| -      return new_command | 
| - | 
| -    # It's annoying to have it block in the middle of a sync, just sensible | 
| -    # defaults. | 
| -    if options.force: | 
| -      new_command.append('--force') | 
| -      if command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 
| -        new_command.extend(('--accept', 'theirs-conflict')) | 
| -    elif command[0] != 'checkout' and scm.SVN.AssertVersion('1.6')[0]: | 
| -      new_command.extend(('--accept', 'postpone')) | 
| -    return new_command | 
|  |