Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1978)

Unified Diff: testing_support/git_test_utils.py

Issue 184253003: Add git-reup and friends (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@freeze_thaw
Patch Set: fix pylint Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « git_upstream_diff.py ('k') | tests/git_common_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: testing_support/git_test_utils.py
diff --git a/testing_support/git_test_utils.py b/testing_support/git_test_utils.py
index 5becad94ba58e0ece7bbcbdaa812fee034d1d0d9..d4c0d8035fbcd41a1b3f7696800c3984688417db 100644
--- a/testing_support/git_test_utils.py
+++ b/testing_support/git_test_utils.py
@@ -10,9 +10,12 @@ import hashlib
import os
import shutil
import subprocess
+import sys
import tempfile
import unittest
+from cStringIO import StringIO
+
def git_hash_data(data, typ='blob'):
"""Calculate the git-style SHA1 for some data.
@@ -159,6 +162,12 @@ class GitRepoSchema(object):
v.difference_update(empty_keys)
is_root = False
+ def add_partial(self, commit, parent=None):
+ if commit not in self.par_map:
+ self.par_map[commit] = OrderedSet()
+ if parent is not None:
+ self.par_map[commit].add(parent)
+
def add_commits(self, schema):
"""Adds more commits from a schema into the existing Schema.
@@ -170,10 +179,7 @@ class GitRepoSchema(object):
for commits in (l.split() for l in schema.splitlines() if l.strip()):
parent = None
for commit in commits:
- if commit not in self.par_map:
- self.par_map[commit] = OrderedSet()
- if parent is not None:
- self.par_map[commit].add(parent)
+ self.add_partial(commit, parent)
parent = commit
if parent and not self.master:
self.master = parent
@@ -195,6 +201,18 @@ class GitRepoSchema(object):
self.data_cache[commit] = self.content_fn(commit)
return self.data_cache[commit]
+ def simple_graph(self):
+ """Returns a dictionary of {commit_subject: {parent commit_subjects}}
+
+ This allows you to get a very simple connection graph over the whole repo
+ for comparison purposes. Only commit subjects (not ids, not content/data)
+ are considered
+ """
+ ret = {}
+ for commit in self.walk():
+ ret.setdefault(commit.name, set()).update(commit.parents)
+ return ret
+
class GitRepo(object):
"""Creates a real git repo for a GitRepoSchema.
@@ -253,12 +271,16 @@ class GitRepo(object):
self.commit_map = {}
self._date = datetime.datetime(1970, 1, 1)
+ self.to_schema_refs = ['--branches']
+
self.git('init')
+ self.git('config', 'user.name', 'testcase')
+ self.git('config', 'user.email', 'testcase@example.com')
for commit in schema.walk():
self._add_schema_commit(commit, schema.data_for(commit.name))
self.last_commit = self[commit.name]
if schema.master:
- self.git('update-ref', 'master', self[schema.master])
+ self.git('update-ref', 'refs/heads/master', self[schema.master])
def __getitem__(self, commit_name):
"""Gets the hash of a commit by its schema name.
@@ -269,8 +291,8 @@ class GitRepo(object):
"""
return self.commit_map[commit_name]
- def _add_schema_commit(self, commit, data):
- data = data or {}
+ def _add_schema_commit(self, commit, commit_data):
+ commit_data = commit_data or {}
if commit.parents:
parents = list(commit.parents)
@@ -281,22 +303,9 @@ class GitRepo(object):
self.git('checkout', '--orphan', 'root_%s' % commit.name)
self.git('rm', '-rf', '.')
- env = {}
- for prefix in ('AUTHOR', 'COMMITTER'):
- for suffix in ('NAME', 'EMAIL', 'DATE'):
- singleton = '%s_%s' % (prefix, suffix)
- key = getattr(self, singleton)
- if key in data:
- val = data[key]
- else:
- if suffix == 'DATE':
- val = self._date
- self._date += datetime.timedelta(days=1)
- else:
- val = getattr(self, 'DEFAULT_%s' % singleton)
- env['GIT_%s' % singleton] = str(val)
+ env = self.get_git_commit_env(commit_data)
- for fname, file_data in data.iteritems():
+ for fname, file_data in commit_data.iteritems():
deleted = False
if 'data' in file_data:
data = file_data.get('data')
@@ -324,6 +333,25 @@ class GitRepo(object):
if commit.is_branch:
self.git('branch', '-f', 'branch_%s' % commit.name, self[commit.name])
+ def get_git_commit_env(self, commit_data=None):
+ commit_data = commit_data or {}
+ env = {}
+ for prefix in ('AUTHOR', 'COMMITTER'):
+ for suffix in ('NAME', 'EMAIL', 'DATE'):
+ singleton = '%s_%s' % (prefix, suffix)
+ key = getattr(self, singleton)
+ if key in commit_data:
+ val = commit_data[key]
+ else:
+ if suffix == 'DATE':
+ val = self._date
+ self._date += datetime.timedelta(days=1)
+ else:
+ val = getattr(self, 'DEFAULT_%s' % singleton)
+ env['GIT_%s' % singleton] = str(val)
+ return env
+
+
def git(self, *args, **kwargs):
"""Runs a git command specified by |args| in this repo."""
assert self.repo_path is not None
@@ -335,6 +363,9 @@ class GitRepo(object):
except subprocess.CalledProcessError as e:
return self.COMMAND_OUTPUT(e.returncode, e.output)
+ def git_commit(self, message):
+ return self.git('commit', '-am', message, env=self.get_git_commit_env())
+
def nuke(self):
"""Obliterates the git repo on disk.
@@ -354,11 +385,59 @@ class GitRepo(object):
finally:
os.chdir(curdir)
+ def capture_stdio(self, fn, *args, **kwargs):
+ """Run a python function with the given args and kwargs with the cwd set to
+ the git repo.
+
+ Returns the (stdout, stderr) of whatever ran, instead of the what |fn|
+ returned.
+ """
+ stdout = sys.stdout
+ stderr = sys.stderr
+ try:
+ sys.stdout = StringIO()
+ sys.stderr = StringIO()
+ try:
+ self.run(fn, *args, **kwargs)
+ except SystemExit:
+ pass
+ return sys.stdout.getvalue(), sys.stderr.getvalue()
+ finally:
+ sys.stdout = stdout
+ sys.stderr = stderr
+
+ def open(self, path, mode='rb'):
+ return open(os.path.join(self.repo_path, path), mode)
+
+ def to_schema(self):
+ lines = self.git('rev-list', '--parents', '--reverse', '--topo-order',
+ '--format=%s', *self.to_schema_refs).stdout.splitlines()
+ hash_to_msg = {}
+ ret = GitRepoSchema()
+ current = None
+ parents = []
+ for line in lines:
+ if line.startswith('commit'):
+ assert current is None
+ tokens = line.split()
+ current, parents = tokens[1], tokens[2:]
+ assert all(p in hash_to_msg for p in parents)
+ else:
+ assert current is not None
+ hash_to_msg[current] = line
+ ret.add_partial(line)
+ for parent in parents:
+ ret.add_partial(line, hash_to_msg[parent])
+ current = None
+ parents = []
+ assert current is None
+ return ret
+
class GitRepoSchemaTestBase(unittest.TestCase):
"""A TestCase with a built-in GitRepoSchema.
- Expects a class variable REPO to be a GitRepoSchema string in the form
+ Expects a class variable REPO_SCHEMA to be a GitRepoSchema string in the form
described by that class.
You may also set class variables in the form COMMIT_%(commit_name)s, which
@@ -367,7 +446,7 @@ class GitRepoSchemaTestBase(unittest.TestCase):
You probably will end up using either GitRepoReadOnlyTestBase or
GitRepoReadWriteTestBase for real tests.
"""
- REPO = None
+ REPO_SCHEMA = None
@classmethod
def getRepoContent(cls, commit):
@@ -376,8 +455,8 @@ class GitRepoSchemaTestBase(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(GitRepoSchemaTestBase, cls).setUpClass()
- assert cls.REPO is not None
- cls.r_schema = GitRepoSchema(cls.REPO, cls.getRepoContent)
+ assert cls.REPO_SCHEMA is not None
+ cls.r_schema = GitRepoSchema(cls.REPO_SCHEMA, cls.getRepoContent)
class GitRepoReadOnlyTestBase(GitRepoSchemaTestBase):
@@ -387,12 +466,12 @@ class GitRepoReadOnlyTestBase(GitRepoSchemaTestBase):
This GitRepo will appear as self.repo, and will be deleted and recreated once
for the duration of all the tests in the subclass.
"""
- REPO = None
+ REPO_SCHEMA = None
@classmethod
def setUpClass(cls):
super(GitRepoReadOnlyTestBase, cls).setUpClass()
- assert cls.REPO is not None
+ assert cls.REPO_SCHEMA is not None
cls.repo = cls.r_schema.reify()
def setUp(self):
@@ -411,7 +490,7 @@ class GitRepoReadWriteTestBase(GitRepoSchemaTestBase):
This GitRepo will appear as self.repo, and will be deleted and recreated for
each test function in the subclass.
"""
- REPO = None
+ REPO_SCHEMA = None
def setUp(self):
super(GitRepoReadWriteTestBase, self).setUp()
@@ -420,3 +499,7 @@ class GitRepoReadWriteTestBase(GitRepoSchemaTestBase):
def tearDown(self):
self.repo.nuke()
super(GitRepoReadWriteTestBase, self).tearDown()
+
+ def assertSchema(self, schema_string):
+ self.assertEqual(GitRepoSchema(schema_string).simple_graph(),
+ self.repo.to_schema().simple_graph())
« no previous file with comments | « git_upstream_diff.py ('k') | tests/git_common_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698