page: added a warning for missing resources
[treecutter.git] / treecutter / page.py
1 #!/usr/bin/python
2 import os
3 import subprocess
4 import tempfile
5 import re
6 import getpass
7 import gnupg
8 from lxml import etree
9 from Cheetah.Template import Template
10 from pkg_resources import resource_filename, resource_listdir
11 from time import time
12 import treecutter.constants as const
13 from treecutter.tools import mkdir_p
14
15 class Page():
16     """Class representing a version of a webpage"""
17     def __init__(self,link,page):
18         self._link = link
19         self._file = page[1]
20         self._lang = page[0]
21         self._doc = None
22         self._resources = []
23         self._title = None
24         self._menu = None
25         self._rendered_article = None
26
27     def language(self):
28         return self._lang
29
30     def resources(self):
31         return set(self._resources)
32
33     def menu(self):
34         return self._menu
35
36     def set_article(self,art):
37         self._rendered_article = art
38
39     def prepare(self):
40         self._doc = etree.parse(self._file)
41         t = self._doc.xpath(u'/db:article/db:info/db:title',namespaces=const.XPATH)
42         if t:
43             self._title = unicode(t[0].text)
44         ta = self._doc.xpath(u'/db:article/db:info/db:titleabbrev',namespaces=const.XPATH)
45         if ta:
46             self._menu = unicode(ta[0].text)
47
48         dirname = os.path.dirname(self._file)
49         cwd = os.getcwd()
50         code  = self._doc.xpath(u"//xi:include[@parse='text']",namespaces=const.XPATH)
51         if code:
52             for c in code:
53                 href = c.get('href')
54                 alang = c.get('accept-language')
55                 xpointer = c.get('xpointer')
56                 (p, ext) = os.path.splitext(href)
57                 if ext in const.valid_scripts:
58                     exe = []
59                     script = os.path.join(os.path.abspath(dirname)+'/'+href)
60                     if os.path.isfile(script):
61                         exe.append(script)
62                     else:
63                         if href in resource_listdir('xinclude', ''):
64                             script = resource_filename('xinclude', href)
65                             exe.append(script)
66                         else:
67                             print "Script "+href+" in "+self._file+" missing"
68                     if alang:
69                         exe.append("lang="+alang)
70                     if xpointer:
71                         exe.append("xptr="+xpointer)
72                     print "  executing %15s" % (href),
73                     ts = time()
74                     os.chdir(dirname)
75                     xml = subprocess.Popen(exe,stdout=subprocess.PIPE,
76                                            stderr=subprocess.PIPE)
77                     (stdout, stderr) = xml.communicate()
78                     if stderr:
79                         print " ".join(exe)+" ERROR : [ "+stderr+" ]"
80                     os.chdir(cwd)
81                     te = time()
82                     print " [%5.2f s]  (%s)" % (round(te-ts,2),xpointer)
83                     xstr = etree.fromstring(stdout)
84 # inserting the generated code and remove the xinclude reference
85                     idp = c.getparent()
86                     idp.insert(idp.index(c)+1,xstr)
87                     idp.remove(c)
88
89         for r in self._doc.xpath(u"//db:link[@xlink:href]",namespaces=const.XPATH):
90             rf = os.path.join(dirname,r.get(const.XLINK+'href'))
91             if os.path.isfile(rf):
92                 if r.get('security')=='encrypt':
93                     with open(rf, 'rb') as f:
94                         gpg = gnupg.GPG()
95                         status = gpg.encrypt_file(
96                         f, None, passphrase=getpass.getpass(rf+' password:'), symmetric=True,
97                         output=rf+'.gpg')
98                     r.set(const.XLINK+'href', r.get(const.XLINK+'href')+'.gpg')
99                     rf=rf+'.gpg'
100                 self._resources.append(rf)
101         for i in self._doc.xpath(u"//db:imagedata[@fileref]",namespaces=const.XPATH):
102             im = os.path.join(dirname,i.get('fileref'))
103             if os.path.isfile(im):
104                 self._resources.append(im)
105             else:
106                 print "WARNING: File "+im+" is missing!"
107         for i in self._doc.xpath(u"//html:form[@action]",namespaces=const.XPATH):
108             pyscript = re.split('\.py',i.get('action'),1)[0]+'.py'
109             im = os.path.join(dirname,pyscript)
110             if os.path.isfile(im):
111                 self._resources.append(im)
112
113     def render(self, style):
114
115 #        xslt_root = etree.XML(open(style+"docbook.xsl", 'r').read())
116 #        transform = etree.XSLT(xslt_root)
117 #        result = etree.tostring(transform(xml_root))
118
119         cwd = os.getcwd()
120         dirname = os.path.dirname(self._file)
121         os.chdir(dirname)
122         infile  = os.path.basename(tempfile.mktemp())
123         outfile = tempfile.mktemp()
124         tfi = open(infile,'w')
125         tfi.write(etree.tostring(self._doc,encoding='UTF-8',pretty_print=False))
126         tfi.close()
127 #  cmd = ["saxon-xslt-xinclude","-o",outfile,infile,style_xslt]
128         cmd = ["xsltproc","--xinclude","--output",outfile,style+"docbook.xsl",infile]
129         retcode = subprocess.call(cmd)
130         if retcode:
131             print 'Error: '+' '.join(cmd)+' Returncode ['+str(retcode)+']'
132         tfo = open(outfile,'r')
133         self._rendered_article = tfo.read()
134         tfo.close()
135         os.remove(infile)
136         os.remove(outfile)
137         os.chdir(cwd)
138
139     def template(self,sitemap,style,tdir):
140         htmlmenu =  sitemap.gen_menu(self._lang,None,"menu")
141         levelmenu = sitemap.gen_menu(self._lang,self,"tree")
142         langmenu = sitemap.lang_menu(self._lang,self._link)
143         template = Template(file=style+'index.'+self._lang+'.html.tmpl',
144                             searchList=[{'title':self._title},
145                                         {'menu':htmlmenu},
146                                         {'article':self._rendered_article},
147                                         {'levelmenu':levelmenu},
148                                         {'langmenu':langmenu}])
149         outfile = tdir+'html'.join(self._file.rsplit('xml',1))
150         mkdir_p(os.path.dirname(outfile))
151         out = open(outfile, 'w')
152         out.write(str(template))
153         out.close()