Put screenshot.py back to work
[chromium-blink-merge.git] / tools / auto_bisect / source_control.py
blob9249f17cbe7495b3aa15a0130202f9e7720b88bd
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.
5 """This module contains functions for performing source control operations."""
7 import bisect_utils
10 def IsInGitRepository():
11 output, _ = bisect_utils.RunGit(['rev-parse', '--is-inside-work-tree'])
12 return output.strip() == 'true'
15 def GetRevisionList(end_revision_hash, start_revision_hash, cwd=None):
16 """Retrieves a list of git commit hashes in a range.
18 Args:
19 end_revision_hash: The SHA1 for the end of the range, inclusive.
20 start_revision_hash: The SHA1 for the beginning of the range, inclusive.
22 Returns:
23 A list of the git commit hashes in the range, in reverse time order --
24 that is, starting with |end_revision_hash|.
25 """
26 revision_range = '%s..%s' % (start_revision_hash, end_revision_hash)
27 cmd = ['log', '--format=%H', '-10000', '--first-parent', revision_range]
28 log_output = bisect_utils.CheckRunGit(cmd, cwd=cwd)
30 revision_hash_list = log_output.split()
31 revision_hash_list.append(start_revision_hash)
33 return revision_hash_list
36 def SyncToRevision(revision, sync_client=None):
37 if not sync_client:
38 _, return_code = bisect_utils.RunGit(['checkout', revision])
39 elif sync_client == 'gclient':
40 return_code = bisect_utils.RunGClientAndSync(revision)
41 else:
42 raise NotImplementedError('Unsupported sync_client: "%s"' % sync_client)
44 return not return_code
47 def ResolveToRevision(revision_to_check, depot, depot_deps_dict,
48 search, cwd=None):
49 """Tries to resolve an SVN revision or commit position to a git SHA1.
51 Args:
52 revision_to_check: The user supplied revision string that may need to be
53 resolved to a git commit hash. This may be an SVN revision, git commit
54 position, or a git commit hash.
55 depot: The depot (dependency repository) that |revision_to_check| is from.
56 depot_deps_dict: A dictionary with information about different depots.
57 search: How many revisions forward or backward to search. If the value is
58 negative, the function will search backwards chronologically, otherwise
59 it will search forward.
61 Returns:
62 A string containing a git SHA1 hash, otherwise None.
63 """
64 # Android-chrome is git only, so no need to resolve this to anything else.
65 if depot == 'android-chrome':
66 return revision_to_check
68 # If the given revision can't be parsed as an integer, then it may already
69 # be a git commit hash.
70 if not bisect_utils.IsStringInt(revision_to_check):
71 return revision_to_check
73 depot_svn = 'svn://svn.chromium.org/chrome/trunk/src'
75 if depot != 'chromium':
76 depot_svn = depot_deps_dict[depot]['svn']
77 svn_revision = int(revision_to_check)
78 git_revision = None
80 if search > 0:
81 search_range = xrange(svn_revision, svn_revision + search, 1)
82 else:
83 search_range = xrange(svn_revision, svn_revision + search, -1)
85 for i in search_range:
86 # NOTE: Checking for the git-svn-id footer is for backwards compatibility.
87 # When we can assume that all the revisions we care about are from after
88 # git commit positions started getting added, we don't need to check this.
89 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i)
90 commit_position_pattern = '^Cr-Commit-Position: .*@{#%d}' % i
91 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern,
92 '--grep', commit_position_pattern, 'origin/master']
93 log_output = bisect_utils.CheckRunGit(cmd, cwd=cwd)
94 log_output = log_output.strip()
96 if log_output:
97 git_revision = log_output
98 break
100 return git_revision
103 def IsInProperBranch():
104 """Checks whether the current branch is "master"."""
105 cmd = ['rev-parse', '--abbrev-ref', 'HEAD']
106 log_output = bisect_utils.CheckRunGit(cmd)
107 log_output = log_output.strip()
108 return log_output == 'master'
111 def GetCommitPosition(git_revision, cwd=None):
112 """Finds git commit postion for the given git hash.
114 This function executes "git footer --position-num <git hash>" command to get
115 commit position the given revision.
117 Args:
118 git_revision: The git SHA1 to use.
119 cwd: Working directory to run the command from.
121 Returns:
122 Git commit position as integer or None.
124 # Some of the respositories are pure git based, unlike other repositories
125 # they doesn't have commit position. e.g., skia, angle.
126 cmd = ['footers', '--position-num', git_revision]
127 output, return_code = bisect_utils.RunGit(cmd, cwd)
128 if not return_code:
129 commit_position = output.strip()
130 if bisect_utils.IsStringInt(commit_position):
131 return int(commit_position)
132 return None
135 def GetCommitTime(git_revision, cwd=None):
136 """Returns commit time for the given revision in UNIX timestamp."""
137 cmd = ['log', '--format=%ct', '-1', git_revision]
138 output = bisect_utils.CheckRunGit(cmd, cwd=cwd)
139 return int(output)
142 def QueryRevisionInfo(revision, cwd=None):
143 """Gathers information on a particular revision, such as author's name,
144 email, subject, and date.
146 Args:
147 revision: Revision you want to gather information on; a git commit hash.
149 Returns:
150 A dict in the following format:
152 'author': %s,
153 'email': %s,
154 'date': %s,
155 'subject': %s,
156 'body': %s,
159 commit_info = {}
161 formats = ['%aN', '%aE', '%s', '%cD', '%b']
162 targets = ['author', 'email', 'subject', 'date', 'body']
164 for i in xrange(len(formats)):
165 cmd = ['log', '--format=%s' % formats[i], '-1', revision]
166 output = bisect_utils.CheckRunGit(cmd, cwd=cwd)
167 commit_info[targets[i]] = output.rstrip()
169 return commit_info
172 def CheckoutFileAtRevision(file_name, revision, cwd=None):
173 """Performs a checkout on a file at the given revision.
175 Returns:
176 True if successful.
178 command = ['checkout', revision, file_name]
179 _, return_code = bisect_utils.RunGit(command, cwd=cwd)
180 return not return_code
183 def RevertFileToHead(file_name):
184 """Un-stages a file and resets the file's state to HEAD.
186 Returns:
187 True if successful.
189 # Reset doesn't seem to return 0 on success.
190 bisect_utils.RunGit(['reset', 'HEAD', file_name])
191 _, return_code = bisect_utils.RunGit(
192 ['checkout', bisect_utils.FILE_DEPS_GIT])
193 return not return_code
196 def QueryFileRevisionHistory(filename, revision_start, revision_end):
197 """Returns a list of commits that modified this file.
199 Args:
200 filename: Name of file.
201 revision_start: Start of revision range (inclusive).
202 revision_end: End of revision range.
204 Returns:
205 Returns a list of commits that touched this file.
207 cmd = [
208 'log',
209 '--format=%H',
210 '%s~1..%s' % (revision_start, revision_end),
211 '--',
212 filename,
214 output = bisect_utils.CheckRunGit(cmd)
215 lines = output.split('\n')
216 return [o for o in lines if o]