Whitespace and indetation changes.
[treecutter.git] / src / tree-cutter.py
1 #!/usr/bin/python
2 import os
3 import fnmatch
4 import subprocess
5 import amara
6 import re
7 import tempfile
8 import errno
9 import time
10 import argparse
11 from amara import bindery
12 from amara.xslt import transform
13 from Cheetah.Template import Template
14
15 parser = argparse.ArgumentParser(description='Process docbook article tree.')
16 parser.add_argument('--style', nargs='?',
17                     default=os.path.dirname(os.getcwd())+'/style/default/')
18 parser.add_argument('--output', nargs='?',
19                     default=os.path.dirname(os.getcwd())+'/htdocs/')
20 args = parser.parse_args()
21
22 style_xslt = args.style+"docbook.xsl"
23 style_tmpl = args.style+"index.en.html.tmpl"
24 outputdir = args.output
25
26 valid_scripts = ['.py','.pl']
27 MAXLEVEL = 10000
28
29 def mkdir_p(path):
30     try:
31         os.makedirs(path)
32     except OSError as exc: # Python >2.5
33         if exc.errno == errno.EEXIST:
34             pass
35         else: raise
36
37 def generateSitemap():
38   sitemap = []
39   try:
40     sfile = open('sitemap.txt')
41     flist = sfile.read().split()
42     sfile.close()
43     for f in flist:
44       sitemap.append(dict(link=f))
45   except IOError, what_error:
46     print 'Sitemap missing - generating one.'
47   for dirname, dirnames, filenames in os.walk('.'):
48     for filename in filenames:
49       if fnmatch.fnmatch(filename, '*.xml'):
50         xfile = os.path.join(dirname,filename)
51         doc = bindery.parse(xfile,
52                             prefixes={u'db': u'http://docbook.org/ns/docbook',
53                                       u'xi': u'http://www.w3.org/2001/XInclude'})
54         title = doc.xml_select(u'/db:article/db:info/db:title')
55         menu  = doc.xml_select(u'/db:article/db:info/db:titleabbrev')
56         code  = doc.xml_select(u"//xi:include[@parse='text']")
57         exe = 0
58         for c in code:
59           (p, ext) = os.path.splitext(c.href)
60           if ext in valid_scripts:
61             exe = 1
62
63         if title and menu:
64           found = 0
65           base = xfile.split('.')[1]
66           link = base.replace('index','')
67           level = len(filter(None,re.split(r'(/\w*/)',link)))
68           page = dict(title=unicode(doc.article.info.title),
69                       menu=unicode(doc.article.info.titleabbrev),
70                       output=os.path.join(dirname,
71                                           filename.replace('xml','html')),
72                       exe=exe,
73                       file=xfile,
74                       level=level)
75           for l in sitemap:
76             if l['link'] == link:
77               found = 1
78               l.update(page)
79           if not found:
80             print "adding "+link+" to sitemap"
81             dd = dict(link=link)
82             dd.update(page)
83             sitemap.append(dd)
84   sfile = open('sitemap.txt','w')
85   for l in sitemap:
86     sfile.write(l['link']+'\n')
87   sfile.close()
88   return sitemap
89
90 def expandXincludeTxt(page):
91   doc = bindery.parse(page['file'],
92                       prefixes={u'db': u'http://docbook.org/ns/docbook',
93                                 u'xi': u'http://www.w3.org/2001/XInclude'})
94   if page['exe']:
95     code  = doc.xml_select(u"//xi:include[@parse='text']")
96     for c in code:
97       (p, ext) = os.path.splitext(c.href)
98       if ext in valid_scripts:
99         exe = os.path.join(os.path.abspath(c.href))
100         xml = subprocess.Popen([exe],stdout=subprocess.PIPE)
101         xstr = bindery.parse(str(xml.stdout.read()))
102         id = c.xml_index_on_parent
103         for x in xstr.xml_children:
104           c.xml_parent.xml_insert(id,x)
105         c.xml_parent.xml_remove(c)
106   return doc
107
108 def xsltConvert(doc):
109 #  amara can not handle the docbook stylesheets
110 #  xmlarticle = transform(doc,style_xslt)
111   cwd = os.getcwd()
112   rundir = os.path.dirname(page['file'])
113   os.chdir(rundir)
114   infile  = os.path.basename(tempfile.mktemp())
115   outfile = tempfile.mktemp()
116   tfi = open(infile,'w')
117   tfi.write(doc.xml_encode())
118   tfi.close()
119 #  cmd = ["saxon-xslt-xinclude","-o",outfile,infile,style_xslt]
120   cmd = ["xsltproc","--xinclude","--output",outfile,style_xslt,infile]
121   retcode = subprocess.call(cmd)
122   if retcode:
123     print 'Error: '+' '.join(cmd)+' Returncode ['+str(retcode)+']'
124   tfo = open(outfile,'r')
125   result = tfo.read()
126   tfo.close()
127   os.remove(infile)
128   os.remove(outfile)
129   os.chdir(cwd)
130   return result
131
132 def genMenu(page,sitemap,slevel,elevel):
133   title = None
134   sm = []
135   if elevel == MAXLEVEL or elevel == 1:
136     sm = sitemap
137   else:
138     idx = sitemap.index(page)
139     while (sitemap[idx]['level'] == page['level']):
140       idx = idx-1
141     title = sitemap[idx]['menu']
142     idx = idx+1
143     while (idx < len(sitemap) and sitemap[idx]['level'] == page['level']):
144       sm.append(sitemap[idx])
145       idx = idx+1
146   oldlevel = slevel
147   html = '<ul>\n'
148   for p in sm:
149     if slevel > p['level'] or elevel < p['level']:
150       continue
151     if not title and p['link'] == '/':
152       title = p['menu']
153
154     if oldlevel < p['level']:
155       html+='<ul>\n'
156     elif oldlevel > p['level']:
157       if p['link'][-1] == '/':
158         html+='</li>\n'
159       html+='</ul>\n</li>\n'
160     if page == p:
161       html+='<li><a href="%s">[%s]</a>' % (p['link'],p['menu'])
162     else:
163       html+='<li><a href="%s">%s</a>' % (p['link'],p['menu'])
164     if p['link'][-1] != '/' or p['link'] == '/':
165         html+='</li>\n'
166     oldlevel = p['level']
167   html+='</ul>\n'
168   return (html,title)
169
170 def writeToTemplate(page,doc,sitemap):
171   (menu,menuname) = genMenu(page,sitemap,1,MAXLEVEL)
172   (levelmenu,levelname) = genMenu(page,sitemap,page['level'],page['level'])
173   template = Template(file=style_tmpl,
174                       searchList=[{'menu':menu},
175                                   {'article':doc},
176                                   {'levelmenu':levelmenu},
177                                   {'levelname':levelname}])
178   outfile = outputdir+page['output']
179   d = os.path.split(outfile)[0]
180   if d != '':
181     mkdir_p(d)
182   out = open(outfile, 'w')
183   out.write(str(template))
184
185 sitemap = generateSitemap()
186 for page in sitemap:
187   t1 = time.time()
188   print "Page : "+page['link'],
189   doc = expandXincludeTxt(page)
190   pubdoc = xsltConvert(doc)
191   writeToTemplate(page,pubdoc,sitemap)
192 #  publishResources()
193   t2 = time.time()
194   print "["+str(round(t2-t1,2))+"]  done."