blob: 5aadaec657eee32c2d1b7ce6b97c70cc4a3b4a4e [file] [log] [blame]
# 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 re
from recipe_engine import recipe_api
class CommitPositionApi(recipe_api.RecipeApi):
"""Recipe module providing commit position parsing and manipulation."""
RE_COMMIT_POSITION = re.compile('(?P<branch>.+)@{#(?P<revision>\d+)}')
COMMIT_POS_STR = '^Cr-Commit-Position: refs/heads/master@{#%d}'
@classmethod
def parse(cls, value):
match = cls.RE_COMMIT_POSITION.match(value)
if not match:
raise ValueError("Invalid commit position (%s)" % (value,))
return match.group('branch'), int(match.group('revision'))
@classmethod
def parse_branch(cls, value):
branch, _ = cls.parse(value)
return branch
@classmethod
def parse_revision(cls, value):
_, revision = cls.parse(value)
return revision
@classmethod
def construct(cls, branch, value):
value = int(value)
return '%(branch)s@{#%(value)d}' % {
'branch': branch,
'value': value,
}
def chromium_hash_from_commit_position(self, commit_pos):
"""Resolve a commit position in the chromium repo to its commit hash."""
try:
int_pos = int(commit_pos)
except ValueError:
raise self.m.step.StepFailure('Invalid commit position (%s).'
% (commit_pos,))
with self.m.context(cwd=self.m.path['checkout']):
step_result = self.m.git('log', '--format=hash:%H', '--grep',
self.COMMIT_POS_STR % int_pos, '-1',
'origin/master',
stdout=self.m.raw_io.output_text(),
name='resolving commit_pos ' + str(commit_pos))
try:
result_line = [line for line in step_result.stdout.splitlines()
if line.startswith('hash:')][0]
result = result_line.split(':')[1]
int(result, 16)
return result
except (IndexError, ValueError): # pragma: no cover
raise self.m.step.StepFailure(
'Could not parse commit hash from git log output' +
step_result.stdout)
def chromium_commit_position_from_hash(self, sha):
"""Resolve a chromium commit hash to its commit position."""
try:
assert int(sha, 16)
sha = str(sha) # Unicode would break the step when passed in the name
except (AssertionError, ValueError):
raise self.m.step.StepFailure('Invalid commit hash: ' + sha)
with self.m.context(cwd=self.m.path['checkout']):
step_result = self.m.git('footers', '--position', sha,
stdout=self.m.raw_io.output_text(),
name='resolving hash ' + sha)
try:
result = int(self.parse_revision(str(step_result.stdout)))
except ValueError:
raise self.m.step.StepFailure(
'Could not parse commit position from git output: ' +
(step_result.stdout or ''))
return result