style.py (8226:bca419132437) style.py (8227:f3aaa2470b5a)
1#! /usr/bin/env python
2# Copyright (c) 2006 The Regents of The University of Michigan
1#! /usr/bin/env python
2# Copyright (c) 2006 The Regents of The University of Michigan
3# Copyright (c) 2007 The Hewlett-Packard Development Company
3# Copyright (c) 2007,2011 The Hewlett-Packard Development Company
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the

--- 11 unchanged lines hidden (view full) ---

23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the

--- 11 unchanged lines hidden (view full) ---

23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31import re
31import heapq
32import os
32import os
33import re
33import sys
34
34import sys
35
35sys.path.insert(0, os.path.dirname(__file__))
36from os.path import dirname, join as joinpath
37from itertools import count
38from mercurial import bdiff, mdiff
36
39
40current_dir = dirname(__file__)
41sys.path.insert(0, current_dir)
42sys.path.insert(1, joinpath(dirname(current_dir), 'src', 'python'))
43
44from m5.util import neg_inf, pos_inf, Region, Regions
37from file_types import lang_type
38
45from file_types import lang_type
46
47all_regions = Region(neg_inf, pos_inf)
48
39tabsize = 8
40lead = re.compile(r'^([ \t]+)')
41trail = re.compile(r'([ \t]+)$')
42any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
43good_control = re.compile(r'\b(if|while|for) [(]')
44
49tabsize = 8
50lead = re.compile(r'^([ \t]+)')
51trail = re.compile(r'([ \t]+)$')
52any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
53good_control = re.compile(r'\b(if|while|for) [(]')
54
45whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
46format_types = set(('C', 'C++'))
47
55format_types = set(('C', 'C++'))
56
57def modified_regions(old_data, new_data):
58 regions = Regions()
59 beg = None
60 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
61 if beg is not None and beg != fbeg:
62 regions.append(beg, fbeg)
63 beg = fend
64 return regions
65
66def modregions(wctx, fname):
67 fctx = wctx.filectx(fname)
68 pctx = fctx.parents()
69
70 file_data = fctx.data()
71 lines = mdiff.splitnewlines(file_data)
72 if len(pctx) in (1, 2):
73 mod_regions = modified_regions(pctx[0].data(), file_data)
74 if len(pctx) == 2:
75 m2 = modified_regions(pctx[1].data(), file_data)
76 # only the lines that are new in both
77 mod_regions &= m2
78 else:
79 mod_regions = Regions()
80 mod_regions.add(0, len(lines))
81
82 return mod_regions
83
48class UserInterface(object):
49 def __init__(self, verbose=False, auto=False):
50 self.auto = auto
51 self.verbose = verbose
52
53 def prompt(self, prompt, results, default):
54 if self.auto:
55 return self.auto

--- 16 unchanged lines hidden (view full) ---

72
73class StdioUI(UserInterface):
74 def do_prompt(self, prompt, results, default):
75 return raw_input(prompt) or default
76
77 def write(self, string):
78 sys.stdout.write(string)
79
84class UserInterface(object):
85 def __init__(self, verbose=False, auto=False):
86 self.auto = auto
87 self.verbose = verbose
88
89 def prompt(self, prompt, results, default):
90 if self.auto:
91 return self.auto

--- 16 unchanged lines hidden (view full) ---

