25 |
|
|
26 |
__docformat__ = 'reStructuredText' |
__docformat__ = 'reStructuredText' |
27 |
|
|
28 |
|
|
29 |
|
import os, string |
30 |
|
import docutils |
31 |
|
|
32 |
|
import config |
33 |
|
|
34 |
|
from navidoc.utils.path import * |
35 |
|
|
36 |
|
dbg = config.dbg.shorthand('pegboard') |
37 |
|
|
38 |
|
|
39 |
|
def pegcmp(a, b): |
40 |
|
""" |
41 |
|
Comparison function used when sorting pegs. |
42 |
|
Sorts pegs primarily in descending priority order of status |
43 |
|
and secondarily in descending time stamp. |
44 |
|
""" |
45 |
|
if priority.has_key(a['status'].capitalize().split()[0]) \ |
46 |
|
and priority.has_key(b['status'].capitalize().split()[0]) \ |
47 |
|
and not a['status'].lower().split() == b['status'].lower().split(): |
48 |
|
return priority[a['status'].capitalize().split()[0]] \ |
49 |
|
> priority[b['status'].capitalize().split()[0]] or -1 |
50 |
|
|
51 |
|
as = a['last-modified'].split('-') |
52 |
|
bs = b['last-modified'].split('-') |
53 |
|
if not len(as) == 3 or not len(bs) == 3: |
54 |
|
return len(as) < len(bs) or (len(bs) < len(as)) * -1 or 0 |
55 |
|
ac = int(as[0])*10000 + int(as[1])*100 + int(as[2]) |
56 |
|
bc = int(bs[0])*10000 + int(bs[1])*100 + int(bs[2]) |
57 |
|
return ac < bc or (ac > bc) * -1 or 0 |
58 |
|
|
59 |
|
def getTagValue(document, tagName, all=0, always_raw=0): |
60 |
|
""" |
61 |
|
Returns the value of the first occurrence, or all values of all of |
62 |
|
the occurrences of given tagName in docutils' document tree |
63 |
|
""" |
64 |
|
values = [] |
65 |
|
if document.tagname.lower() == tagName.lower(): |
66 |
|
if hasattr(document.children[0], 'data') and not always_raw: |
67 |
|
return document.children[0].data |
68 |
|
else: |
69 |
|
return document.rawsource |
70 |
|
if hasattr(document, 'children'): |
71 |
|
for child in document.children: |
72 |
|
value = getTagValue(child, tagName, all=all, always_raw=always_raw) |
73 |
|
if value and not all: |
74 |
|
return value |
75 |
|
elif value: |
76 |
|
if type(value) == type([]): |
77 |
|
values.extend(value) |
78 |
|
else: |
79 |
|
values.append(value) |
80 |
|
if len(values) > 0: |
81 |
|
return values |
82 |
|
else: |
83 |
|
return '' |
84 |
|
|
85 |
|
def getFieldTagValue(document, fieldName): |
86 |
|
""" |
87 |
|
Returns the value of the first occurrense of field tag with given |
88 |
|
field name. |
89 |
|
""" |
90 |
|
if document.tagname.lower() == 'field': |
91 |
|
if document.children[0].rawsource.lower() == fieldName.lower(): |
92 |
|
return document.children[1].rawsource |
93 |
|
if hasattr(document, 'children'): |
94 |
|
for child in document.children: |
95 |
|
value = getFieldTagValue(child, fieldName) |
96 |
|
if value: |
97 |
|
return value |
98 |
|
return '' |
99 |
|
|
100 |
|
def build_pegtable(): |
101 |
|
""" |
102 |
|
Search all subdirs of working directory for peg files and |
103 |
|
parses peg metadata from them. Returns the table containing |
104 |
|
metadata from all the pegs. |
105 |
|
""" |
106 |
|
|
107 |
|
pegtable = [] |
108 |
|
|
109 |
|
pegdirs = [d for d in os.listdir(_slashify(config.working_directory)) |
110 |
|
if os.path.isdir(_slashify(config.working_directory)+d) and d != 'CVS'] |
111 |
|
|
112 |
|
|
113 |
|
for pegdir in pegdirs: |
114 |
|
dbg('processing PEG ' + pegdir) |
115 |
|
|
116 |
|
peg = {'authors': [], 'status': undefined, 'topic': pegdir, 'stakeholders': [], |
117 |
|
'last-modified': '', 'dir': pegdir, 'files': '', 'html': '', 'rst': '', |
118 |
|
'rstfiles': [], 'cvsignore': [] } |
119 |
|
|
120 |
|
pegfiles = [f for f in os.listdir(pegroot+'/'+pegdir+'/') \ |
121 |
|
if os.path.isfile(pegroot+'/'+pegdir+'/'+f) and not f.startswith('.') |
122 |
|
and '#' not in f and '~' not in f] |
123 |
|
|
124 |
|
peg['files'] = pegfiles |
125 |
|
|
126 |
|
try: |
127 |
|
index = pegfiles.index('peg.rst') |
128 |
|
peg['rst'] = pegfiles[index] |
129 |
|
except ValueError: |
130 |
|
for pegfile in peg['files']: |
131 |
|
if pegfile.endswith('.rst'): |
132 |
|
peg['rst'] = pegfile |
133 |
|
|
134 |
|
rstfiles = [f for f in peg['files'] if f.endswith('.rst')] |
135 |
|
|
136 |
|
for rstfile in rstfiles: |
137 |
|
#creates and setups a new docutils.core.Publisher, which seems to be |
138 |
|
#easy interface to use docutils |
139 |
|
pub = Publisher() |
140 |
|
pub.set_reader('standalone', None, 'restructuredtext') |
141 |
|
pub.set_writer('html') |
142 |
|
file = pegroot+'/'+pegdir+'/'+rstfile[0:len(rstfile)-4] |
143 |
|
args = '-stg --stylesheet ../'+css+' %s.rst %s.gen.html' % (file,file) |
144 |
|
|
145 |
|
#saves using contexts for diagrams |
146 |
|
settings['context'] = pegroot+'/'+pegdir+'/'+rstfile |
147 |
|
umltool.set_transition_paths(settings['context']) |
148 |
|
pub.process_command_line(argv=args.split()) |
149 |
|
|
150 |
|
#conversion may fail because of bad restructuredtext |
151 |
|
try: |
152 |
|
pub.set_io() |
153 |
|
document = pub.reader.read(pub.source, pub.parser, pub.settings) |
154 |
|
pub.apply_transforms(document) |
155 |
|
output = pub.writer.write(document, pub.destination) |
156 |
|
peg['cvsignore'].append(rstfile[0:len(rstfile)-4]+'.gen.html') |
157 |
|
|
158 |
|
#conversion have succeeded so far, parsing peg's metadata |
159 |
|
#from its document tree |
160 |
|
if rstfile == peg['rst']: |
161 |
|
peg['html'] = rstfile[0:len(rstfile)-4]+'.gen.html' |
162 |
|
peg['topic'] = getTagValue(document, 'title', always_raw=1) |
163 |
|
peg['topic'] = peg['topic'] |
164 |
|
peg['last-modified'] = getFieldTagValue(document, 'last-modified') |
165 |
|
#we may have got 'rawsource', which needs some tidying |
166 |
|
if peg['last-modified'].startswith('$Date'): |
167 |
|
peg['last-modified'] = peg['last-modified'][7:len(peg['last-modified'])-11].replace('/', '-') |
168 |
|
peg['status'] = getTagValue(document, 'status') or undefined |
169 |
|
stakeholders = getFieldTagValue(document, 'stakeholder') |
170 |
|
if not stakeholders: |
171 |
|
stakeholders = getFieldTagValue(document, 'stakeholders') |
172 |
|
peg['stakeholders'] = [s.strip() for s in stakeholders.split(',')] |
173 |
|
peg['authors'] = getTagValue(document, 'author', all=1) |
174 |
|
else: |
175 |
|
status = getTagValue(document, 'status') |
176 |
|
if status: |
177 |
|
peg['rstfiles'].append({'filename': rstfile, 'status': status}) |
178 |
|
|
179 |
|
except: |
180 |
|
fails += 'PEG %s: Docutil raised an exception while converting %s. ' % (pegdir, rstfile) |
181 |
|
fails += 'Conversion failed and HTML not created.\n' |
182 |
|
|
183 |
|
if not peg['html']: |
184 |
|
for file in peg['files']: |
185 |
|
if file[len(file)-5:len(file)] == '.html': |
186 |
|
peg['html'] = file |
187 |
|
break |
188 |
|
elif file[len(file)-4:len(file)] in ('.rst', '.txt'): |
189 |
|
peg['html'] = file |
190 |
|
break |
191 |
|
|
192 |
|
#finally adds peg's metadata into pegtable |
193 |
|
pegtable.append(peg) |
194 |
|
|
195 |
|
|
196 |
|
#create the ``.. pegboard::`` directive |
197 |
|
|
198 |
|
|
199 |
def pegboard_directive(*args): |
def pegboard_directive(*args): |
200 |
|
|
201 |
|
pegtable = build_pegtable() |
202 |
pegtable.sort(pegcmp) |
pegtable.sort(pegcmp) |
203 |
|
|
204 |
## Python doesn't like this, as 'class' is reserved |
# Python doesn't like this, as 'class' is reserved |
205 |
# table = nodes.table(class='pegboard') |
# table = nodes.table(class='pegboard') |
|
|
|
206 |
table = nodes.table() |
table = nodes.table() |
207 |
table['class'] = 'pegboard' |
table['class'] = 'pegboard' |
208 |
tgroup = nodes.tgroup(cols=6) |
tgroup = nodes.tgroup(cols=6) |
257 |
status_emph |
status_emph |
258 |
] |
] |
259 |
|
|
260 |
## massive uglification here because cpython doesn't like |
# massive uglification here because cpython doesn't like |
261 |
## the use of the reserved word 'class'. ;-/. Gotta think of |
# the use of the reserved word 'class'. ;-/. Gotta think of |
262 |
## something cuter. |
# something cuter. |
263 |
#row += td(status, class='peg_status_field') |
#row += td(status, class='peg_status_field') |
264 |
#row += td(ref, class='peg_name_field') |
#row += td(ref, class='peg_name_field') |
265 |
#row += td(peg['topic'].split(':')[-1], class='peg_topic_field') |
#row += td(peg['topic'].split(':')[-1], class='peg_topic_field') |
266 |
#row += td(string.join(_authors, ', '), class='peg_authors_field') |
#row += td(string.join(_authors, ', '), class='peg_authors_field') |
267 |
#row += td(string.join(_stakeholders, ', '), class='peg_stakeholders_field') |
#row += td(string.join(_stakeholders, ', '), class='peg_stakeholders_field') |
268 |
temp = td(status) |
temp = td(status); temp['class'] = 'peg_status_field' |
|
temp['class'] = 'peg_status_field' |
|
269 |
row += temp |
row += temp |
270 |
|
|
271 |
temp = td(ref) |
temp = td(ref); temp['class'] = 'peg_name_field' |
|
temp['class'] = 'peg_name_field' |
|
272 |
row += temp |
row += temp |
273 |
|
|
274 |
temp = td(peg['topic'].split(':')[-1]) |
temp = td(peg['topic'].split(':')[-1]); temp['class'] = 'peg_topic_field' |
|
temp['class'] = 'peg_topic_field' |
|
275 |
row += temp |
row += temp |
276 |
|
|
277 |
temp = td(string.join(_authors, ', ')) |
temp = td(string.join(_authors, ', ')); temp['class'] = 'peg_authors_field' |
|
temp['class'] = 'peg_authors_field' |
|
278 |
row += temp |
row += temp |
279 |
|
|
280 |
temp = td(string.join(_stakeholders, ', ')) |
temp = td(string.join(_stakeholders, ', ')); temp['class'] = 'peg_stakeholders_field' |
|
temp['class'] = 'peg_stakeholders_field' |
|
281 |
row += temp |
row += temp |
282 |
|
|
283 |
row += make_files(peg) |
row += make_files(peg) |
284 |
|
|
285 |
return [table] |
return [table] |
286 |
|
|
287 |
|
def td(__node, **args): |
288 |
|
entry = nodes.entry(**args) |
289 |
|
para = nodes.paragraph() |
290 |
|
entry += para |
291 |
|
|
292 |
|
if isinstance(__node, type('')): |
293 |
|
str = __node |
294 |
|
#mark literates |
295 |
|
if str.count('``')%2 == 0: |
296 |
|
for i in range(str.count('``')/2): |
297 |
|
if str.find('``') != 0: |
298 |
|
para += nodes.Text(str[0:str.find('``')]) |
299 |
|
str = str[str.find('``')+2:len(str)] |
300 |
|
literal = nodes.literal(para, nodes.Text(str[0:str.find('``')])) |
301 |
|
para += literal |
302 |
|
str = str[str.find('``')+2:len(str)] |
303 |
|
__node = nodes.Text(str) |
304 |
|
|
305 |
|
para += __node |
306 |
|
return entry |
307 |
|
|
308 |
|
|
309 |
|
def make_files(peg): |
310 |
|
# again, cpython and 'class' |
311 |
|
# list = nodes.bullet_list(class="plain") |
312 |
|
list = nodes.bullet_list() |
313 |
|
list['class'] = 'plain' |
314 |
|
|
315 |
|
# entry = nodes.entry(class='peg_files_field') |
316 |
|
entry = nodes.entry() |
317 |
|
entry['class'] = 'peg_files_field' |
318 |
|
|
319 |
|
entry += list |
320 |
|
|
321 |
|
for file in peg['files']: |
322 |
|
try: |
323 |
|
if peg['cvsignore'].index(file): |
324 |
|
pass |
325 |
|
except ValueError: |
326 |
|
converted = 0 |
327 |
|
status = 0 |
328 |
|
if file != peg['rst']: |
329 |
|
for rstfile in peg['rstfiles']: |
330 |
|
if rstfile['filename'] == file: |
331 |
|
status = rstfile['status'] |
332 |
|
for htmlfile in peg['cvsignore']: |
333 |
|
if htmlfile == file[0:len(file)-4]+'.html': |
334 |
|
converted = htmlfile |
335 |
|
if converted: |
336 |
|
href = peg['dir'] + '/' + converted |
337 |
|
|
338 |
|
ref = nodes.reference(anonymous=1, refuri=href) |
339 |
|
if status: |
340 |
|
klass = 'peg-'+status.split()[0].lower() |
341 |
|
#ref = nodes.reference(anonymous=1, class=klass, refuri=href) |
342 |
|
ref['class'] = klass |
343 |
|
|
344 |
|
text = nodes.Text(converted) |
345 |
|
|
346 |
|
ref += text |
347 |
|
listitem = nodes.list_item(list, ref) |
348 |
|
list += listitem |
349 |
|
else: |
350 |
|
href = peg['dir'] + '/' + file |
351 |
|
ref = nodes.reference(anonymous=1, refuri=href) |
352 |
|
text = nodes.Text(file) |
353 |
|
|
354 |
|
ref += text |
355 |
|
listitem = nodes.list_item(list, ref) |
356 |
|
list += listitem |
357 |
|
return entry |
358 |
|
|
359 |
|
pegboard_directive.arguments = () |
360 |
|
pegboard_directive.options = {} |
361 |
|
pegboard_directive.content = 0 |