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