108
109class StdioUI(UserInterface):
110 def do_prompt(self, prompt, results, default):
111 return raw_input(prompt) or default
112
113 def write(self, string):
114 sys.stdout.write(string)
115
80def checkwhite_line(line):
81 match = lead.search(line)
82 if match and match.group(1).find('\t') != -1:
83 return False
116class Region(object):
117 def __init__(self, asdf):
118 self.regions = Foo
84
119
85 match = trail.search(line)
86 if match:
87 return False
120class Verifier(object):
121 def __init__(self, ui, repo=None):
122 self.ui = ui
123 self.repo = repo
124 if repo is None:
125 self.wctx = None
88
126
89 return True
127 def __getattr__(self, attr):
128 if attr in ('prompt', 'write'):
129 return getattr(self.ui, attr)
90
130
91def checkwhite(filename):
92 if lang_type(filename) not in whitespace_types:
93 return
131 if attr == 'wctx':
132 try:
133 wctx = repo.workingctx()
134 except:
135 from mercurial import context
136 wctx = context.workingctx(repo)
137 self.wctx = wctx
138 return wctx
94
139
95 try:
96 f = file(filename, 'r+')
97 except OSError, msg:
98 print 'could not open file %s: %s' % (filename, msg)
99 return
140 raise AttributeError
100
141
101 for num,line in enumerate(f):
102 if not checkwhite_line(line):
103 yield line,num + 1
142 def open(self, filename, mode):
143 if self.repo:
144 filename = self.repo.wjoin(filename)
104
145
105def fixwhite_line(line):
106 if lead.search(line):
107 newline = ''
108 for i,c in enumerate(line):
109 if c == ' ':
110 newline += ' '
111 elif c == '\t':
112 newline += ' ' * (tabsize - len(newline) % tabsize)
113 else:
114 newline += line[i:]
115 break
146 try:
147 f = file(filename, mode)
148 except OSError, msg:
149 print 'could not open file %s: %s' % (filename, msg)
150 return None
116
151
117 line = newline
152 return f
118
153
119 return line.rstrip() + '\n'
154 def skip(self, filename):
155 return lang_type(filename) not in self.languages
120
156
121def fixwhite(filename, fixonly=None):
122 if lang_type(filename) not in whitespace_types:
123 return
157 def check(self, filename, regions=all_regions):
158 f = self.open(filename, 'r')
124
159
125 try:
126 f = file(filename, 'r+')
127 except OSError, msg:
128 print 'could not open file %s: %s' % (filename, msg)
129 return
160 errors = 0
161 for num,line in enumerate(f):
162 if num not in regions:
163 continue
164 if not self.check_line(line):
165 self.write("invalid %s in %s:%d\n" % \
166 (self.test_name, filename, num + 1))
167 if self.ui.verbose:
168 self.write(">>%s<<\n" % line[-1])
169 errors += 1
170 return errors
130
171
131 lines = list(f)
172 def fix(self, filename, regions=all_regions):
173 f = self.open(filename, 'r+')
132
174
133 f.seek(0)
134 f.truncate()
175 lines = list(f)
135
176
136 for i,line in enumerate(lines):
137 if fixonly is None or i in fixonly:
138 line = fixwhite_line(line)
177 f.seek(0)
178 f.truncate()
139
179
140 print >>f, line,
180 for i,line in enumerate(lines):
181 if i in regions:
182 line = self.fix_line(line)
141
183
184 f.write(line)
185 f.close()
186
187class Whitespace(Verifier):
188 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
189 test_name = 'whitespace'
190 def check_line(self, line):
191 match = lead.search(line)
192 if match and match.group(1).find('\t') != -1:
193 return False
194
195 match = trail.search(line)
196 if match:
197 return False
198
199 return True
200
201 def fix_line(self, line):
202 if lead.search(line):
203 newline = ''
204 for i,c in enumerate(line):
205 if c == ' ':
206 newline += ' '
207 elif c == '\t':
208 newline += ' ' * (tabsize - len(newline) % tabsize)
209 else:
210 newline += line[i:]
211 break
212
213 line = newline
214
215 return line.rstrip() + '\n'
216
142def linelen(line):
143 tabs = line.count('\t')
144 if not tabs:
145 return len(line)
146
147 count = 0
148 for c in line:
149 if c == '\t':

--- 86 unchanged lines hidden (view full) ---

236 if cpp:
237 match = any_control.search(line)
238 if match and not good_control.search(line):
239 stats.badcontrol += 1
240 if verbose > 1:
241 msg(i, line, 'improper spacing after %s' % match.group(1))
242 bad()
243
217def linelen(line):
218 tabs = line.count('\t')
219 if not tabs:
220 return len(line)
221
222 count = 0
223 for c in line:
224 if c == '\t':

--- 86 unchanged lines hidden (view full) ---

