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

Unified Diff: testing_support/git/schema.py

Issue 418643004: Copy git tooling into testing_support. (Closed) Base URL: https://chromium.googlesource.com/infra/testing/testing_support@master
Patch Set: fix scripts Created 6 years, 5 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 | « testing_support/git/repo.py ('k') | testing_support/git/unittest_helpers.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: testing_support/git/schema.py
diff --git a/testing_support/git/schema.py b/testing_support/git/schema.py
new file mode 100644
index 0000000000000000000000000000000000000000..b5e171a6eb848fe31fbad69344654b01e5b72e96
--- /dev/null
+++ b/testing_support/git/schema.py
@@ -0,0 +1,124 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import copy
+
+
+from testing_support.git.util import OrderedSet
+
+
+class GitRepoSchema(object):
+ """A declarative git testing repo.
+
+ Pass a schema to __init__ in the form of:
+ A B C D
+ B E D
+
+ This is the repo
+
+ A - B - C - D
+ \ E /
+
+ Whitespace doesn't matter. Each line is a declaration of which commits come
+ before which other commits.
+
+ Every commit gets a tag 'tag_%(commit)s'
+ Every unique terminal commit gets a branch 'branch_%(commit)s'
+ Last commit in First line is the branch 'master'
+ Root commits get a ref 'root_%(commit)s'
+
+ Timestamps are in topo order, earlier commits (as indicated by their presence
+ in the schema) get earlier timestamps. Stamps start at the Unix Epoch, and
+ increment by 1 day each.
+ """
+ COMMIT = collections.namedtuple('COMMIT', 'name parents is_branch is_root')
+
+ def __init__(self, repo_schema='',
+ content_fn=lambda v: {v: {'data': v}}):
+ """Builds a new GitRepoSchema.
+
+ Args:
+ repo_schema (str) - Initial schema for this repo. See class docstring for
+ info on the schema format.
+ content_fn ((commit_name) -> commit_data) - A function which will be
+ lazily called to obtain data for each commit. The results of this
+ function are cached (i.e. it will never be called twice for the same
+ commit_name). See the docstring on the GitRepo class for the format of
+ the data returned by this function.
+ """
+ self.master = None
+ self.par_map = {}
+ self.data_cache = {}
+ self.content_fn = content_fn
+ self.add_commits(repo_schema)
+
+ def walk(self):
+ """(Generator) Walks the repo schema from roots to tips.
+
+ Generates GitRepoSchema.COMMIT objects for each commit.
+
+ Throws an AssertionError if it detects a cycle.
+ """
+ is_root = True
+ par_map = copy.deepcopy(self.par_map)
+ while par_map:
+ empty_keys = set(k for k, v in par_map.iteritems() if not v)
+ assert empty_keys, 'Cycle detected! %s' % par_map
+
+ for k in sorted(empty_keys):
+ yield self.COMMIT(k, self.par_map[k],
+ not any(k in v for v in self.par_map.itervalues()),
+ is_root)
+ del par_map[k]
+ for v in par_map.itervalues():
+ 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.
+
+ Args:
+ schema (str) - See class docstring for info on schema format.
+
+ Throws an AssertionError if it detects a cycle.
+ """
+ for commits in (l.split() for l in schema.splitlines() if l.strip()):
+ parent = None
+ for commit in commits:
+ self.add_partial(commit, parent)
+ parent = commit
+ if parent and not self.master:
+ self.master = parent
+ for _ in self.walk(): # This will throw if there are any cycles.
+ pass
+
+ def data_for(self, commit):
+ """Obtains the data for |commit|.
+
+ See the docstring on the GitRepo class for the format of the returned data.
+
+ Caches the result on this GitRepoSchema instance.
+ """
+ if commit not in self.data_cache:
+ 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
« no previous file with comments | « testing_support/git/repo.py ('k') | testing_support/git/unittest_helpers.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698