Remove SVN support from checkout.py

R=hinoka@chromium.org
BUG=475320

Review-Url: https://codereview.chromium.org/2398603003
diff --git a/checkout.py b/checkout.py
index 8f7c4be..7c49761 100644
--- a/checkout.py
+++ b/checkout.py
@@ -4,7 +4,7 @@
 # found in the LICENSE file.
 """Manages a project checkout.
 
-Includes support for svn, git-svn and git.
+Includes support only for git.
 """
 
 import fnmatch
@@ -161,403 +161,6 @@
     raise NotImplementedError()
 
 
-class RawCheckout(CheckoutBase):
-  """Used to apply a patch locally without any intent to commit it.
-
-  To be used by the try server.
-  """
-  def prepare(self, revision):
-    """Stubbed out."""
-    pass
-
-  def apply_patch(self, patches, post_processors=None, verbose=False):
-    """Ignores svn properties."""
-    post_processors = post_processors or self.post_processors or []
-    for p in patches:
-      stdout = []
-      try:
-        filepath = os.path.join(self.project_path, p.filename)
-        if p.is_delete:
-          os.remove(filepath)
-          assert(not os.path.exists(filepath))
-          stdout.append('Deleted.')
-        else:
-          dirname = os.path.dirname(p.filename)
-          full_dir = os.path.join(self.project_path, dirname)
-          if dirname and not os.path.isdir(full_dir):
-            os.makedirs(full_dir)
-            stdout.append('Created missing directory %s.' % dirname)
-
-          if p.is_binary:
-            content = p.get()
-            with open(filepath, 'wb') as f:
-              f.write(content)
-            stdout.append('Added binary file %d bytes.' % len(content))
-          else:
-            if p.source_filename:
-              if not p.is_new:
-                raise PatchApplicationFailed(
-                    p,
-                    'File has a source filename specified but is not new')
-              # Copy the file first.
-              if os.path.isfile(filepath):
-                raise PatchApplicationFailed(
-                    p, 'File exist but was about to be overwriten')
-              shutil.copy2(
-                  os.path.join(self.project_path, p.source_filename), filepath)
-              stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
-            if p.diff_hunks:
-              cmd = ['patch', '-u', '--binary', '-p%s' % p.patchlevel]
-              if verbose:
-                cmd.append('--verbose')
-              env = os.environ.copy()
-              env['TMPDIR'] = tempfile.mkdtemp(prefix='crpatch')
-              try:
-                stdout.append(
-                    subprocess2.check_output(
-                        cmd,
-                        stdin=p.get(False),
-                        stderr=subprocess2.STDOUT,
-                        cwd=self.project_path,
-                        timeout=GLOBAL_TIMEOUT,
-                        env=env))
-              finally:
-                shutil.rmtree(env['TMPDIR'])
-            elif p.is_new and not os.path.exists(filepath):
-              # There is only a header. Just create the file.
-              open(filepath, 'w').close()
-              stdout.append('Created an empty file.')
-        for post in post_processors:
-          post(self, p)
-        if verbose:
-          print p.filename
-          print align_stdout(stdout)
-      except OSError, e:
-        raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
-      except subprocess.CalledProcessError, e:
-        raise PatchApplicationFailed(
-            p,
-            'While running %s;\n%s%s' % (
-              ' '.join(e.cmd),
-              align_stdout(stdout),
-              align_stdout([getattr(e, 'stdout', '')])))
-
-  def commit(self, commit_message, user):
-    """Stubbed out."""
-    raise NotImplementedError('RawCheckout can\'t commit')
-
-  def revisions(self, _rev1, _rev2):
-    return None
-
-
-class SvnConfig(object):
-  """Parses a svn configuration file."""
-  def __init__(self, svn_config_dir=None):
-    super(SvnConfig, self).__init__()
-    self.svn_config_dir = svn_config_dir
-    self.default = not bool(self.svn_config_dir)
-    if not self.svn_config_dir:
-      if sys.platform == 'win32':
-        self.svn_config_dir = os.path.join(os.environ['APPDATA'], 'Subversion')
-      else:
-        self.svn_config_dir = os.path.expanduser(
-            os.path.join('~', '.subversion'))
-    svn_config_file = os.path.join(self.svn_config_dir, 'config')
-    parser = configparser.SafeConfigParser()
-    if os.path.isfile(svn_config_file):
-      parser.read(svn_config_file)
-    else:
-      parser.add_section('auto-props')
-    self.auto_props = dict(parser.items('auto-props'))
-
-
-class SvnMixIn(object):
-  """MixIn class to add svn commands common to both svn and git-svn clients."""
-  # These members need to be set by the subclass.
-  commit_user = None
-  commit_pwd = None
-  svn_url = None
-  project_path = None
-  # Override at class level when necessary. If used, --non-interactive is
-  # implied.
-  svn_config = SvnConfig()
-  # Set to True when non-interactivity is necessary but a custom subversion
-  # configuration directory is not necessary.
-  non_interactive = False
-
-  def _add_svn_flags(self, args, non_interactive, credentials=True):
-    args = ['svn'] + args
-    if not self.svn_config.default:
-      args.extend(['--config-dir', self.svn_config.svn_config_dir])
-    if not self.svn_config.default or self.non_interactive or non_interactive:
-      args.append('--non-interactive')
-    if credentials:
-      if self.commit_user:
-        args.extend(['--username', self.commit_user])
-      if self.commit_pwd:
-        args.extend(['--password', self.commit_pwd])
-    return args
-
-  def _check_call_svn(self, args, **kwargs):
-    """Runs svn and throws an exception if the command failed."""
-    kwargs.setdefault('cwd', self.project_path)
-    kwargs.setdefault('stdout', self.VOID)
-    kwargs.setdefault('timeout', GLOBAL_TIMEOUT)
-    return subprocess2.check_call_out(
-        self._add_svn_flags(args, False), **kwargs)
-
-  def _check_output_svn(self, args, credentials=True, **kwargs):
-    """Runs svn and throws an exception if the command failed.
-
-     Returns the output.
-    """
-    kwargs.setdefault('cwd', self.project_path)
-    return subprocess2.check_output(
-        self._add_svn_flags(args, True, credentials),
-        stderr=subprocess2.STDOUT,
-        timeout=GLOBAL_TIMEOUT,
-        **kwargs)
-
-  @staticmethod
-  def _parse_svn_info(output, key):
-    """Returns value for key from svn info output.
-
-    Case insensitive.
-    """
-    values = {}
-    key = key.lower()
-    for line in output.splitlines(False):
-      if not line:
-        continue
-      k, v = line.split(':', 1)
-      k = k.strip().lower()
-      v = v.strip()
-      assert not k in values
-      values[k] = v
-    return values.get(key, None)
-
-
-class SvnCheckout(CheckoutBase, SvnMixIn):
-  """Manages a subversion checkout."""
-  def __init__(self, root_dir, project_name, commit_user, commit_pwd, svn_url,
-      post_processors=None):
-    CheckoutBase.__init__(self, root_dir, project_name, post_processors)
-    SvnMixIn.__init__(self)
-    self.commit_user = commit_user
-    self.commit_pwd = commit_pwd
-    self.svn_url = svn_url
-    assert bool(self.commit_user) >= bool(self.commit_pwd)
-
-  def prepare(self, revision):
-    # Will checkout if the directory is not present.
-    assert self.svn_url
-    if not os.path.isdir(self.project_path):
-      logging.info('Checking out %s in %s' %
-          (self.project_name, self.project_path))
-    return self._revert(revision)
-
-  def apply_patch(self, patches, post_processors=None, verbose=False):
-    post_processors = post_processors or self.post_processors or []
-    for p in patches:
-      stdout = []
-      try:
-        filepath = os.path.join(self.project_path, p.filename)
-        # It is important to use credentials=False otherwise credentials could
-        # leak in the error message. Credentials are not necessary here for the
-        # following commands anyway.
-        if p.is_delete:
-          stdout.append(self._check_output_svn(
-              ['delete', p.filename, '--force'], credentials=False))
-          assert(not os.path.exists(filepath))
-          stdout.append('Deleted.')
-        else:
-          # svn add while creating directories otherwise svn add on the
-          # contained files will silently fail.
-          # First, find the root directory that exists.
-          dirname = os.path.dirname(p.filename)
-          dirs_to_create = []
-          while (dirname and
-              not os.path.isdir(os.path.join(self.project_path, dirname))):
-            dirs_to_create.append(dirname)
-            dirname = os.path.dirname(dirname)
-          for dir_to_create in reversed(dirs_to_create):
-            os.mkdir(os.path.join(self.project_path, dir_to_create))
-            stdout.append(
-                self._check_output_svn(
-                  ['add', dir_to_create, '--force'], credentials=False))
-            stdout.append('Created missing directory %s.' % dir_to_create)
-
-          if p.is_binary:
-            content = p.get()
-            with open(filepath, 'wb') as f:
-              f.write(content)
-            stdout.append('Added binary file %d bytes.' % len(content))
-          else:
-            if p.source_filename:
-              if not p.is_new:
-                raise PatchApplicationFailed(
-                    p,
-                    'File has a source filename specified but is not new')
-              # Copy the file first.
-              if os.path.isfile(filepath):
-                raise PatchApplicationFailed(
-                    p, 'File exist but was about to be overwriten')
-              stdout.append(
-                  self._check_output_svn(
-                    ['copy', p.source_filename, p.filename]))
-              stdout.append('Copied %s -> %s' % (p.source_filename, p.filename))
-            if p.diff_hunks:
-              cmd = [
-                'patch',
-                '-p%s' % p.patchlevel,
-                '--forward',
-                '--force',
-                '--no-backup-if-mismatch',
-              ]
-              env = os.environ.copy()
-              env['TMPDIR'] = tempfile.mkdtemp(prefix='crpatch')
-              try:
-                stdout.append(
-                    subprocess2.check_output(
-                      cmd,
-                      stdin=p.get(False),
-                      cwd=self.project_path,
-                      timeout=GLOBAL_TIMEOUT,
-                      env=env))
-              finally:
-                shutil.rmtree(env['TMPDIR'])
-
-            elif p.is_new and not os.path.exists(filepath):
-              # There is only a header. Just create the file if it doesn't
-              # exist.
-              open(filepath, 'w').close()
-              stdout.append('Created an empty file.')
-          if p.is_new and not p.source_filename:
-            # Do not run it if p.source_filename is defined, since svn copy was
-            # using above.
-            stdout.append(
-                self._check_output_svn(
-                  ['add', p.filename, '--force'], credentials=False))
-          for name, value in p.svn_properties:
-            if value is None:
-              stdout.append(
-                  self._check_output_svn(
-                    ['propdel', '--quiet', name, p.filename],
-                    credentials=False))
-              stdout.append('Property %s deleted.' % name)
-            else:
-              stdout.append(
-                  self._check_output_svn(
-                    ['propset', name, value, p.filename], credentials=False))
-              stdout.append('Property %s=%s' % (name, value))
-          for prop, values in self.svn_config.auto_props.iteritems():
-            if fnmatch.fnmatch(p.filename, prop):
-              for value in values.split(';'):
-                if '=' not in value:
-                  params = [value, '.']
-                else:
-                  params = value.split('=', 1)
-                if params[1] == '*':
-                  # Works around crbug.com/150960 on Windows.
-                  params[1] = '.'
-                stdout.append(
-                    self._check_output_svn(
-                      ['propset'] + params + [p.filename], credentials=False))
-                stdout.append('Property (auto) %s' % '='.join(params))
-        for post in post_processors:
-          post(self, p)
-        if verbose:
-          print p.filename
-          print align_stdout(stdout)
-      except OSError, e:
-        raise PatchApplicationFailed(p, '%s%s' % (align_stdout(stdout), e))
-      except subprocess.CalledProcessError, e:
-        raise PatchApplicationFailed(
-            p,
-            'While running %s;\n%s%s' % (
-              ' '.join(e.cmd),
-              align_stdout(stdout),
-              align_stdout([getattr(e, 'stdout', '')])))
-
-  def commit(self, commit_message, user):
-    logging.info('Committing patch for %s' % user)
-    assert self.commit_user
-    assert isinstance(commit_message, unicode)
-    handle, commit_filename = tempfile.mkstemp(text=True)
-    try:
-      # Shouldn't assume default encoding is UTF-8. But really, if you are using
-      # anything else, you are living in another world.
-      os.write(handle, commit_message.encode('utf-8'))
-      os.close(handle)
-      # When committing, svn won't update the Revision metadata of the checkout,
-      # so if svn commit returns "Committed revision 3.", svn info will still
-      # return "Revision: 2". Since running svn update right after svn commit
-      # creates a race condition with other committers, this code _must_ parse
-      # the output of svn commit and use a regexp to grab the revision number.
-      # Note that "Committed revision N." is localized but subprocess2 forces
-      # LANGUAGE=en.
-      args = ['commit', '--file', commit_filename]
-      # realauthor is parsed by a server-side hook.
-      if user and user != self.commit_user:
-        args.extend(['--with-revprop', 'realauthor=%s' % user])
-      out = self._check_output_svn(args)
-    finally:
-      os.remove(commit_filename)
-    lines = filter(None, out.splitlines())
-    match = re.match(r'^Committed revision (\d+).$', lines[-1])
-    if not match:
-      raise PatchApplicationFailed(
-          None,
-          'Couldn\'t make sense out of svn commit message:\n' + out)
-    return int(match.group(1))
-
-  def _revert(self, revision):
-    """Reverts local modifications or checks out if the directory is not
-    present. Use depot_tools's functionality to do this.
-    """
-    flags = ['--ignore-externals']
-    if revision:
-      flags.extend(['--revision', str(revision)])
-    if os.path.isdir(self.project_path):
-      # This may remove any part (or all) of the checkout.
-      scm.SVN.Revert(self.project_path, no_ignore=True)
-
-    if os.path.isdir(self.project_path):
-      # Revive files that were deleted in scm.SVN.Revert().
-      self._check_call_svn(['update', '--force'] + flags,
-                           timeout=FETCH_TIMEOUT)
-    else:
-      logging.info(
-          'Directory %s is not present, checking it out.' % self.project_path)
-      self._check_call_svn(
-          ['checkout', self.svn_url, self.project_path] + flags, cwd=None,
-          timeout=FETCH_TIMEOUT)
-    return self._get_revision()
-
-  def _get_revision(self):
-    out = self._check_output_svn(['info', '.'])
-    revision = int(self._parse_svn_info(out, 'revision'))
-    if revision != self._last_seen_revision:
-      logging.info('Updated to revision %d' % revision)
-      self._last_seen_revision = revision
-    return revision
-
-  def revisions(self, rev1, rev2):
-    """Returns the number of actual commits, not just the difference between
-    numbers.
-    """
-    rev2 = rev2 or 'HEAD'
-    # Revision range is inclusive and ordering doesn't matter, they'll appear in
-    # the order specified.
-    try:
-      out = self._check_output_svn(
-          ['log', '-q', self.svn_url, '-r', '%s:%s' % (rev1, rev2)])
-    except subprocess.CalledProcessError:
-      return None
-    # Ignore the '----' lines.
-    return len([l for l in out.splitlines() if l.startswith('r')]) - 1
-
-
 class GitCheckout(CheckoutBase):
   """Manages a git checkout."""
   def __init__(self, root_dir, project_name, remote_branch, git_url,
@@ -639,8 +242,6 @@
     """Applies a patch on 'working_branch' and switches to it.
 
     The changes remain staged on the current branch.
-
-    Ignores svn properties and raise an exception on unexpected ones.
     """
     post_processors = post_processors or self.post_processors or []
     # It this throws, the checkout is corrupted. Maybe worth deleting it and
@@ -686,19 +287,6 @@
             if verbose:
               cmd.append('--verbose')
             stdout.append(self._check_output_git(cmd, stdin=p.get(True)))
-          for key, value in p.svn_properties:
-            # Ignore some known auto-props flags through .subversion/config,
-            # bails out on the other ones.
-            # TODO(maruel): Read ~/.subversion/config and detect the rules that
-            # applies here to figure out if the property will be correctly
-            # handled.
-            stdout.append('Property %s=%s' % (key, value))
-            if not key in (
-                'svn:eol-style', 'svn:executable', 'svn:mime-type'):
-              raise patch.UnsupportedPatchFormat(
-                  p.filename,
-                  'Cannot apply svn property %s to file %s.' % (
-                        key, p.filename))
         for post in post_processors:
           post(self, p)
         if verbose: