blob: f7497600d642a7db6b364f43f0e0a50efd519232 [file]
#!/usr/bin/env python
# Copyright 2014 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
"""Prints a short log from HEAD (or [end]) to a pseudo revision number."""
__version__ = '1.0'
import optparse
import subprocess
import sys
import calculate_version # pylint: disable=W0403
def get_logs(root, pseudo_revision, mergebase, start, end):
start_ref = '%s~%d' % (mergebase, pseudo_revision - start)
end_ref = mergebase
if end is not None:
end_ref += '~%d' % (pseudo_revision - end)
refspec = '%s..%s' % (start_ref, end_ref)
cmd = ['git', 'log', refspec, '--date=short', '--format=%ad %ae %s']
nb_commits = (end or pseudo_revision) - start
try:
log = subprocess.check_output(cmd, cwd=root)
except subprocess.CalledProcessError:
print >> sys.stderr, (
'\nFailed to retrieve the log of last %d commits.' % nb_commits)
return 1
maxlen = 0
lines = []
for l in log.rstrip().splitlines():
parts = l.split(' ', 2)
parts[1] = parts[1].split('@', 1)[0]
maxlen = max(maxlen, len(parts[1]))
lines.append(parts)
out = '\n'.join(
'%s %-*s %s' % (parts[0], maxlen, parts[1], parts[2])
for parts in lines)
return out, refspec
def main():
root = calculate_version.checkout_root('.')
pseudo_revision, mergebase = calculate_version.get_head_pseudo_revision(
root, 'origin/master')
is_pristine = calculate_version.is_pristine(root, mergebase)
parser = optparse.OptionParser(
usage='%prog [options] <start> [end]',
version=__version__,
description=sys.modules[__name__].__doc__)
parser.add_option(
'-f', '--force', action='store_true',
help='Run even if not pristine checkout, e.g. HEAD != origin/master')
parser.add_option(
'-F', '--files', action='store_true', help='List all modified files')
options, args = parser.parse_args()
print >> sys.stderr, (
'Current version: %s @ %s\n' % (pseudo_revision, mergebase))
if not args:
parser.error('Specify the pseudo-revision number of the last push.')
start = int(args[0])
end = None
if len(args) == 2:
end = int(args[1])
if len(args) > 2:
parser.error('Too many arguments.')
if start >= pseudo_revision:
parser.error(
'%d >= %d, you specified \'start\' that was not committed yet?'
% (start, pseudo_revision))
if end is not None:
if start >= end:
parser.error('%d >= %d, did you reverse start and end?' % (start, end))
if end > pseudo_revision:
parser.error(
'%d >= %d, you specified \'end\' that was not committed yet?'
% (end, pseudo_revision))
nb_commits = (end or pseudo_revision) - start
if not is_pristine:
if not options.force:
parser.error(
'Make sure to sync to what was committed and uploaded first.')
print >> sys.stderr, (
'Warning: --force was specified, continuing even if not pristine.\n')
out, refspec = get_logs(root, pseudo_revision, mergebase, start, end)
print(out)
if options.files:
print('')
cmd = ['git', 'diff', refspec, '--stat', '-C', '-C']
try:
subprocess.check_call(cmd, cwd=root)
except subprocess.CalledProcessError:
print >> sys.stderr, (
'\nFailed to list files of last %d commits.' % nb_commits)
return 1
return 0
if __name__ == '__main__':
sys.exit(main())