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

Side by Side Diff: dashboard/dashboard/pinpoint/models/change/commit.py

Issue 3013013002: [pinpoint] Change refactor. (Closed)
Patch Set: . Created 3 years, 3 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 unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 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
7 from dashboard.common import namespaced_stored_object
8 from dashboard.services import gitiles_service
9
10
11 _REPOSITORIES_KEY = 'repositories'
12
13
14 class NonLinearError(Exception):
15 """Raised when trying to find the midpoint of Changes that are not linear."""
16
17
18 class AdjacentCommitsWarning(Exception):
perezju 2017/09/12 10:59:54 I'm not trilled about "raising" warnings as except
dtu 2017/09/12 22:31:16 Done.
19 """Raised when trying to find the midpoint of Commits that are adjacent."""
20
21
22 class SameCommitWarning(Exception):
23 """Raised when trying to find the midpoint of identical Commits."""
24
25
26 class Commit(collections.namedtuple('Commit', ('repository', 'git_hash'))):
27 """A git repository pinned to a particular commit."""
28
29 def __str__(self):
30 return self.repository + '@' + self.git_hash[:7]
31
32 @property
33 def id_string(self):
34 return self.repository + '@' + self.git_hash
35
36 @property
37 def repository_url(self):
38 """The HTTPS URL of the repository as passed to `git clone`."""
39 repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
40 return repositories[self.repository]['repository_url']
41
42 def Deps(self):
43 """Return the DEPS of this Commit as a frozenset of Commits."""
44 # Download and execute DEPS file.
45 deps_file_contents = gitiles_service.FileContents(
46 self.repository_url, self.git_hash, 'DEPS')
47 deps_data = {'Var': lambda variable: deps_data['vars'][variable]}
48 exec deps_file_contents in deps_data # pylint: disable=exec-used
49
50 # Pull out deps dict, including OS-specific deps.
51 deps_dict = deps_data['deps']
52 for deps_os in deps_data.get('deps_os', {}).itervalues():
53 deps_dict.update(deps_os)
54
55 # Convert deps strings to Commit objects.
56 commits = []
57 for dep_string in deps_dict.itervalues():
58 dep_string_parts = dep_string.split('@')
59 if len(dep_string_parts) < 2:
60 continue # Dep is not pinned to any particular revision.
61 if len(dep_string_parts) > 2:
62 raise NotImplementedError('Unknown DEP format: ' + dep_string)
63
64 repository_url, git_hash = dep_string_parts
65 repository = _Repository(repository_url)
66 if not repository:
67 _AddRepository(repository_url)
perezju 2017/09/12 10:59:54 nit: make _AddRepository to return the repository
dtu 2017/09/12 22:31:16 Done.
68 repository = _Repository(repository_url)
69 commits.append(Commit(repository, git_hash))
70
71 return frozenset(commits)
72
73 def AsDict(self):
74 return {
75 'repository': self.repository,
76 'git_hash': self.git_hash,
77 'url': self.repository_url + '/+/' + self.git_hash,
78 }
79
80 @classmethod
81 def FromDict(cls, data):
82 """Create a Commit from a dict.
83
84 If the repository is a repository URL, it will be translated to its short
85 form name.
86
87 Raises:
88 KeyError: The repository name is not in the local datastore,
89 or the git hash is not valid.
90 """
91 repository = data['repository']
92
93 # Translate repository if it's a URL.
94 repository_from_url = _Repository(repository)
95 if repository_from_url:
96 repository = repository_from_url
perezju 2017/09/12 10:59:54 Wouldn't it be safer to check for leading 'https?:
dtu 2017/09/12 22:31:16 Done.
97
98 commit = cls(repository, data['git_hash'])
99
100 try:
101 gitiles_service.CommitInfo(commit.repository_url, commit.git_hash)
102 except gitiles_service.NotFoundError as e:
103 raise KeyError(str(e))
104
105 return commit
106
107 @classmethod
108 def Midpoint(cls, commit_a, commit_b):
109 """Return a Commit halfway between the two given Commits.
110
111 Uses Gitiles to look up the commit range.
112
113 Args:
114 commit_a: The first Commit in the range.
115 commit_b: The last Commit in the range.
116
117 Returns:
118 A new Commit representing the midpoint.
119 The commit before the midpoint if the range has an even number of commits.
120
121 Raises:
122 AdjacentCommitsWarning: The Commits are adjacent.
123 SameCommitWarning: The Commits are the same.
perezju 2017/09/12 10:59:54 I think these warnings raised as exceptions are aw
dtu 2017/09/12 22:31:16 Done.
124 NonLinearError: The Commits are in different repositories or are in the
125 wrong order.
126 """
127 if commit_a == commit_b:
128 raise SameCommitWarning()
129
130 if commit_a.repository != commit_b.repository:
131 raise NonLinearError('Repositories differ between Commits: %s vs %s' %
132 (commit_a.repository, commit_b.repository))
133
134 commits = gitiles_service.CommitRange(commit_a.repository_url,
135 commit_a.git_hash, commit_b.git_hash)
136 # We don't handle NotFoundErrors because we assume that all Commits either
137 # came from this method or were already validated elsewhere.
138 if len(commits) == 0:
139 raise NonLinearError('The commits are in the wrong order: %s and %s' %
perezju 2017/09/12 10:59:54 nit: Rephrase as "Commit {a} does not come before
dtu 2017/09/12 22:31:16 Done. Do you mean e.g. they're in the same reposit
perezju 2017/09/13 12:52:23 Yep exactly. This may not be common since we tend
140 commit_a, commit_b)
141 if len(commits) == 1:
142 raise AdjacentCommitsWarning()
143 commits = commits[1:] # Remove commit_b from the range.
144
145 return cls(commit_a.repository, commits[len(commits) / 2]['commit'])
146
147
148 def _Repository(repository_url):
149 if repository_url.endswith('.git'):
150 repository_url = repository_url[:-4]
151
152 repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
153 for repo_label, repo_info in repositories.iteritems():
154 if repository_url == repo_info['repository_url']:
155 return repo_label
156
157 return None
158
159
160 def _AddRepository(repository_url):
161 if repository_url.endswith('.git'):
162 repository_url = repository_url[:-4]
163
164 repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
165 repository = repository_url.split('/')[-1]
166
167 if repository in repositories:
168 raise AssertionError("Attempted to add a repository that's already in the "
169 'Datastore: %s: %s' % (repository, repository_url))
170
171 repositories[repository] = {'repository_url': repository_url}
172 namespaced_stored_object.Set(_REPOSITORIES_KEY, repositories)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698