Chromium Code Reviews

Side by Side 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, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « testing_support/git/repo.py ('k') | testing_support/git/unittest_helpers.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import collections
6 import copy
7
8
9 from testing_support.git.util import OrderedSet
10
11
12 class GitRepoSchema(object):
13 """A declarative git testing repo.
14
15 Pass a schema to __init__ in the form of:
16 A B C D
17 B E D
18
19 This is the repo
20
21 A - B - C - D
22 \ E /
23
24 Whitespace doesn't matter. Each line is a declaration of which commits come
25 before which other commits.
26
27 Every commit gets a tag 'tag_%(commit)s'
28 Every unique terminal commit gets a branch 'branch_%(commit)s'
29 Last commit in First line is the branch 'master'
30 Root commits get a ref 'root_%(commit)s'
31
32 Timestamps are in topo order, earlier commits (as indicated by their presence
33 in the schema) get earlier timestamps. Stamps start at the Unix Epoch, and
34 increment by 1 day each.
35 """
36 COMMIT = collections.namedtuple('COMMIT', 'name parents is_branch is_root')
37
38 def __init__(self, repo_schema='',
39 content_fn=lambda v: {v: {'data': v}}):
40 """Builds a new GitRepoSchema.
41
42 Args:
43 repo_schema (str) - Initial schema for this repo. See class docstring for
44 info on the schema format.
45 content_fn ((commit_name) -> commit_data) - A function which will be
46 lazily called to obtain data for each commit. The results of this
47 function are cached (i.e. it will never be called twice for the same
48 commit_name). See the docstring on the GitRepo class for the format of
49 the data returned by this function.
50 """
51 self.master = None
52 self.par_map = {}
53 self.data_cache = {}
54 self.content_fn = content_fn
55 self.add_commits(repo_schema)
56
57 def walk(self):
58 """(Generator) Walks the repo schema from roots to tips.
59
60 Generates GitRepoSchema.COMMIT objects for each commit.
61
62 Throws an AssertionError if it detects a cycle.
63 """
64 is_root = True
65 par_map = copy.deepcopy(self.par_map)
66 while par_map:
67 empty_keys = set(k for k, v in par_map.iteritems() if not v)
68 assert empty_keys, 'Cycle detected! %s' % par_map
69
70 for k in sorted(empty_keys):
71 yield self.COMMIT(k, self.par_map[k],
72 not any(k in v for v in self.par_map.itervalues()),
73 is_root)
74 del par_map[k]
75 for v in par_map.itervalues():
76 v.difference_update(empty_keys)
77 is_root = False
78
79 def add_partial(self, commit, parent=None):
80 if commit not in self.par_map:
81 self.par_map[commit] = OrderedSet()
82 if parent is not None:
83 self.par_map[commit].add(parent)
84
85 def add_commits(self, schema):
86 """Adds more commits from a schema into the existing Schema.
87
88 Args:
89 schema (str) - See class docstring for info on schema format.
90
91 Throws an AssertionError if it detects a cycle.
92 """
93 for commits in (l.split() for l in schema.splitlines() if l.strip()):
94 parent = None
95 for commit in commits:
96 self.add_partial(commit, parent)
97 parent = commit
98 if parent and not self.master:
99 self.master = parent
100 for _ in self.walk(): # This will throw if there are any cycles.
101 pass
102
103 def data_for(self, commit):
104 """Obtains the data for |commit|.
105
106 See the docstring on the GitRepo class for the format of the returned data.
107
108 Caches the result on this GitRepoSchema instance.
109 """
110 if commit not in self.data_cache:
111 self.data_cache[commit] = self.content_fn(commit)
112 return self.data_cache[commit]
113
114 def simple_graph(self):
115 """Returns a dictionary of {commit_subject: {parent commit_subjects}}
116
117 This allows you to get a very simple connection graph over the whole repo
118 for comparison purposes. Only commit subjects (not ids, not content/data)
119 are considered
120 """
121 ret = {}
122 for commit in self.walk():
123 ret.setdefault(commit.name, set()).update(commit.parents)
124 return ret
OLDNEW
« 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