<commit_before># Copyright 2009 Google Inc.  All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import logging
import os
import re
import subprocess
import sys
import xml.dom.minidom

import gclient_utils

SVN_COMMAND = "svn"
GIT_COMMAND = "git"


### SCM abstraction layer


# Factory Method for SCM wrapper creation

def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'):
  # TODO(maruel): Deduce the SCM from the url.
  scm_map = {
    'svn' : SVNWrapper,
    'git' : GitWrapper,
  }

  if url and (url.startswith('git:') or
              url.startswith('ssh:') or
              url.endswith('.git')):
    scm_name = 'git'

  if not scm_name in scm_map:
    raise gclient_utils.Error('Unsupported scm %s' % scm_name)
  return scm_map[scm_name](url, root_dir, relpath, scm_name)


# SCMWrapper base class

class SCMWrapper(object):
  """Add necessary glue between all the supported SCM.

  This is the abstraction layer to bind to different SCM. Since currently only
  subversion is supported, a lot of subersionism remains. This can be sorted out
  once another SCM is supported."""
  def __init__(self, url=None, root_dir=None, relpath=None,
               scm_name='svn'):
    self.scm_name = scm_name
    self.url = url
    self._root_dir = root_dir
    if self._root_dir:
      self._root_dir = self._root_dir.replace('/', os.sep)
    self.relpath = relpath
    if self.relpath:
      self.relpath = self.relpath.replace('/', os.sep)
    if self.relpath and self._root_dir:
      self.checkout_path = os.path.join(self._root_dir, self.relpath)

  def FullUrlForRelativeUrl(self, url):
    # Find the forth '/' and strip from there. A bit hackish.
    return '/'.join(self.url.split('/')[:4]) + url

  def RunCommand(self, command, options, args, file_list=None):
    # file_list will have all files that are modified appended to it.
    if file_list is None:
      file_list = []

    commands = ['cleanup', 'export', 'update', 'revert',
                'status', 'diff', 'pack', 'runhooks']

    if not command in commands:
      raise gclient_utils.Error('Unknown command %s' % command)

    if not command in dir(self):
      raise gclient_utils.Error('Command %s not implemnted in %s wrapper' % (
          command, self.scm_name))

    return getattr(self, command)(options, args, file_list)


class GitWrapper(SCMWrapper):
  """Wrapper for Git"""

  def cleanup(self, options, args, file_list):
    """Cleanup working copy."""
    self._RunGit(['prune'])
    self._RunGit(['fsck'])
    self._RunGit(['gc'])

  def diff(self, options, args, file_list):
    # NOTE: This function does not currently modify file_list.
    merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
    print self._RunGit(['diff', merge_base])

  def export(self, options, args, file_list):
    assert len(args) == 1
    export_path = os.path.abspath(os.path.join(args[0], self.relpath))
    if not os.path.exists(export_path):
      os.makedirs(export_path)
    self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path])

  def update(self, options, args, file_list):
    """Runs git 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.
    """

    if args:
      raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))

    components = self.url.split("@")
    url = components[0]
    revision = None
    if options.revision:
      revision = options.revision
    elif len(components) == 2:
      revision = components[1]

    if not os.path.exists(self.checkout_path):
      self._RunGit(['clone', '-q', url, self.checkout_path], cwd=self._root_dir)
      if revision:
        self._RunGit(['reset', '--hard', revision])
      files =  self._RunGit(['ls-files']).split()
      file_list.extend([os.path.join(self.checkout_path, f) for f in files])
      return

    self._RunGit(['remote', 'update'])
    new_base = 'origin'
    if revision:
      new_base = revision
    files = self._RunGit(['diff', new_base, '--name-only']).split()
    file_list.extend([os.path.join(self.checkout_path, f) for f in files])
    self._RunGit(['rebase', new_base])

  def revert(self, options, args, file_list):
    """Reverts local modifications.

    All reverted files will be appended to file_list.
    """
    merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
    files = self._RunGit(['diff', merge_base, '--name-only']).split()
    print self._RunGit(['reset', '--hard', merge_base])
    file_list.extend([os.path.join(self.checkout_path, f) for f in files])

  def runhooks(self, options, args, file_list):
    self.status(options, args, file_list)

  def status(self, options, args, file_list):
    """Display status information."""
    if not os.path.isdir(self.checkout_path):
      print('\n________ couldn\'t run status in %s:\nThe directory '
            'does not exist.' % checkout_path)
    else:
      merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
      print self._RunGit(['diff', '--name-status', merge_base])
      files = self._RunGit(['diff', '--name-only', merge_base]).split()
      file_list.extend([os.path.join(self.checkout_path, f) for f in files])

  def _RunGit(self, args, cwd=None, checkrc=True):
    if cwd == None:
      cwd = self.checkout_path
    cmd = ['git']
    cmd.extend(args)
    sp = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE)<commit_msg>Add directory check to Git revert.<commit_after># Copyright 2009 Google Inc.  All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import logging
import os
import re
import subprocess
import sys
import xml.dom.minidom

import gclient_utils

SVN_COMMAND = "svn"
GIT_COMMAND = "git"


### SCM abstraction layer


# Factory Method for SCM wrapper creation