311 if cpp:
312 match = any_control.search(line)
313 if match and not good_control.search(line):
314 stats.badcontrol += 1
315 if verbose > 1:
316 msg(i, line, 'improper spacing after %s' % match.group(1))
317 bad()
318
244def modified_lines(old_data, new_data, max_lines):
245 from itertools import count
246 from mercurial import bdiff, mdiff
247
248 modified = set()
249 counter = count()
250 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
251 for i in counter:
252 if i < fbeg:
253 modified.add(i)
254 elif i + 1 >= fend:
255 break
256 elif i > max_lines:
257 break
258 return modified
259
260def do_check_style(hgui, repo, *files, **args):
261 """check files for proper m5 style guidelines"""
262 from mercurial import mdiff, util
263
264 auto = args.get('auto', False)
265 if auto:
266 auto = 'f'
267 ui = MercurialUI(hgui, hgui.verbose, auto)
268
269 if files:
270 files = frozenset(files)
271
272 def skip(name):
273 return files and name in files
274
319def do_check_style(hgui, repo, *files, **args):
320 """check files for proper m5 style guidelines"""
321 from mercurial import mdiff, util
322
323 auto = args.get('auto', False)
324 if auto:
325 auto = 'f'
326 ui = MercurialUI(hgui, hgui.verbose, auto)
327
328 if files:
329 files = frozenset(files)
330
331 def skip(name):
332 return files and name in files
333
275 def prompt(name, func, fixonly=None):
334 def prompt(name, func, regions=all_regions):
276 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a')
277 if result == 'a':
278 return True
279 elif result == 'f':
335 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a')
336 if result == 'a':
337 return True
338 elif result == 'f':
280 func(repo.wjoin(name), fixonly)
339 func(repo.wjoin(name), regions)
281
282 return False
283
284 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
285
340
341 return False
342
343 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
344
345 whitespace = Whitespace(ui)
286 for fname in added:
346 for fname in added:
287 if skip(fname):
347 if skip(fname) or whitespace.skip(fname):
288 continue
289
348 continue
349
290 ok = True
291 for line,num in checkwhite(repo.wjoin(fname)):
292 ui.write("invalid whitespace in %s:%d\n" % (fname, num))
293 if ui.verbose:
294 ui.write(">>%s<<\n" % line[-1])
295 ok = False
296
297 if not ok:
298 if prompt(fname, fixwhite):
350 errors = whitespace.check(fname)
351 if errors:
352 print errors
353 if prompt(fname, whitespace.fix):
299 return True
300
301 try:
302 wctx = repo.workingctx()
303 except:
304 from mercurial import context
305 wctx = context.workingctx(repo)
306
307 for fname in modified:
354 return True
355
356 try:
357 wctx = repo.workingctx()
358 except:
359 from mercurial import context
360 wctx = context.workingctx(repo)
361
362 for fname in modified:
308 if skip(fname):
363 if skip(fname) or whitespace.skip(fname):
309 continue
310
364 continue
365
311 if lang_type(fname) not in whitespace_types:
312 continue
366 regions = modregions(wctx, fname)
313
367
314 fctx = wctx.filectx(fname)
315 pctx = fctx.parents()
316
317 file_data = fctx.data()
318 lines = mdiff.splitnewlines(file_data)
319 if len(pctx) in (1, 2):
320 mod_lines = modified_lines(pctx[0].data(), file_data, len(lines))
321 if len(pctx) == 2:
322 m2 = modified_lines(pctx[1].data(), file_data, len(lines))
323 # only the lines that are new in both
324 mod_lines = mod_lines & m2
325 else:
326 mod_lines = xrange(0, len(lines))
327
328 fixonly = set()
329 for i,line in enumerate(lines):
330 if i not in mod_lines:
331 continue
332
333 if checkwhite_line(line):
334 continue
335
336 ui.write("invalid whitespace: %s:%d\n" % (fname, i+1))
337 if ui.verbose:
338 ui.write(">>%s<<\n" % line[:-1])
339 fixonly.add(i)
340
341 if fixonly:
342 if prompt(fname, fixwhite, fixonly):
368 errors = whitespace.check(fname, regions)
369 if errors:
370 if prompt(fname, whitespace.fix, regions):
343 return True
344
345def do_check_format(hgui, repo, **args):
346 ui = MercurialUI(hgui, hgui.verbose, auto)
347
348 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
349
350 verbose = 0

--- 111 unchanged lines hidden ---
371 return True
372
373def do_check_format(hgui, repo, **args):
374 ui = MercurialUI(hgui, hgui.verbose, auto)
375
376 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
377
378 verbose = 0

--- 111 unchanged lines hidden ---