blob: 98683289372678b1f08be9c15c244d135fab8b34 [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Git utility."""
from __future__ import print_function
import logging
import re
import subprocess
from bisect_kit import cli
from bisect_kit import util
logger = logging.getLogger(__name__)
GIT_FULL_COMMIT_ID_LENGTH = 40
# Minimal acceptable length of git commit id.
#
# For chromium, hash collision rate over number of digits:
# - 6 digits: 4.85%
# - 7 digits: 0.32%
# - 8 digits: 0.01%
# As foolproof check, 7 digits should be enough.
GIT_MIN_COMMIT_ID_LENGTH = 7
def is_git_rev(s):
"""Is a git hash-like version string.
It accepts shortened hash with at least 7 digits.
"""
if not GIT_MIN_COMMIT_ID_LENGTH <= len(s) <= GIT_FULL_COMMIT_ID_LENGTH:
return False
return bool(re.match(r'^[0-9a-f]+$', s))
def argtype_git_rev(s):
"""Validates git hash."""
if not is_git_rev(s):
msg = 'should be git hash, at least %d digits' % GIT_MIN_COMMIT_ID_LENGTH
raise cli.ArgTypeError(msg, '1a2b3c4d5e')
return s
def checkout_version(git_repo, rev):
"""git checkout.
Args:
git_repo: path of git repo.
rev: git commit revision to checkout.
"""
util.check_call('git', 'checkout', '-q', '-f', rev, cwd=git_repo)
def is_containing_commit(git_repo, rev):
"""Determines given commit exists.
Args:
git_repo: path of git repo.
rev: git commit revision in query.
"""
try:
return util.check_output(
'git', 'cat-file', '-t', rev, cwd=git_repo) == 'commit\n'
except subprocess.CalledProcessError:
return False
def get_revlist(git_repo, old, new):
"""Enumerates git commit between two revisions (inclusive).
Args:
git_repo: path of git repo.
old: git commit revision.
new: git commit revision.
Returns:
list of git revisions. The list contains the input revisions, old and new.
"""
assert old
assert new
cmd = ['git', 'rev-list', '--reverse', '%s^..%s' % (old, new)]
revlist = util.check_output(*cmd, cwd=git_repo).splitlines()
return revlist
def get_commit_log(git_repo, rev):
"""Get git commit log.
Args:
git_repo: path of git repo.
rev: git commit revision.
Returns:
commit log message
"""
cmd = ['git', 'log', '-1', '--format=%B', rev]
msg = util.check_output(*cmd, cwd=git_repo)
return msg
def get_commit_hash(git_repo, rev):
"""Get git commit hash.
Args:
git_repo: path of git repo.
rev: could be git tag, branch, or (shortened) commit hash
Returns:
full git commit hash
"""
cmd = ['git', 'rev-parse', rev]
git_rev = util.check_output(*cmd, cwd=git_repo).strip()
assert git_rev
return git_rev