12 import pygraphviz as pgv
13 from amara import bindery
14 from amara.xslt import transform
15 from Cheetah.Template import Template
17 parser = argparse.ArgumentParser(description='Process docbook article tree.')
18 parser.add_argument('--style', nargs='?',
19 default=os.path.dirname(os.getcwd())+'/style/default/')
20 parser.add_argument('--output', nargs='?',
21 default=os.path.dirname(os.getcwd())+'/htdocs/')
22 args = parser.parse_args()
24 style_xslt = args.style+"docbook.xsl"
25 style_tmpl = args.style+"index.en.html.tmpl"
26 outputdir = args.output
28 valid_scripts = ['.py','.pl']
34 except OSError as exc: # Python >2.5
35 if exc.errno == errno.EEXIST:
39 def publish(src,target):
40 cmd = ["rsync","-a","--delete",src,target]
41 retcode = subprocess.call(cmd)
43 print 'Error: '+' '.join(cmd)+' Returncode ['+str(retcode)+']'
46 PREFIXES={u'db': u'http://docbook.org/ns/docbook',
47 u'xi': u'http://www.w3.org/2001/XInclude',
48 u'xl': u'http://www.w3.org/1999/xlink'}
51 """Class containing the state of the directory with articles"""
57 for dirname, dirnames, filenames in os.walk(self._cwd):
58 for filename in filenames:
59 if fnmatch.fnmatch(filename, '*.xml'):
60 file_ = os.path.join(dirname,filename)
61 doc = bindery.parse(file_, prefixes=PREFIXES)
62 title = doc.xml_select(u'/db:article/db:info/db:title')
63 menu = doc.xml_select(u'/db:article/db:info/db:titleabbrev')
65 base = file_.split('.')[1]
66 link = base.replace('index','')
67 self._tree.append(link)
70 return set(self._tree)
73 """Class representing a webpage on the site"""
74 def __init__(self,link):
83 def __init__(self,token,value):
101 def _add(self,trie, key, content):
105 node = Node(k,content)
110 self._add(ch.children(), key, content)
112 def add(self,key, content):
113 self._add(self._root, key, content)
115 def _graph(self, trie, G):
117 G.add_node(l.token())
118 for ch in l.children():
119 G.add_edge(l.token(),ch.token())
120 self._graph(l.children(), G)
123 G = pgv.AGraph(directed=True)
124 G.add_node("sitemap")
125 for ch in self._root:
126 G.add_edge("sitemap",ch.token())
127 self._graph(self._root, G)
133 """Class keeping the internal site structure"""
135 self._file = 'sitemap.txt'
139 def add_page(self, link):
141 self._pages.append(page)
142 tokens = filter(None,re.split(r'(^/\w*/|\w*/)',link))
143 self._tree.add(tokens,page)
148 sml = f.read().split()
152 except IOError, what_error:
153 print 'INFO: Could not read sitemap.txt - one will be created'
156 return set(page.link() for page in self._pages)
164 def generateSitemap():
167 sfile = open('sitemap.txt')
168 flist = sfile.read().split()
171 sitemap.append(dict(link=f))
172 except IOError, what_error:
173 print 'Sitemap missing - generating one.'
175 for dirname, dirnames, filenames in os.walk('.'):
176 for filename in filenames:
177 if fnmatch.fnmatch(filename, '*.xml'):
178 xfile = os.path.join(dirname,filename)
179 doc = bindery.parse(xfile,
180 prefixes={u'db': u'http://docbook.org/ns/docbook',
181 u'xi': u'http://www.w3.org/2001/XInclude',
182 u'xl': u'http://www.w3.org/1999/xlink'})
183 title = doc.xml_select(u'/db:article/db:info/db:title')
184 menu = doc.xml_select(u'/db:article/db:info/db:titleabbrev')
185 code = doc.xml_select(u"//xi:include[@parse='text']")
186 resource = doc.xml_select(u"//db:link[@xl:href]")
187 image = doc.xml_select(u"//db:imagedata[@fileref]")
190 (p, ext) = os.path.splitext(c.href)
191 if ext in valid_scripts:
196 base = xfile.split('.')[1]
197 link = base.replace('index','')
198 level = len(filter(None,re.split(r'(^/\w*/|\w*/)',link)))
201 rf = os.path.join(dirname,r.href)
202 if os.path.isfile(rf):
205 im = os.path.join(dirname,i.fileref)
206 if os.path.isfile(im):
208 page = dict(title=unicode(doc.article.info.title),
209 menu=unicode(doc.article.info.titleabbrev),
210 output=os.path.join(dirname,
211 filename.replace('xml','html')),
217 if l['link'] == link:
221 print "adding "+link+" to sitemap"
225 sfile = open('sitemap.txt','w')
227 sfile.write(l['link']+'\n')
231 def expandXincludeTxt(page):
232 doc = bindery.parse(page['file'],
233 prefixes={u'db': u'http://docbook.org/ns/docbook',
234 u'xi': u'http://www.w3.org/2001/XInclude'})
236 code = doc.xml_select(u"//xi:include[@parse='text']")
238 (p, ext) = os.path.splitext(c.href)
239 if ext in valid_scripts:
240 exe = os.path.join(os.path.abspath(c.href))
241 xml = subprocess.Popen([exe],stdout=subprocess.PIPE)
242 xstr = bindery.parse(str(xml.stdout.read()))
243 id = c.xml_index_on_parent
244 for x in xstr.xml_children:
245 c.xml_parent.xml_insert(id,x)
246 c.xml_parent.xml_remove(c)
249 def xsltConvert(doc):
250 # amara can not handle the docbook stylesheets
251 # xmlarticle = transform(doc,style_xslt)
253 rundir = os.path.dirname(page['file'])
255 infile = os.path.basename(tempfile.mktemp())
256 outfile = tempfile.mktemp()
257 tfi = open(infile,'w')
258 tfi.write(doc.xml_encode())
260 # cmd = ["saxon-xslt-xinclude","-o",outfile,infile,style_xslt]
261 cmd = ["xsltproc","--xinclude","--output",outfile,style_xslt,infile]
262 retcode = subprocess.call(cmd)
264 print 'Error: '+' '.join(cmd)+' Returncode ['+str(retcode)+']'
265 tfo = open(outfile,'r')
273 def genMenu(page,sitemap,slevel,elevel):
276 if elevel == MAXLEVEL or elevel == 1 or page == None:
280 html = '<ul class="tree">\n'
281 idx = sitemap.index(page)
282 while (sitemap[idx]['level'] == page['level']):
284 title = sitemap[idx]['menu']
286 while (idx < len(sitemap) and sitemap[idx]['level'] == page['level']):
287 sm.append(sitemap[idx])
292 if slevel > p['level'] or elevel < p['level']:
294 if not title and p['link'] == '/':
297 if oldlevel < p['level']:
299 elif oldlevel > p['level']:
300 if p['link'][-1] == '/':
302 html+='</ul>\n</li>\n'
303 if page != None and page == p:
304 html+='<li class="selected"><a href="%s">%s</a>' % (p['link'],p['menu'])
306 html+='<li><a href="%s">%s</a>' % (p['link'],p['menu'])
307 if p['link'][-1] != '/' or p['link'] == '/':
309 oldlevel = p['level']
313 def writeToTemplate(page,doc,sitemap):
314 (menu,menuname) = genMenu(page,sitemap,1,MAXLEVEL)
315 (levelmenu,levelname) = genMenu(page,sitemap,page['level'],page['level'])
316 template = Template(file=style_tmpl,
317 searchList=[{'title':page['title']},
320 {'levelmenu':levelmenu},
321 {'levelname':levelname}])
322 outfile = tmptarget+page['output']
323 mkdir_p(os.path.dirname(outfile))
324 out = open(outfile, 'w')
325 out.write(str(template))
327 for r in page['res']:
328 mkdir_p(os.path.dirname(tmptarget+r))
329 shutil.copyfile(r, tmptarget+r)
331 def createSitemap(sitemap):
332 (menu,menuname) = genMenu(None,sitemap,1,MAXLEVEL)
333 template = Template(file=style_tmpl,
340 outfile = tmptarget+'sitemap.en.html'
341 mkdir_p(os.path.dirname(outfile))
342 out = open(outfile, 'w')
343 out.write(str(template))
352 missing = dir_.set() - sitemap.set()
353 removed = sitemap.set() - dir_.set()
355 print removed+' pages missing!!'
358 print 'adding missing page '+page
359 sitemap.add_page(page)
364 sitemap = generateSitemap()
365 tmptarget = tempfile.mkdtemp()+'/'
368 print "Page : %-30s %30s" % (page['link'],
369 time.ctime(os.stat(page['file']).st_mtime)),
370 doc = expandXincludeTxt(page)
371 pubdoc = xsltConvert(doc)
372 writeToTemplate(page,pubdoc,sitemap)
374 print "[%5.2f s]" % (round(t2-t1,2))
376 createSitemap(sitemap)
377 publish(tmptarget, args.output)
378 publish(args.style+"css", args.output)
379 publish(args.style+"images",args.output)