forked from luci/luci-py
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog_since.py
executable file
·110 lines (92 loc) · 3.37 KB
/
log_since.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/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())