blob: 396769df581e993938629ffe5249a195ea22e5e2 [file] [log] [blame]
Gina Diminoee0fa6b2016-04-04 17:30:54 -07001"""
2Utility for building the CDD from component markdown files.
3
4From the compatibility/cdd directory, run python make-cdd.py.
5
6Each generated CDD file is marked with a hash based on the content of the input files.
7
8TODO(gdimino): Clean up and comment this code.
9"""
10
11from bs4 import BeautifulSoup
12import hashlib
13import markdown
14import os
15import pprint
16import re
17import tidylib
18import subprocess
19
20# TODO (gdimino): Clean up this code using templates
21# from jinja2 import Template
22
23HEADERS_FOR_TOC = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
24ANDROID_VERSION = "7.0, (N)"
25TOC_PER_COL = 34
26
27def get_section_info(my_path):
28 # (_, _, filenames) = os.walk(my_path).next()
29 section_info = [];
30 # Get section info from every file whose name contains a number. TODO: fix
31 # this ugly hack.
32 # for rootdir, subdirs, files in os.walk(my_path):
33 for dir in get_immediate_subdirs(my_path):
34 # for dir in subdirs:
35 if (not dir.isalpha() and dir != 'older-versions'):
36 child_data = []
37 print 'dir = ' + dir
38 for file in os.listdir(dir):
39 if '.md' in file:
40 if file == 'index.md':
41 number = 0
42 else:
43 number = int((file.split('_')[1]))
44 print 'file = ' + file + ', dir = ' + dir
45 html_string = markdown.markdown(unicode(open(my_path + '/' + dir + '/' + file, 'r').read(), 'utf-8'))
46 child_data.append({'file': file,
47 'number': number,
48 'title': dir.split('_')[-1],
49 'html': html_string,
50 'children':[]})
51 child_data.sort(key=lambda child: child['number'])
52 section_info.append({'id': dir,
53 'number': int(''.join((dir.split('_')[:-1])).replace("_", ".")),
54 'title': dir.split('_')[-1],
55 'html': '',
56 'children':child_data})
57 section_info.sort(key=lambda section: section['number'])
58 return section_info
59
60
61def get_soup(section_info):
62 html_body_text = '''<!DOCTYPE html>
63<head>
64<title>Android ''' + ANDROID_VERSION + ''' Compatibility Definition</title>
65<link rel="stylesheet" type="text/css" href="source/android-cdd.css"/>
66</head>
67<body>
68<div id="main">'''
69
70 for section in section_info:
71 for child in section['children']:
72 html_body_text += child['html']
73 html_body_text += '</div></body><html>'
74 return BeautifulSoup(html_body_text)
75
76
77def add_id_to_section_headers(soup):
78 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
79 for tag in soup.find_all(header_tags):
80 tag['id'] = create_id(tag)
81
82def old_generate_toc(soup):
83 toc_html = ''
84 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
85 for tag in soup.find_all(header_tags):
86 tag_html = '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
87 toc_html = toc_html + tag_html
88 return (BeautifulSoup(toc_html).body.contents, '')
89
90def generate_toc(soup):
91 toc_html = '<div id="toc">'
92 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
93 toc_entries = soup.find_all(header_tags)
94 toc_chunks = [toc_entries[i:i + TOC_PER_COL] for i in xrange(0, len(toc_entries), TOC_PER_COL)]
95 print 'Number of chunks = %d' % len(toc_chunks)
96 for chunk in toc_chunks:
97 if not toc_chunks.index(chunk) %2:
98 toc_html = toc_html + ('<div id="toc_left">')
99 for tag in chunk:
100 toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
101 toc_html = toc_html + ('</div>')
102 else:
103 toc_html = toc_html + ('<div id="toc_right">')
104 for tag in chunk:
105 toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
106 toc_html = toc_html + ('</div>')
107 toc_html = toc_html + '<div style="clear: both; page-break-after:always; height:1px"></div>'
108 toc_html = toc_html + '<div style="clear: both"></div>'
109 return (BeautifulSoup(toc_html).body.contents)
110
111def old_add_toc(soup):
112 toc = soup.new_tag('div', id='toc')
113 toc_left = soup.new_tag('div', id='toc_left')
114 toc_right = soup.new_tag('div', id='toc_right')
115 toc.append(toc_left)
116 toc.append(toc_right)
117 # toc_left.contents, toc_right.contents = generate_toc(soup)
118 toc_left.contents, toc_right.contents = generate_toc(soup)
119 toc_title = BeautifulSoup("<h6>Table of Contents</h6>").body.contents[0]
120 soup.body.insert(0,toc)
121 soup.body.insert(0, toc_title)
122 return soup
123
124def add_toc(soup):
125 toc_contents = generate_toc(soup)[0]
126 toc_title = BeautifulSoup("<h6>Table of Contents</h6>").body.contents[0]
127 soup.body.insert(0, toc_contents)
128 soup.body.insert(0, toc_title)
129 return soup
130
131def create_id(header_tag):
132 return header_tag.contents[0].lower().replace('. ', '_').replace(' ', '_').replace('.', '_')
133
134# Utilities
135def get_immediate_subdirs(dir):
136 return [name for name in os.listdir(dir)
137 if os.path.isdir(os.path.join(dir, name))]
138
139# Odds and ends
140
141def check_section_numbering(soup):
142 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
143 for tag in header_tags:
144 headings = soup.find_all(tag)
145 header_numbers = []
146 for heading in headings:
147 header_numbers.append(re.sub(r"([\d.]*).*", r"\1"), heading.contents)
148 return true
149
150def elim_para_whitespace(html):
151 new_html = re.sub(re.compile(r"(<p[^>]*>)\s*\n\s*(<a[^>]*>)\n([^<]*)\n\s*(</a>)\n\s*(</p>)", re.M),r"\1\2\3\4\5\n", html)
152 return new_html
153
154def main():
155 my_path = os.getcwd()
156 section_info = get_section_info(my_path)
157 soup = get_soup(section_info)
158 add_id_to_section_headers(soup)
159 add_toc(soup)
160 html = soup.prettify(formatter='html')
161 # Add a hash to the filename, so that identidal inputs produce the same output
162 # file.
163 output_filename = "test-generated-cdd-%s.html" % hashlib.md5(html).hexdigest()[0:5]
164 output = open(output_filename, "w")
165 output.write(html.encode('utf-8'))
166 output.close()
167 # Code to generate PDF, needs work.
168 # subprocess.call('wkhtmltopdf -B 1in -T 1in -L .75in -R .75in page ' + output_filename + ' --footer-html source/android-cdd-footer.html /tmp/android-cdd-body.pdf')
169
170
171if __name__ == '__main__':
172 main()
173
174
175
176