def CreateSCM(url=None, root_dir=None, relpath=None, scm_name='svn'):
  # TODO(maruel): Deduce the SCM from the url.
  scm_map = {
    'svn' : SVNWrapper,
    'git' : GitWrapper,
  }

  if url and (url.startswith('git:') or
              url.startswith('ssh:') or
              url.endswith('.git')):
    scm_name = 'git'

  if not scm_name in scm_map:
    raise gclient_utils.Error('Unsupported scm %s' % scm_name)
  return scm_map[scm_name](url, root_dir, relpath, scm_name)


# SCMWrapper base class

class SCMWrapper(object):
  """Add necessary glue between all the supported SCM.

  This is the abstraction layer to bind to different SCM. Since currently only
  subversion is supported, a lot of subersionism remains. This can be sorted out
  once another SCM is supported."""
  def __init__(self, url=None, root_dir=None, relpath=None,
               scm_name='svn'):
    self.scm_name = scm_name
    self.url = url
    self._root_dir = root_dir
    if self._root_dir:
      self._root_dir = self._root_dir.replace('/', os.sep)
    self.relpath = relpath
    if self.relpath:
      self.relpath = self.relpath.replace('/', os.sep)
    if self.relpath and self._root_dir:
      self.checkout_path = os.path.join(self._root_dir, self.relpath)

  def FullUrlForRelativeUrl(self, url):
    # Find the forth '/' and strip from there. A bit hackish.
    return '/'.join(self.url.split('/')[:4]) + url

  def RunCommand(self, command, options, args, file_list=None):
    # file_list will have all files that are modified appended to it.
    if file_list is None:
      file_list = []

    commands = ['cleanup', 'export', 'update', 'revert',
                'status', 'diff', 'pack', 'runhooks']

    if not command in commands:
      raise gclient_utils.Error('Unknown command %s' % command)

    if not command in dir(self):
      raise gclient_utils.Error('Command %s not implemnted in %s wrapper' % (
          command, self.scm_name))

    return getattr(self, command)(options, args, file_list)


class GitWrapper(SCMWrapper):
  """Wrapper for Git"""

  def cleanup(self, options, args, file_list):
    """Cleanup working copy."""
    self._RunGit(['prune'])
    self._RunGit(['fsck'])
    self._RunGit(['gc'])

  def diff(self, options, args, file_list):
    # NOTE: This function does not currently modify file_list.
    merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
    print self._RunGit(['diff', merge_base])

  def export(self, options, args, file_list):
    assert len(args) == 1
    export_path = os.path.abspath(os.path.join(args[0], self.relpath))
    if not os.path.exists(export_path):
      os.makedirs(export_path)
    self._RunGit(['checkout-index', '-a', '--prefix=%s/' % export_path])

  def update(self, options, args, file_list):
    """Runs git 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.
    """

    if args:
      raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))

    components = self.url.split("@")
    url = components[0]
    revision = None
    if options.revision:
      revision = options.revision
    elif len(components) == 2:
      revision = components[1]

    if not os.path.exists(self.checkout_path):
      self._RunGit(['clone', '-q', url, self.checkout_path], cwd=self._root_dir)
      if revision:
        self._RunGit(['reset', '--hard', revision])
      files =  self._RunGit(['ls-files']).split()
      file_list.extend([os.path.join(self.checkout_path, f) for f in files])
      return

    self._RunGit(['remote', 'update'])
    new_base = 'origin'
    if revision:
      new_base = revision
    files = self._RunGit(['diff', new_base, '--name-only']).split()
    file_list.extend([os.path.join(self.checkout_path, f) for f in files])
    self._RunGit(['rebase', new_base])

  def revert(self, options, args, file_list):
    """Reverts local modifications.

    All reverted files will be appended to file_list.
    """
    path = os.path.join(self._root_dir, self.relpath)
    if not os.path.isdir(path):
      # revert won't work if the directory doesn't exist. It needs to
      # checkout instead.
      print("\n_____ %s is missing, synching instead" % self.relpath)
      # Don't reuse the args.
      return self.update(options, [], file_list)
    merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
    files = self._RunGit(['diff', merge_base, '--name-only']).split()
    print self._RunGit(['reset', '--hard', merge_base])
    file_list.extend([os.path.join(self.checkout_path, f) for f in files])

  def runhooks(self, options, args, file_list):
    self.status(options, args, file_list)

  def status(self, options, args, file_list):
    """Display status information."""
    if not os.path.isdir(self.checkout_path):
      print('\n________ couldn\'t run status in %s:\nThe directory '
            'does not exist.' % checkout_path)
    else:
      merge_base = self._RunGit(['merge-base', 'HEAD', 'origin'])
      print self._RunGit(['diff', '--name-status', merge_base])
      files = self._RunGit(['diff', '--name-only', merge_base]).split()
      file_list.extend([os.path.join(self.checkout_path, f) for f in files])

  def _RunGit(self, args, cwd=None, checkrc=True):
    if cwd == None:
      cwd = self.checkout_path
    cmd = ['git']
    cmd.extend(args)
    sp = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE)
{'fraction_non_alphanumeric': 0.132126035406854, 'fraction_numerical': 0.0022738346597368847, 'mean_word_length': 3.388809693513899, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '567019', 'n_tokens_mistral': 4059, 'n_tokens_neox': 3928, 'n_words': 1153}