Commit e28e4986 authored by msb@chromium.org's avatar msb@chromium.org

gclient_scm: add support for .git

gclient_tests: add GitWrapper test cases

gclient_scm: make RunGit private and add url check

gclient_scm: add revert, run_hooks, and status

gclient_scm: add git implementations of cleanup, diff, and export

gclient_scm: implment GitSCM::update

gclient_scm: add a checks for unsupported scm and unimplemented method

Review URL: http://codereview.chromium.org/235005

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@27241 0039d316-1c4b-4281-b951-d872f2087c98
parent 81344141
......@@ -12,6 +12,7 @@ details on the presubmit API built into gcl.
UNIT_TESTS = [
'tests.gcl_unittest',
'tests.gclient_test',
'tests.gclient_scm_test',
'tests.presubmit_unittest',
'tests.revert_unittest',
'tests.trychange_unittest',
......
......@@ -34,7 +34,14 @@ 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)
......@@ -58,6 +65,8 @@ class SCMWrapper(object):
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.
......@@ -81,6 +90,99 @@ class SCMWrapper(object):
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)
if checkrc and sp.returncode:
raise gclient_utils.Error('git command %s returned %d' %
(args[0], sp.returncode))
return sp.communicate()[0].strip()
class SVNWrapper(SCMWrapper):
""" Wrapper for SVN """
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment