0ecefe4278efae22c581d702bb7c513630e43700
[treecutter.git] / treecutter / sitemap.py
1 #!/usr/bin/python
2 import os
3 import codecs
4 import re
5 import shutil
6 import gettext
7 import tempfile
8 from lxml import etree
9 from lxml.builder import ElementMaker
10 from time import time
11 from treecutter import constants as const
12 from treecutter.trie import Trie
13 from treecutter.link import Link
14 from treecutter.tools import ssh_cmd, publish, mkdir_p
15
16 class Sitemap():
17     """Class keeping the internal site structure"""
18     def __init__(self,args):
19         self._output = args.output
20         self._style = args.style
21         self._subdir = args.subdir
22         self._file = 'sitemap.txt'
23         self._tree = Trie()
24         self._sitelang = set()
25         self._isocode = etree.parse('/usr/share/xml/iso-codes/iso_639_3.xml')
26         self._tranlang = {}
27         self._tmptarget = tempfile.mkdtemp()+'/'
28
29     # The sitemap uses a trie structure to keep track of links
30     # A link represents the path to the document and the link
31     # representing the text on the site.
32     # A link can have several pages in different languages.
33     def add_link(self, link):
34         tokens = filter(None,re.split(r'(^/[\w:-]*$|^/[\w:-]*/|[\w:-]*/)',link,flags=re.UNICODE))
35         self._tree.add(tokens,Link(link))
36
37     def write_map(self):
38         f = codecs.open(self._file,'w','utf-8')
39         s = '\n'.join(link.link() for link in self._tree)
40         f.write(s)
41         f.close()
42
43     def read_map(self):
44         try:
45             f = codecs.open(self._file, 'r', 'utf-8')
46             sml = f.read().split()
47             f.close()
48             for line in sml:
49                 self.add_link(line)
50         except IOError, what_error:
51             print 'INFO: Could not read sitemap.txt - one will be created'
52
53     # Create a set of the current tree for comparison with the
54     # directory scan
55     def set(self):
56         return set(link.link() for link in self._tree)
57
58     # Main driver in the application processing the documents
59     # in the collected sitemap
60     def process(self):
61         t1 = time()
62         print "Prepareing the input"
63         for link in self._tree:
64             link.prepare()
65         t2 = time()
66         print "Prepare  [%5.2f s]" % (round(t2-t1,2))
67         for link in self._tree:
68             self._sitelang = self._sitelang.union(set(link.languages()))
69         for tran in self._sitelang:
70             if tran != 'en':
71                 self._tranlang[tran] = gettext.translation('iso_639_3',
72                                                            languages=[tran])
73         t3 = time()
74         print "Language [%5.2f s]" % (round(t3-t2,2))
75         for link in self._tree:
76             link.render(self._style)
77         t4 = time()
78         print "Render   [%5.2f s]" % (round(t4-t3,2))
79         for link in self._tree:
80             link.template(self, self._style, self._tmptarget)
81         t5 = time()
82         print "Template [%5.2f s]" % (round(t5-t4,2))
83         t6 = time()
84         res = set()
85         # Collect all files used by the documents
86         for link in self._tree:
87             res = res.union(link.resources())
88         for f in res:
89             outfile = self._tmptarget+f
90             mkdir_p(os.path.dirname(outfile))
91             shutil.copyfile(f,outfile)
92         print "Resources[%5.2f s]" % (round(t6-t5,2))
93         # TODO: Improve the sitemap, it is a page that is generated from
94         #       the ground up and added a bit adhoc.
95         sitmaplink = Link('/sitemap')
96         for l in self._sitelang:
97             sitmaplink.add_page((l,'/sitemap.'+l+'.xml'))
98         for l in self._sitelang:
99             sitmaplink.page(l).set_article(self.gen_menu(l,None,"tree sitemap"))
100             sitmaplink.page(l).template(self,self._style,self._tmptarget)
101         t7 = time()
102         print "Sitemap  [%5.2f s]" % (round(t7-t6,2))
103
104     def graph(self):
105         self._tree.graph()
106
107     def gen_menu(self,lang,page,cssclass):
108         return self._tree.menu(lang,page,cssclass,self._subdir)
109
110     def lang_menu(self,lang,link):
111         html = ElementMaker()
112         menu = html.ul()
113         for l in link.languages():
114             isoxml = u"//iso_639_3_entry[@*='"+l+"']"
115             ln = self._isocode.xpath(isoxml)[0].get('name')
116             if lang != 'en':
117                 ln = self._tranlang[lang].gettext(ln)
118             p = unicode(link.link())
119             if p[-1] == u'/':
120                 p = p +u'index'
121             p = p+u'.'+l
122             li = html.li(html.a(ln.decode('utf-8'),
123                                 href=self._subdir+p,hreflang=l))
124             menu.append(li)
125         return etree.tostring(menu,encoding='UTF-8',pretty_print=False)
126
127     def publish(self):
128         ssh_cmd(self._output,"mkdir -p")
129         publish(self._tmptarget, self._output)
130         for res in ["css","images","js","fonts","favicon.ico"]:
131             if (os.path.exists(self._style+res)):
132                 publish(self._style+res, self._output)
133         ssh_cmd(self._output,"chmod a+rx")