Upload Tizen:Base source
[toolchains/python-lxml.git] / doc / mkhtml.py
1 from docstructure import SITE_STRUCTURE, HREF_MAP, BASENAME_MAP
2 from lxml.etree import (parse, fromstring, ElementTree,
3                         Element, SubElement, XPath)
4 import os, shutil, re, sys, copy, time
5
6 RST2HTML_OPTIONS = " ".join([
7     '--no-toc-backlinks',
8     '--strip-comments',
9     '--language en',
10     '--date',
11     ])
12
13 htmlnsmap = {"h" : "http://www.w3.org/1999/xhtml"}
14
15 find_title = XPath("/h:html/h:head/h:title/text()", namespaces=htmlnsmap)
16 find_title_tag = XPath("/h:html/h:head/h:title", namespaces=htmlnsmap)
17 find_headings = XPath("//h:h1[not(@class)]//text()", namespaces=htmlnsmap)
18 find_menu = XPath("//h:ul[@id=$name]", namespaces=htmlnsmap)
19 find_page_end = XPath("/h:html/h:body/h:div[last()]", namespaces=htmlnsmap)
20
21 find_words = re.compile('(\w+)').findall
22 replace_invalid = re.compile(r'[-_/.\s\\]').sub
23
24 def make_menu_section_head(section, menuroot):
25     section_id = section + '-section'
26     section_head = menuroot.xpath("//ul[@id=$section]/li", section=section_id)
27     if not section_head:
28         ul = SubElement(menuroot, "ul", id=section_id)
29         section_head = SubElement(ul, "li")
30         title = SubElement(section_head, "span", {"class":"section title"})
31         title.text = section
32     else:
33         section_head = section_head[0]
34     return section_head
35
36 def build_menu(tree, basename, section_head):
37     page_title = find_title(tree)
38     if page_title:
39         page_title = page_title[0]
40     else:
41         page_title = replace_invalid('', basename.capitalize())
42     build_menu_entry(page_title, basename+".html", section_head,
43                      headings=find_headings(tree))
44
45 def build_menu_entry(page_title, url, section_head, headings=None):
46     page_id = replace_invalid(' ', os.path.splitext(url)[0]) + '-menu'
47     ul = SubElement(section_head, "ul", {"class":"menu foreign", "id":page_id})
48
49     title = SubElement(ul, "li", {"class":"menu title"})
50     a = SubElement(title, "a", href=url)
51     a.text = page_title
52
53     if headings:
54         subul = SubElement(title, "ul", {"class":"submenu"})
55         for heading in headings:
56             li = SubElement(subul, "li", {"class":"menu item"})
57             ref = '-'.join(find_words(replace_invalid(' ', heading.lower())))
58             a  = SubElement(li, "a", href=url+'#'+ref)
59             a.text = heading
60
61 def merge_menu(tree, menu, name):
62     menu_root = copy.deepcopy(menu)
63     tree.getroot()[1][0].insert(0, menu_root) # html->body->div[class=document]
64     for el in menu_root.iter():
65         tag = el.tag
66         if tag[0] != '{':
67             el.tag = "{http://www.w3.org/1999/xhtml}" + tag
68     current_menu = find_menu(
69         menu_root, name=replace_invalid(' ', name + '-menu'))
70     if not current_menu:
71         current_menu = find_menu(
72             menu_root, name=replace_invalid('-', name + '-menu'))
73     if current_menu:
74         for submenu in current_menu:
75             submenu.set("class", submenu.get("class", "").
76                         replace("foreign", "current"))
77     return tree
78
79 def rest2html(script, source_path, dest_path, stylesheet_url):
80     command = ('%s %s %s --stylesheet=%s --link-stylesheet %s > %s' %
81                (sys.executable, script, RST2HTML_OPTIONS,
82                 stylesheet_url, source_path, dest_path))
83     os.system(command)
84
85 def publish(dirname, lxml_path, release):
86     if not os.path.exists(dirname):
87         os.mkdir(dirname)
88
89     doc_dir = os.path.join(lxml_path, 'doc')
90     script = os.path.join(doc_dir, 'rest2html.py')
91     pubkey = os.path.join(doc_dir, 'pubkey.asc')
92     stylesheet_url = 'style.css'
93
94     shutil.copy(pubkey, dirname)
95
96     href_map = HREF_MAP.copy()
97     changelog_basename = 'changes-%s' % release
98     href_map['Release Changelog'] = changelog_basename + '.html'
99
100     trees = {}
101     menu = Element("div", {"class":"sidemenu"})
102     # build HTML pages and parse them back
103     for section, text_files in SITE_STRUCTURE:
104         section_head = make_menu_section_head(section, menu)
105         for filename in text_files:
106             if filename.startswith('@'):
107                 # special menu entry
108                 page_title = filename[1:]
109                 url = href_map[page_title]
110                 build_menu_entry(page_title, url, section_head)
111             else:
112                 path = os.path.join(doc_dir, filename)
113                 basename = os.path.splitext(os.path.basename(filename))[0]
114                 basename = BASENAME_MAP.get(basename, basename)
115                 outname = basename + '.html'
116                 outpath = os.path.join(dirname, outname)
117
118                 rest2html(script, path, outpath, stylesheet_url)
119
120                 tree = parse(outpath)
121                 trees[filename] = (tree, basename, outpath)
122
123                 build_menu(tree, basename, section_head)
124
125     # also convert CHANGES.txt
126     rest2html(script,
127               os.path.join(lxml_path, 'CHANGES.txt'),
128               os.path.join(dirname, 'changes-%s.html' % release),
129               '')
130
131     # integrate menu
132     for tree, basename, outpath in trees.itervalues():
133         new_tree = merge_menu(tree, menu, basename)
134         title = find_title_tag(new_tree)
135         if title and title[0].text == 'lxml':
136             title[0].text = "lxml - Processing XML and HTML with Python"
137         new_tree.write(outpath)
138
139 if __name__ == '__main__':
140     publish(sys.argv[1], sys.argv[2], sys.argv[3])