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

Unified Diff: dashboard/dashboard/pinpoint/models/change/commit.py

Issue 3013013002: [pinpoint] Change refactor. (Closed)
Patch Set: UI 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 side-by-side diff with in-line comments
Download patch
Index: dashboard/dashboard/pinpoint/models/change/commit.py
diff --git a/dashboard/dashboard/pinpoint/models/change/commit.py b/dashboard/dashboard/pinpoint/models/change/commit.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7357279de5c7bc9385e39d07640f0d188d42657
--- /dev/null
+++ b/dashboard/dashboard/pinpoint/models/change/commit.py
@@ -0,0 +1,166 @@
+# Copyright 2016 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
+
+from dashboard.common import namespaced_stored_object
+from dashboard.services import gitiles_service
+
+
+_REPOSITORIES_KEY = 'repositories'
+
+
+class NonLinearError(Exception):
+ """Raised when trying to find the midpoint of Changes that are not linear."""
+
+
+class Commit(collections.namedtuple('Commit', ('repository', 'git_hash'))):
+ """A git repository pinned to a particular commit."""
+
+ def __str__(self):
+ """Returns an informal short string representation of this Commit."""
+ return self.repository + '@' + self.git_hash[:7]
+
+ @property
+ def id_string(self):
+ """Returns a string that is unique to this repository and git hash."""
+ return self.repository + '@' + self.git_hash
+
+ @property
+ def repository_url(self):
+ """The HTTPS URL of the repository as passed to `git clone`."""
+ repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
+ return repositories[self.repository]['repository_url']
+
+ def Deps(self):
+ """Return the DEPS of this Commit as a frozenset of Commits."""
+ # Download and execute DEPS file.
+ deps_file_contents = gitiles_service.FileContents(
+ self.repository_url, self.git_hash, 'DEPS')
+ deps_data = {'Var': lambda variable: deps_data['vars'][variable]}
+ exec deps_file_contents in deps_data # pylint: disable=exec-used
+
+ # Pull out deps dict, including OS-specific deps.
+ deps_dict = deps_data['deps']
+ for deps_os in deps_data.get('deps_os', {}).itervalues():
+ deps_dict.update(deps_os)
+
+ # Convert deps strings to Commit objects.
+ commits = []
+ for dep_string in deps_dict.itervalues():
+ dep_string_parts = dep_string.split('@')
+ if len(dep_string_parts) < 2:
+ continue # Dep is not pinned to any particular revision.
+ if len(dep_string_parts) > 2:
+ raise NotImplementedError('Unknown DEP format: ' + dep_string)
+
+ repository_url, git_hash = dep_string_parts
+ try:
+ repository = _Repository(repository_url)
+ except KeyError:
+ repository = _AddRepository(repository_url)
+ commits.append(Commit(repository, git_hash))
+
+ return frozenset(commits)
+
+ def AsDict(self):
+ return {
+ 'repository': self.repository,
+ 'git_hash': self.git_hash,
+ 'url': self.repository_url + '/+/' + self.git_hash,
+ }
+
+ @classmethod
+ def FromDict(cls, data):
+ """Create a Commit from a dict.
+
+ If the repository is a repository URL, it will be translated to its short
+ form name.
+
+ Raises:
+ KeyError: The repository name is not in the local datastore,
+ or the git hash is not valid.
+ """
+ repository = data['repository']
+
+ # Translate repository if it's a URL.
+ if repository.startswith('https://'):
+ repository = _Repository(repository)
+
+ commit = cls(repository, data['git_hash'])
+
+ try:
+ gitiles_service.CommitInfo(commit.repository_url, commit.git_hash)
+ except gitiles_service.NotFoundError as e:
+ raise KeyError(str(e))
+
+ return commit
+
+ @classmethod
+ def Midpoint(cls, commit_a, commit_b):
+ """Return a Commit halfway between the two given Commits.
+
+ Uses Gitiles to look up the commit range.
+
+ Args:
+ commit_a: The first Commit in the range.
+ commit_b: The last Commit in the range.
+
+ Returns:
+ A new Commit representing the midpoint.
+ The commit before the midpoint if the range has an even number of commits.
+ commit_a if the Commits are the same or adjacent.
+
+ Raises:
+ NonLinearError: The Commits are in different repositories or commit_a does
+ not come before commit_b.
+ """
+ if commit_a == commit_b:
+ return commit_a
+
+ if commit_a.repository != commit_b.repository:
+ raise NonLinearError('Repositories differ between Commits: %s vs %s' %
+ (commit_a.repository, commit_b.repository))
+
+ commits = gitiles_service.CommitRange(commit_a.repository_url,
+ commit_a.git_hash, commit_b.git_hash)
+ # We don't handle NotFoundErrors because we assume that all Commits either
+ # came from this method or were already validated elsewhere.
+ if len(commits) == 0:
+ raise NonLinearError('Commit "%s" does not come before commit "%s".' %
+ commit_a, commit_b)
+ if len(commits) == 1:
+ return commit_a
+ commits.pop(0) # Remove commit_b from the range.
+
+ return cls(commit_a.repository, commits[len(commits) / 2]['commit'])
+
+
+def _Repository(repository_url):
+ if repository_url.endswith('.git'):
+ repository_url = repository_url[:-4]
+
+ repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
+ for repo_label, repo_info in repositories.iteritems():
+ if repository_url == repo_info['repository_url']:
+ return repo_label
+
+ raise KeyError('Unknown repository URL: ' + repository_url)
+
+
+def _AddRepository(repository_url):
+ if repository_url.endswith('.git'):
+ repository_url = repository_url[:-4]
+
+ repositories = namespaced_stored_object.Get(_REPOSITORIES_KEY)
+ repository = repository_url.split('/')[-1]
+
+ if repository in repositories:
+ raise AssertionError("Attempted to add a repository that's already in the "
+ 'Datastore: %s: %s' % (repository, repository_url))
+
+ repositories[repository] = {'repository_url': repository_url}
+ namespaced_stored_object.Set(_REPOSITORIES_KEY, repositories)
+
+ return repository

Powered by Google App Engine
This is Rietveld 408576698