Commit 172ccc05 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

Revert "Reland: "Add --merge-base-ref option to lastchange.py"""

This reverts commit f4f6c5ff.

Reason for revert:
Still fails on chromeos build-bot. See 919777 #4 for more details.
Example failure:
  https://cros-goldeneye.corp.google.com/chromeos/healthmonitoring/buildDetails?buildbucketId=8922379830326735328

Bug: 919777

Original change's description:
> Reland: "Add --merge-base-ref option to lastchange.py""
> 
> Reland commit fb941d6f.
> Revert was bff8ece1.
> 
> The original commit changed RunGitCommand as a standard refactor
> to simplify the code in a single module. Turns out that module is
> called by python code in other repositories. Therefore this version
> retains the old behavior of RunGitCommand until the other repositories
> can be changed.
> 
> Change-Id: Ifcbb74c6928ad27169a9381415277d95d0c9265e
> Bug: 917159
> Reviewed-on: https://chromium-review.googlesource.com/c/1401511
> Reviewed-by: Alexander Alekseev <alemate@chromium.org>
> Reviewed-by: John Budorick <jbudorick@chromium.org>
> Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
> Commit-Queue: Eli Ribble <eliribble@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#628936}

TBR=alemate@chromium.org,dpranke@chromium.org,tandrii@chromium.org,jbudorick@chromium.org,eliribble@chromium.org

Change-Id: Ia65dba384bf477660c33f89c1cd3c0e76d5e6d61
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 917159
Reviewed-on: https://chromium-review.googlesource.com/c/1454803Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#629165}
parent 46ebd310
......@@ -7,23 +7,20 @@
lastchange.py -- Chromium revision fetching utility.
"""
import argparse
import collections
import re
import logging
import argparse
import os
import subprocess
import sys
VersionInfo = collections.namedtuple("VersionInfo",
("revision_id", "revision", "timestamp"))
class VersionInfo(object):
def __init__(self, revision_id, full_revision_string, timestamp):
self.revision_id = revision_id
self.revision = full_revision_string
self.timestamp = timestamp
class GitError(Exception):
pass
# This function exists for compatibility with logic outside this
# repository that uses this file as a library.
# TODO(eliribble) remove this function after it has been ported into
# the repositories that depend on it
def RunGitCommand(directory, command):
"""
Launches git subcommand.
......@@ -52,97 +49,50 @@ def RunGitCommand(directory, command):
return None
def _RunGitCommand(directory, command):
"""
Launches git subcommand.
Returns:
The stripped stdout of the git command.
Raises:
GitError on failure, including a nonzero return code.
def FetchGitRevision(directory, filter):
"""
command = ['git'] + command
# Force shell usage under cygwin. This is a workaround for
# mysterious loss of cwd while invoking cygwin's git.
# We can't just pass shell=True to Popen, as under win32 this will
# cause CMD to be used, while we explicitly want a cygwin shell.
if sys.platform == 'cygwin':
command = ['sh', '-c', ' '.join(command)]
try:
logging.info("Executing '%s' in %s", ' '.join(command), directory)
proc = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=directory,
shell=(sys.platform=='win32'))
stdout, stderr = proc.communicate()
stdout = stdout.strip()
logging.debug("returncode: %d", proc.returncode)
logging.debug("stdout: %s", stdout)
logging.debug("stderr: %s", stderr)
if proc.returncode != 0 or not stdout:
raise GitError((
"Git command 'git {}' in {} failed: "
"rc={}, stdout='{}' stderr='{}'").format(
" ".join(command), directory, proc.returncode, stdout, stderr))
return stdout
except OSError as e:
raise GitError("Git command 'git {}' in {} failed: {}".format(
" ".join(command), directory, e))
Fetch the Git hash (and Cr-Commit-Position if any) for a given directory.
def GetMergeBase(directory, ref):
"""
Return the merge-base of HEAD and ref.
Errors are swallowed.
Args:
directory: The directory containing the .git directory.
ref: The ref to use to find the merge base.
Returns:
The git commit SHA of the merge-base as a string.
A VersionInfo object or None on error.
"""
logging.debug("Calculating merge base between HEAD and %s in %s",
ref, directory)
command = ['merge-base', 'HEAD', ref]
return _RunGitCommand(directory, command)
def FetchGitRevision(directory, commit_filter, start_commit="HEAD"):
hsh = ''
git_args = ['log', '-1', '--format=%H %ct']
if filter is not None:
git_args.append('--grep=' + filter)
proc = RunGitCommand(directory, git_args)
if proc:
output = proc.communicate()[0].strip()
if proc.returncode == 0 and output:
hsh, ct = output.split()
else:
logging.error('Git error: rc=%d, output=%r' %
(proc.returncode, output))
if not hsh:
return None
pos = ''
proc = RunGitCommand(directory, ['cat-file', 'commit', hsh])
if proc:
output = proc.communicate()[0]
if proc.returncode == 0 and output:
for line in reversed(output.splitlines()):
if line.startswith('Cr-Commit-Position:'):
pos = line.rsplit()[-1].strip()
break
return VersionInfo(hsh, '%s-%s' % (hsh, pos), int(ct))
def FetchVersionInfo(directory=None, filter=None):
"""
Returns the last change (as a VersionInfo object)
from some appropriate revision control system.
Args:
directory: The directory containing the .git directory.
commit_filter: A filter to supply to grep to filter commits
start_commit: A commit identifier. The result of this function
will be limited to only consider commits before the provided
commit.
Returns:
A VersionInfo object. On error all values will be 0.
"""
hash_ = ''
git_args = ['log', '-1', '--format=%H %ct']
if commit_filter is not None:
git_args.append('--grep=' + commit_filter)
git_args.append(start_commit)
output = _RunGitCommand(directory, git_args)
hash_, commit_timestamp = output.split()
if not hash_:
return VersionInfo('0', '0', 0)
revision = hash_
output = _RunGitCommand(directory, ['cat-file', 'commit', hash_])
for line in reversed(output.splitlines()):
if line.startswith('Cr-Commit-Position:'):
pos = line.rsplit()[-1].strip()
logging.debug("Found Cr-Commit-Position '%s'", pos)
revision = "{}-{}".format(hash_, pos)
break
return VersionInfo(hash_, revision, int(commit_timestamp))
version_info = FetchGitRevision(directory, filter)
if not version_info:
version_info = VersionInfo('0', '0', 0)
return version_info
def GetHeaderGuard(path):
......@@ -183,16 +133,6 @@ def GetHeaderContents(path, define, version):
return header_contents
def GetGitTopDirectory(source_dir):
"""Get the top git directory - the directory that contains the .git directory.
Args:
source_dir: The directory to search.
Returns:
The output of "git rev-parse --show-toplevel" as a string
"""
return _RunGitCommand(source_dir, ['rev-parse', '--show-toplevel'])
def WriteIfChanged(file_name, contents):
"""
Writes the specified contents to the specified file_name
......@@ -217,23 +157,20 @@ def main(argv=None):
parser = argparse.ArgumentParser(usage="lastchange.py [options]")
parser.add_argument("-m", "--version-macro",
help=("Name of C #define when using --header. Defaults to "
"LAST_CHANGE."))
help="Name of C #define when using --header. Defaults to " +
"LAST_CHANGE.",
default="LAST_CHANGE")
parser.add_argument("-o", "--output", metavar="FILE",
help=("Write last change to FILE. "
"Can be combined with --header to write both files."))
help="Write last change to FILE. " +
"Can be combined with --header to write both files.")
parser.add_argument("--header", metavar="FILE",
help=("Write last change to FILE as a C/C++ header. "
"Can be combined with --output to write both files."))
parser.add_argument("--merge-base-ref",
default=None,
help=("Only consider changes since the merge "
"base between HEAD and the provided ref"))
parser.add_argument("--revision-id-only", action='store_true',
help=("Output the revision as a VCS revision ID only (in "
"Git, a 40-character commit hash, excluding the "
"Cr-Commit-Position)."))
parser.add_argument("--print-only", action="store_true",
parser.add_argument("--print-only", action='store_true',
help=("Just print the revision string. Overrides any "
"file-output-related options."))
parser.add_argument("-s", "--source-dir", metavar="DIR",
......@@ -243,14 +180,13 @@ def main(argv=None):
"matches the supplied filter regex. Defaults to "
"'^Change-Id:' to suppress local commits."),
default='^Change-Id:')
args, extras = parser.parse_known_args(argv[1:])
logging.basicConfig(level=logging.WARNING)
out_file = args.output
header = args.header
commit_filter = args.filter
filter=args.filter
while len(extras) and out_file is None:
if out_file is None:
......@@ -260,37 +196,18 @@ def main(argv=None):
parser.print_help()
sys.exit(2)
source_dir = args.source_dir or os.path.dirname(os.path.abspath(__file__))
try:
git_top_dir = GetGitTopDirectory(source_dir)
except GitError as e:
logging.error("Failed to get git top directory from '%s': %s",
source_dir, e)
return 2
if args.merge_base_ref:
try:
merge_base_sha = GetMergeBase(git_top_dir, args.merge_base_ref)
except GitError as e:
logging.error("You requested a --merge-base-ref value of '%s' but no "
"merge base could be found between it and HEAD. Git "
"reports: %s", args.merge_base_ref, e)
return 3
if args.source_dir:
src_dir = args.source_dir
else:
merge_base_sha = 'HEAD'
try:
version_info = FetchGitRevision(git_top_dir, commit_filter, merge_base_sha)
except GitError as e:
logging.error("Failed to get version info: %s")
return 1
src_dir = os.path.dirname(os.path.abspath(__file__))
version_info = FetchVersionInfo(directory=src_dir, filter=filter)
revision_string = version_info.revision
if args.revision_id_only:
revision_string = version_info.revision_id
if args.print_only:
print(revision_string)
print revision_string
else:
contents = "LASTCHANGE=%s\n" % revision_string
if not out_file and not args.header:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment