Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/util/cstyle.py
34878 views
1
# Copyright (C) 2012 by the Massachusetts Institute of Technology.
2
# All rights reserved.
3
#
4
# Export of this software from the United States of America may
5
# require a specific license from the United States Government.
6
# It is the responsibility of any person or organization contemplating
7
# export to obtain such a license before exporting.
8
#
9
# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10
# distribute this software and its documentation for any purpose and
11
# without fee is hereby granted, provided that the above copyright
12
# notice appear in all copies and that both that copyright notice and
13
# this permission notice appear in supporting documentation, and that
14
# the name of M.I.T. not be used in advertising or publicity pertaining
15
# to distribution of the software without specific, written prior
16
# permission. Furthermore if you modify this software you must label
17
# your software as modified software and not distribute it in such a
18
# fashion that it might be confused with the original M.I.T. software.
19
# M.I.T. makes no representations about the suitability of
20
# this software for any purpose. It is provided "as is" without express
21
# or implied warranty.
22
23
# This program attempts to detect MIT krb5 coding style violations
24
# attributable to the changes a series of git commits. It can be run
25
# from anywhere within a git working tree.
26
27
import getopt
28
import os
29
import re
30
import sys
31
from subprocess import Popen, PIPE, call
32
33
def usage():
34
u = ['Usage: cstyle [-w] [rev|rev1..rev2]',
35
'',
36
'By default, checks working tree against HEAD, or checks changes in',
37
'HEAD if the working tree is clean. With a revision option, checks',
38
'changes in rev or the series rev1..rev2. With the -w option,',
39
'checks working tree against rev (defaults to HEAD).']
40
sys.stderr.write('\n'.join(u) + '\n')
41
sys.exit(1)
42
43
44
# Run a command and return a list of its output lines.
45
def run(args):
46
# subprocess.check_output would be ideal here, but requires Python 2.7.
47
p = Popen(args, stdout=PIPE, stderr=PIPE, universal_newlines=True)
48
out, err = p.communicate()
49
if p.returncode != 0:
50
sys.stderr.write('Failed command: ' + ' '.join(args) + '\n')
51
if err != '':
52
sys.stderr.write('stderr:\n' + err)
53
sys.stderr.write('Unexpected command failure, exiting\n')
54
sys.exit(1)
55
return out.splitlines()
56
57
58
# Find the top level of the git working tree, or None if we're not in
59
# one.
60
def find_toplevel():
61
# git doesn't seem to have a way to do this, so we search by hand.
62
dir = os.getcwd()
63
while True:
64
if os.path.exists(os.path.join(dir, '.git')):
65
break
66
parent = os.path.dirname(dir)
67
if (parent == dir):
68
return None
69
dir = parent
70
return dir
71
72
73
# Check for style issues in a file within rev (or within the current
74
# checkout if rev is None). Report only problems on line numbers in
75
# new_lines.
76
line_re = re.compile(r'^\s*(\d+) (.*)$')
77
def check_file(filename, rev, new_lines):
78
# Process only C source files under src.
79
root, ext = os.path.splitext(filename)
80
if not filename.startswith('src/') or ext not in ('.c', '.h', '.hin'):
81
return
82
dispname = filename[4:]
83
84
if rev is None:
85
p1 = Popen(['cat', filename], stdout=PIPE)
86
else:
87
p1 = Popen(['git', 'show', rev + ':' + filename], stdout=PIPE)
88
p2 = Popen([sys.executable, 'src/util/cstyle-file.py'], stdin=p1.stdout,
89
stdout=PIPE, universal_newlines=True)
90
p1.stdout.close()
91
out, err = p2.communicate()
92
if p2.returncode != 0:
93
sys.exit(1)
94
95
first = True
96
for line in out.splitlines():
97
m = line_re.match(line)
98
if int(m.group(1)) in new_lines:
99
if first:
100
print(' ' + dispname + ':')
101
first = False
102
print(' ' + line)
103
104
105
# Determine the lines of each file modified by diff (a sequence of
106
# strings) and check for style violations in those lines. rev
107
# indicates the version in which the new contents of each file can be
108
# found, or is None if the current contents are in the working copy.
109
chunk_header_re = re.compile(r'^@@ -\d+(,(\d+))? \+(\d+)(,(\d+))? @@')
110
def check_diff(diff, rev):
111
old_count, new_count, lineno = 0, 0, 0
112
filename = None
113
for line in diff:
114
if not line or line.startswith('\\ No newline'):
115
continue
116
if old_count > 0 or new_count > 0:
117
# We're in a chunk.
118
if line[0] == '+':
119
new_lines.append(lineno)
120
if line[0] in ('+', ' '):
121
new_count = new_count - 1
122
lineno = lineno + 1
123
if line[0] in ('-', ' '):
124
old_count = old_count - 1
125
elif line.startswith('+++ b/'):
126
# We're starting a new file. Check the last one.
127
if filename:
128
check_file(filename, rev, new_lines)
129
filename = line[6:]
130
new_lines = []
131
else:
132
m = chunk_header_re.match(line)
133
if m:
134
old_count = int(m.group(2) or '1')
135
lineno = int(m.group(3))
136
new_count = int(m.group(5) or '1')
137
138
# Check the last file in the diff.
139
if filename:
140
check_file(filename, rev, new_lines)
141
142
143
# Check a sequence of revisions for style issues.
144
def check_series(revlist):
145
for rev in revlist:
146
sys.stdout.flush()
147
call(['git', 'show', '-s', '--oneline', rev])
148
diff = run(['git', 'diff-tree', '--no-commit-id', '--root', '-M',
149
'--cc', rev])
150
check_diff(diff, rev)
151
152
153
# Parse arguments.
154
try:
155
opts, args = getopt.getopt(sys.argv[1:], 'w')
156
except getopt.GetoptError as err:
157
print(str(err))
158
usage()
159
if len(args) > 1:
160
usage()
161
162
# Change to the top level of the working tree so we easily run the file
163
# checker and refer to working tree files.
164
toplevel = find_toplevel()
165
if toplevel is None:
166
sys.stderr.write('%s must be run within a git working tree')
167
os.chdir(toplevel)
168
169
if ('-w', '') in opts:
170
# Check the working tree against a base revision.
171
arg = 'HEAD'
172
if args:
173
arg = args[0]
174
check_diff(run(['git', 'diff', arg]), None)
175
elif args:
176
# Check the differences in a rev or a series of revs.
177
if '..' in args[0]:
178
check_series(run(['git', 'rev-list', '--reverse', args[0]]))
179
else:
180
check_series([args[0]])
181
else:
182
# No options or arguments. Check the differences against HEAD, or
183
# the differences in HEAD if the working tree is clean.
184
diff = run(['git', 'diff', 'HEAD'])
185
if diff:
186
check_diff(diff, None)
187
else:
188
check_series(['HEAD'])
189
190