page: added ability to encrypt linktargets
[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         for i in self._doc.xpath(u"//html:form[@action]",namespaces=const.XPATH):
106             pyscript = re.split('\.py',i.get('action'),1)[0]+'.py'
107             im = os.path.join(dirname,pyscript)
108             if os.path.isfile(im):
109                 self._resources.append(im)
110
111     def render(self, style):
112
113 #        xslt_root = etree.XML(open(style+"docbook.xsl", 'r').read())
114 #        transform = etree.XSLT(xslt_root)
115 #        result = etree.tostring(transform(xml_root))
116
117         cwd = os.getcwd()
118         dirname = os.path.dirname(self._file)
119         os.chdir(dirname)
120         infile  = os.path.basename(tempfile.mktemp())
121         outfile = tempfile.mktemp()
122         tfi = open(infile,'w')
123         tfi.write(etree.tostring(self._doc,encoding='UTF-8',pretty_print=False))
124         tfi.close()
125 #  cmd = ["saxon-xslt-xinclude","-o",outfile,infile,style_xslt]
126         cmd = ["xsltproc","--xinclude","--output",outfile,style+"docbook.xsl",infile]
127         retcode = subprocess.call(cmd)
128         if retcode:
129             print 'Error: '+' '.join(cmd)+' Returncode ['+str(retcode)+']'
130         tfo = open(outfile,'r')
131         self._rendered_article = tfo.read()
132         tfo.close()
133         os.remove(infile)
134         os.remove(outfile)
135         os.chdir(cwd)
136
137     def template(self,sitemap,style,tdir):
138         htmlmenu =  sitemap.gen_menu(self._lang,None,"menu")
139         levelmenu = sitemap.gen_menu(self._lang,self,"tree")
140         langmenu = sitemap.lang_menu(self._lang,self._link)
141         template = Template(file=style+'index.'+self._lang+'.html.tmpl',
142                             searchList=[{'title':self._title},
143                                         {'menu':htmlmenu},
144                                         {'article':self._rendered_article},
145                                         {'levelmenu':levelmenu},
146                                         {'langmenu':langmenu}])
147         outfile = tdir+'html'.join(self._file.rsplit('xml',1))
148         mkdir_p(os.path.dirname(outfile))
149         out = open(outfile, 'w')
150         out.write(str(template))
151         out.close()