10637.3.1
by Guilherme Salgado
Use the default python version instead of a hard-coded version |
1 |
#!/usr/bin/python
|
8687.15.4
by Karl Fogel
Add the copyright header block to more files; tweak format in a few files. |
2 |
#
|
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
|
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
5 |
||
6912.5.11
by Curtis Hovey
Minor fixes. |
6 |
"""Create a XXX comment reports in many formats."""
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
7 |
|
8 |
||
9 |
__metaclass__ = type |
|
10 |
||
11 |
||
12 |
import cgi |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
13 |
from optparse import OptionParser |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
14 |
import os |
15 |
import re |
|
16 |
import sys |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
17 |
from textwrap import dedent |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
18 |
import time |
19 |
||
20 |
from bzrlib import bzrdir |
|
14612.2.6
by William Grant
utilities |
21 |
from bzrlib.errors import NotBranchError |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
22 |
|
23 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
24 |
excluded_dir_re = re.compile(r'.*(not-used|lib/mailman)') |
25 |
excluded_file_re = re.compile(r'.*(pyc$)') |
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
26 |
|
27 |
||
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
28 |
class Report: |
29 |
"""The base class for an XXX report."""
|
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
30 |
# Match XXX comments.
|
31 |
xxx_re = re.compile('^\s*(<!--|//|#) XXX[:,]?') |
|
32 |
||
33 |
def __init__(self, root_dir, output_name=None): |
|
34 |
"""Create and write the HTML report to a file.
|
|
35 |
||
36 |
:param root_dir: The root directory that contains files with comments.
|
|
37 |
:param output_name: The name of the html file to write to.
|
|
38 |
"""
|
|
39 |
assert os.path.isdir(root_dir), ( |
|
40 |
"Root directory does not exist: %s." % root_dir) |
|
41 |
self.root_dir = root_dir |
|
42 |
self.output_name = output_name |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
43 |
self.revno = self._getBranchRevno() |
44 |
self.comments = self._findComments() |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
45 |
|
46 |
def _close(self, output_file): |
|
47 |
"""Close the output_file if it was opened."""
|
|
48 |
if self.output_name is not None: |
|
49 |
output_file.close() |
|
50 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
51 |
def _getBranchRevno(self): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
52 |
"""Return the bazaar revision number of the branch or None."""
|
53 |
# pylint: disable-msg=W0612
|
|
54 |
a_bzrdir = bzrdir.BzrDir.open_containing(self.root_dir)[0] |
|
55 |
try: |
|
56 |
branch = a_bzrdir.open_branch() |
|
57 |
branch.lock_read() |
|
58 |
try: |
|
59 |
revno, head = branch.last_revision_info() |
|
60 |
finally: |
|
61 |
branch.unlock() |
|
62 |
except NotBranchError: |
|
63 |
revno = None |
|
64 |
return revno |
|
65 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
66 |
def _findComments(self): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
67 |
"""Set the list of XXX comments in files below a directory."""
|
68 |
comments = [] |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
69 |
for file_path in self._findFiles(): |
70 |
comments.extend(self._extractComments(file_path)) |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
71 |
return comments |
72 |
||
73 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
74 |
def _findFiles(self): |
6912.5.15
by Curtis Hovey
added lib/mailman to the skip list. |
75 |
"""Generate a list of matching files below a directory."""
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
76 |
for path, subdirs, files in os.walk(self.root_dir): |
6912.5.15
by Curtis Hovey
added lib/mailman to the skip list. |
77 |
subdirs[:] = [dir_name for dir_name in subdirs |
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
78 |
if self._isTraversable(path, dir_name)] |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
79 |
for file in files: |
80 |
file_path = os.path.join(path, file) |
|
81 |
if os.path.islink(file_path): |
|
82 |
continue
|
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
83 |
if excluded_file_re.match(file) is None: |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
84 |
yield os.path.join(path, file) |
85 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
86 |
def _isTraversable(self, path, dir_name): |
6912.5.16
by Curtis Hovey
Minor changes per review. |
87 |
"""Return True if path/dir_name does not match dir_re pattern."""
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
88 |
return excluded_dir_re.match(os.path.join(path, dir_name)) is None |
6912.5.15
by Curtis Hovey
added lib/mailman to the skip list. |
89 |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
90 |
def _extractComments(self, file_path): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
91 |
"""Return a list of XXX comments in a file.
|
92 |
||
93 |
:param file_path: The path of the file that contains XXX comments.
|
|
94 |
"""
|
|
95 |
comments = [] |
|
96 |
file = open(file_path, 'r') |
|
97 |
try: |
|
98 |
comment = None |
|
99 |
for line_num, line in enumerate(file): |
|
100 |
xxx_mark = self.xxx_re.match(line) |
|
101 |
if xxx_mark is None and comment is None: |
|
102 |
# The loop is not in a comment or starting a comment.
|
|
103 |
continue
|
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
104 |
if xxx_mark is not None and comment is not None: |
105 |
# Two XXX comments run together.
|
|
106 |
self._finaliseComment(comments, comment) |
|
107 |
comment = None |
|
108 |
if xxx_mark is not None and comment is None: |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
109 |
# Start a new comment.
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
110 |
comment = self.extractMetadata(line) |
111 |
comment['file_path'] = file_path |
|
112 |
comment['line_no'] = line_num + 1 |
|
113 |
comment['context_list'] = [] |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
114 |
elif '#' in line and '##' not in line: |
115 |
# Continue collecting the comment text.
|
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
116 |
leading_, text = line.split('#', 1) |
117 |
comment['text_list'].append(text.lstrip()) |
|
118 |
elif xxx_mark is None and len(comment['context_list']) < 2: |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
119 |
# Collect the code context of the comment.
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
120 |
comment['context_list'].append(line) |
121 |
elif xxx_mark is None and len(comment['context_list']) == 2: |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
122 |
# Finalise the comment.
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
123 |
comment['context_list'].append(line) |
124 |
self._finaliseComment(comments, comment) |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
125 |
comment = None |
126 |
else: |
|
127 |
raise ValueError, ( |
|
128 |
"comment or xxx_mark are in an unknown state.") |
|
6912.5.16
by Curtis Hovey
Minor changes per review. |
129 |
if comment is not None: |
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
130 |
self._finaliseComment(comments, comment) |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
131 |
finally: |
132 |
file.close() |
|
133 |
return comments |
|
134 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
135 |
def _finaliseComment(self, comments, comment): |
136 |
"""Replace the lists with strs and append the comment to comments."""
|
|
137 |
context = ''.join(comment['context_list']) |
|
138 |
if context.strip() == '': |
|
139 |
# Whitespace is not context; do not store it.
|
|
140 |
context = '' |
|
141 |
comment['context'] = context |
|
142 |
comment['text'] = ''.join(comment['text_list']).strip() |
|
143 |
del comment['context_list'] |
|
144 |
del comment['text_list'] |
|
6912.5.16
by Curtis Hovey
Minor changes per review. |
145 |
comments.append(comment) |
146 |
||
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
147 |
# The standard XXX comment form of:
|
148 |
# 'XXX: First Last Name 2007-07-01 bug=nnnn spec=cccc:'
|
|
6912.5.16
by Curtis Hovey
Minor changes per review. |
149 |
# Colons, commas, and spaces may follow each token.
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
150 |
xxx_person_date_re = re.compile(r""" |
6912.5.11
by Curtis Hovey
Minor fixes. |
151 |
.*XXX[:,]?[ ] # The XXX indicator.
|
152 |
(?P<person>[a-zA-Z][^:]*[\w])[,: ]* # The persons's nick.
|
|
153 |
(?P<date>\d\d\d\d[/-]?\d\d[/-]?\d\d)[,: ]* # The date in YYYY-MM-DD.
|
|
154 |
(?:[(]?bug[s]?[= ](?P<bug>[\w-]*)[),: ]*)? # The bug id.
|
|
155 |
(?:[(]?spec[= ](?P<spec>[\w-]*)[),: ]*)? # The spec name.
|
|
156 |
(?P<text>.*) # The comment text.
|
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
157 |
""", re.VERBOSE) |
158 |
||
159 |
# An uncommon XXX comment form of:
|
|
160 |
# 'XXX: 2007-01-01 First Last Name bug=nnnn spec=cccc:'
|
|
161 |
# Colons, commas, and spaces may follow each token.
|
|
162 |
xxx_date_person_re = re.compile(r""" |
|
6912.5.11
by Curtis Hovey
Minor fixes. |
163 |
.*XXX[:,]?[ ] # The XXX indicator.
|
164 |
(?P<date>\d\d\d\d[/-]?\d\d[/-]?\d\d)[,: ]* # The date in YYYY-MM-DD.
|
|
165 |
(?P<person>[a-zA-Z][\w]+)[,: ]* # The person's nick.
|
|
166 |
(?:[(]?bug[s]?[= ](?P<bug>[\w-]*)[),: ]*)? # The bug id.
|
|
167 |
(?:[(]?spec[= ](?P<spec>[\w-]*)[),: ]*)? # The spec name.
|
|
168 |
(?P<text>.*) # The comment text.
|
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
169 |
""", re.VERBOSE) |
170 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
171 |
def extractMetadata(self, comment_line): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
172 |
"""Return a dict of metadata extracted from the comment line.
|
173 |
||
174 |
:param comment_line: The first line of an XXX comment contains the
|
|
175 |
metadata.
|
|
176 |
:return: dict(person, date, bug, spec, and [text]). The text is the
|
|
177 |
same as remainder of the comment_line after the metadata is extracted.
|
|
178 |
"""
|
|
179 |
comment = dict(person=None, date=None, bug=None, spec=None, text=[]) |
|
180 |
match = (self.xxx_person_date_re.match(comment_line) |
|
181 |
or self.xxx_date_person_re.match(comment_line)) |
|
182 |
if match is not None: |
|
183 |
# This comment follows a known style.
|
|
184 |
comment['person'] = match.group('person') |
|
185 |
comment['date'] = match.group('date') |
|
186 |
comment['bug'] = match.group('bug') or None |
|
187 |
comment['spec'] = match.group('spec') or None |
|
188 |
text = match.group('text').lstrip(':, ') |
|
189 |
else: |
|
190 |
# Unknown comment format.
|
|
191 |
text = comment_line |
|
192 |
||
193 |
text = text.strip() |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
194 |
comment['text_list'] = [text + '\n'] |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
195 |
return comment |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
196 |
|
6912.5.14
by Curtis Hovey
Added 'not-used' to the list of dirs not to traverse. |
197 |
def write(self): |
198 |
"""Write the total count of comments."""
|
|
199 |
output_file = self._open() |
|
200 |
try: |
|
201 |
output_file.write('%s\n' % len(self.comments)) |
|
202 |
output_file.flush() |
|
203 |
finally: |
|
204 |
self._close(output_file) |
|
205 |
||
206 |
def _open(self): |
|
207 |
"""Open the output_name or use STDOUT."""
|
|
208 |
if self.output_name is not None: |
|
209 |
return open(self.output_name, 'w') |
|
210 |
return sys.stdout |
|
211 |
||
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
212 |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
213 |
class HTMLReport(Report): |
214 |
"""A HTML XXX report."""
|
|
215 |
# Match URLs.
|
|
216 |
http_re = re.compile('(https?://[^ \n&]*)') |
|
217 |
||
218 |
# Match bugs.
|
|
219 |
bug_link_re = re.compile(r'\b(bugs?:?) #?(\d+)', re.IGNORECASE) |
|
220 |
||
221 |
report_top = """\ |
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
222 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
223 |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
224 |
<html>
|
|
225 |
<head>
|
|
226 |
<title>XXX Comment report for Launchpad</title>
|
|
227 |
<style type="text/css" media="screen, print">
|
|
228 |
@import url(https://launchpad.net/+icing/rev6895/+style-slimmer.css);
|
|
229 |
.context {
|
|
230 |
border: #666 1px dashed;
|
|
231 |
width: 50em;
|
|
232 |
}
|
|
233 |
</style>
|
|
234 |
</head>
|
|
235 |
||
236 |
<body style="margin: 1em;">
|
|
237 |
<h1>XXX Comment report for Launchpad</h1>
|
|
238 |
||
239 |
<p>
|
|
240 |
A report of the XXX comments in the rocketfuel branch. All files
|
|
241 |
except *.pyc files were examined.
|
|
242 |
<br />This report may also be available as a tab-delimted file:
|
|
6912.5.13
by Curtis Hovey
Fixed spec links. |
243 |
<a href="xxx-report.csv">xxx-report.csv</a>
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
244 |
</p>
|
245 |
||
246 |
<h3>Summary</h3>
|
|
247 |
||
248 |
<p>
|
|
249 |
There are <strong>%(commentcount)s XXX comments</strong> |
|
250 |
in <strong>revno: %(revno)s</strong>. |
|
251 |
<br />Generated on %(reporttime)s. |
|
252 |
</p>
|
|
253 |
||
254 |
<hr/>
|
|
255 |
||
256 |
<h3>Listing</h3>
|
|
257 |
||
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
258 |
<ol>"""
|
6912.5.8
by Curtis Hovey
Added documentation to xxxreport. |
259 |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
260 |
report_comment = """ |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
261 |
<li>
|
262 |
<div>
|
|
263 |
<strong>File: %(file_path)s:%(line_no)s</strong> |
|
264 |
</div>
|
|
265 |
<div style="margin: .5em 0em 0em 0em;">
|
|
266 |
<strong class="xxx">XXX</strong>:
|
|
267 |
<strong class="person">%(person)s</strong> |
|
268 |
<strong class="date">%(date)s</strong> |
|
269 |
bug %(bugurl)s |
|
6912.5.13
by Curtis Hovey
Fixed spec links. |
270 |
spec %(specurl)s |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
271 |
</div>
|
272 |
<pre style="margin-top: 0px;">%(text)s</pre> |
|
273 |
<pre class="context">%(context)s</pre> |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
274 |
</li>"""
|
6912.5.8
by Curtis Hovey
Added documentation to xxxreport. |
275 |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
276 |
report_bottom = """ |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
277 |
</ol>
|
278 |
</body>
|
|
6912.5.8
by Curtis Hovey
Added documentation to xxxreport. |
279 |
</html>
|
280 |
"""
|
|
281 |
||
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
282 |
def write(self): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
283 |
"""Write the report in HTML format."""
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
284 |
report_time = time.strftime( |
285 |
"%a, %d %b %Y %H:%M:%S UTC", time.gmtime()) |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
286 |
output_file = self._open() |
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
287 |
try: |
288 |
output_file.write( |
|
289 |
self.report_top % {"commentcount": len(self.comments), |
|
290 |
"reporttime": report_time, |
|
291 |
"revno": self.revno}) |
|
292 |
||
293 |
for comment in self.comments: |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
294 |
comment['text'] = self.markupText(comment['text']) |
295 |
comment['context'] = self.markupText(comment['context']) |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
296 |
if comment['bug'] is not None: |
297 |
comment['bugurl'] = ( |
|
6912.5.13
by Curtis Hovey
Fixed spec links. |
298 |
'<a href="https://bugs.launchpad.net/bugs/%s">%s</a>' |
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
299 |
% (comment['bug'], comment['bug'])) |
300 |
else: |
|
301 |
comment['bugurl'] = comment['bug'] |
|
6912.5.13
by Curtis Hovey
Fixed spec links. |
302 |
if comment['spec'] is not None: |
303 |
comment['specurl'] = ( |
|
304 |
'<a href="https://blueprints.launchpad.net'
|
|
305 |
'/launchpad-project/+specs?searchtext=%s">%s</a>' |
|
306 |
% (comment['spec'], comment['spec'])) |
|
307 |
else: |
|
308 |
comment['specurl'] = comment['spec'] |
|
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
309 |
output_file.write(self.report_comment % comment) |
310 |
||
311 |
output_file.write(self.report_bottom) |
|
312 |
output_file.flush() |
|
313 |
finally: |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
314 |
self._close(output_file) |
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
315 |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
316 |
def markupText(self, text): |
6912.5.9
by Curtis Hovey
Moved the HTML report code into a single class. |
317 |
"""Return the line as HTML markup.
|
318 |
||
319 |
:param text: The text to escape and link.
|
|
320 |
"""
|
|
321 |
text = cgi.escape(text) |
|
322 |
text = self.http_re.sub(r'<a href="\1">\1</a>', text) |
|
323 |
bug_sub = r'<a href="https://bugs.launchpad.net/bugs/\2">\1 \2</a>' |
|
324 |
text = self.bug_link_re.sub(bug_sub, text) |
|
325 |
return text |
|
6912.5.8
by Curtis Hovey
Added documentation to xxxreport. |
326 |
|
327 |
||
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
328 |
class CSVReport(Report): |
329 |
"""A CSV XXX report."""
|
|
330 |
report_header = ( |
|
331 |
'File_Path, Line_No, Person, Date, Bug, Spec, Text\n') |
|
332 |
report_comment = ( |
|
333 |
'%(file_path)s, %(line_no)s, ' |
|
334 |
'%(person)s, %(date)s, %(bug)s, %(spec)s, %(text)s\n') |
|
335 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
336 |
def markupText(self, text): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
337 |
"""Return the line as TSV markup.
|
338 |
||
339 |
:param text: The text to escape.
|
|
340 |
"""
|
|
341 |
if text is not None: |
|
342 |
return text.replace('\n', ' ').replace(',', ';') |
|
343 |
||
344 |
def write(self): |
|
345 |
"""Write the report in CSV format."""
|
|
346 |
output_file = self._open() |
|
347 |
try: |
|
348 |
output_file.write(self.report_header) |
|
349 |
for comment in self.comments: |
|
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
350 |
comment['person'] = self.markupText(comment['person']) |
351 |
comment['text'] = self.markupText(comment['text']) |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
352 |
output_file.write(self.report_comment % comment) |
353 |
output_file.flush() |
|
354 |
finally: |
|
355 |
self._close(output_file) |
|
356 |
||
357 |
||
358 |
class TSVReport(CSVReport): |
|
359 |
"""A TSV XXX report."""
|
|
360 |
report_header = ( |
|
361 |
'File_Path\tLine_No\tPerson\tDate\tBug\tSpec\tText\n') |
|
362 |
report_comment = ( |
|
363 |
'%(file_path)s\t%(line_no)s\t' |
|
364 |
'%(person)s\t%(date)s\t%(bug)s\t%(spec)s\t%(text)s\n') |
|
365 |
||
6912.5.17
by Curtis Hovey
Revised the variable and method names. Simplified the extractComment loop. |
366 |
def markupText(self, text): |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
367 |
"""Return the line as TSV markup.
|
368 |
||
369 |
:param text: The text to escape.
|
|
370 |
"""
|
|
371 |
if text is not None: |
|
372 |
return text.replace('\n', ' ').replace('\t', ' ') |
|
373 |
||
374 |
||
375 |
def get_option_parser(): |
|
376 |
"""Return the option parser for this program."""
|
|
377 |
usage = dedent(""" %prog [options] <root-dir> |
|
378 |
||
379 |
Create a report of all the XXX comments in the files below a directory.
|
|
380 |
Set the -f option to 'count' to print the total number of XXX comments,
|
|
381 |
which is the default when -f is not set.""") |
|
382 |
parser = OptionParser(usage=usage) |
|
383 |
parser.add_option( |
|
384 |
"-f", "--format", dest="format", default="count", |
|
385 |
help="the format of the report: count, html, csv, tsv") |
|
386 |
parser.add_option( |
|
387 |
"-o", "--output", dest="output_name", |
|
388 |
help="the name of the output file, otherwise STDOUT is used") |
|
389 |
return parser |
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
390 |
|
391 |
||
392 |
def main(argv=None): |
|
393 |
"""Run the command line operations."""
|
|
394 |
if argv is None: |
|
395 |
argv = sys.argv |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
396 |
parser = get_option_parser() |
397 |
(options, arguments) = parser.parse_args(args=argv[1:]) |
|
6912.5.12
by Curtis Hovey
Revised Makefile rules for xxxreport. |
398 |
if len(arguments) != 1: |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
399 |
parser.error('No root directory was provided.') |
6912.5.12
by Curtis Hovey
Revised Makefile rules for xxxreport. |
400 |
root_dir = arguments[0] |
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
401 |
|
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
402 |
if options.format.lower() == 'html': |
403 |
report = HTMLReport(root_dir, options.output_name) |
|
404 |
elif options.format.lower() == 'tsv': |
|
405 |
report = TSVReport(root_dir, options.output_name) |
|
406 |
elif options.format.lower() == 'csv': |
|
407 |
report = CSVReport(root_dir, options.output_name) |
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
408 |
else: |
6912.5.12
by Curtis Hovey
Revised Makefile rules for xxxreport. |
409 |
report = Report(root_dir, options.output_name) |
6912.5.10
by Curtis Hovey
Added the optionsparser, moved several functions into the base Report class. |
410 |
report.write() |
411 |
sys.exit(0) |
|
6912.5.1
by Curtis Hovey
Initial addition of the XXX report from the old 3732 branch. |
412 |
|
413 |
||
414 |
if __name__ == '__main__': |
|
415 |
sys.exit(main()) |
|
416 |