blob: c51821e14662360488e201874a19a396b16b4c2a [file] [log] [blame]
Glenn Kasten31ae5a12016-08-08 09:39:52 -07001#!/usr/bin/python
Gina Diminoee0fa6b2016-04-04 17:30:54 -07002"""
3Utility for building the CDD from component markdown files.
4
Gina Dimino8f4279b2017-01-11 16:18:39 -08005From the compatibility/cdd directory, run:
6python make-cdd.py --version <version number> --branch <AOSP branch>
7 --output <output file name>
Gina Diminoee0fa6b2016-04-04 17:30:54 -07008
Gina Diminoee0fa6b2016-04-04 17:30:54 -07009
10TODO(gdimino): Clean up and comment this code.
11"""
12
13from bs4 import BeautifulSoup
Gina Dimino8f4279b2017-01-11 16:18:39 -080014import argparse
Gina Diminoee0fa6b2016-04-04 17:30:54 -070015import hashlib
16import markdown
17import os
18import pprint
19import re
20import tidylib
21import subprocess
22
23# TODO (gdimino): Clean up this code using templates
24# from jinja2 import Template
25
26HEADERS_FOR_TOC = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
Gina Diminoee0fa6b2016-04-04 17:30:54 -070027TOC_PER_COL = 34
28
29def get_section_info(my_path):
30 # (_, _, filenames) = os.walk(my_path).next()
31 section_info = [];
32 # Get section info from every file whose name contains a number. TODO: fix
33 # this ugly hack.
34 # for rootdir, subdirs, files in os.walk(my_path):
35 for dir in get_immediate_subdirs(my_path):
36 # for dir in subdirs:
Gina Dimino2cf721f2016-06-27 12:45:01 -070037 if (not dir.isalpha() and dir != 'older-versions' and dir != '.git'):
Gina Diminoee0fa6b2016-04-04 17:30:54 -070038 child_data = []
39 print 'dir = ' + dir
40 for file in os.listdir(dir):
41 if '.md' in file:
42 if file == 'index.md':
43 number = 0
44 else:
45 number = int((file.split('_')[1]))
46 print 'file = ' + file + ', dir = ' + dir
47 html_string = markdown.markdown(unicode(open(my_path + '/' + dir + '/' + file, 'r').read(), 'utf-8'))
48 child_data.append({'file': file,
49 'number': number,
50 'title': dir.split('_')[-1],
51 'html': html_string,
52 'children':[]})
53 child_data.sort(key=lambda child: child['number'])
54 section_info.append({'id': dir,
55 'number': int(''.join((dir.split('_')[:-1])).replace("_", ".")),
56 'title': dir.split('_')[-1],
57 'html': '',
58 'children':child_data})
59 section_info.sort(key=lambda section: section['number'])
60 return section_info
61
62
63def get_soup(section_info):
64 html_body_text = '''<!DOCTYPE html>
65<head>
Gina Dimino8f4279b2017-01-11 16:18:39 -080066<title>Android ANDROID_VERSION Compatibility Definition</title>
Gina Diminoee0fa6b2016-04-04 17:30:54 -070067<link rel="stylesheet" type="text/css" href="source/android-cdd.css"/>
68</head>
69<body>
70<div id="main">'''
71
72 for section in section_info:
73 for child in section['children']:
74 html_body_text += child['html']
75 html_body_text += '</div></body><html>'
76 return BeautifulSoup(html_body_text)
77
78
79def add_id_to_section_headers(soup):
80 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
81 for tag in soup.find_all(header_tags):
82 tag['id'] = create_id(tag)
83
Gina Diminoee0fa6b2016-04-04 17:30:54 -070084def generate_toc(soup):
85 toc_html = '<div id="toc">'
86 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
87 toc_entries = soup.find_all(header_tags)
88 toc_chunks = [toc_entries[i:i + TOC_PER_COL] for i in xrange(0, len(toc_entries), TOC_PER_COL)]
89 print 'Number of chunks = %d' % len(toc_chunks)
90 for chunk in toc_chunks:
91 if not toc_chunks.index(chunk) %2:
92 toc_html = toc_html + ('<div id="toc_left">')
93 for tag in chunk:
94 toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
95 toc_html = toc_html + ('</div>')
96 else:
97 toc_html = toc_html + ('<div id="toc_right">')
98 for tag in chunk:
99 toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
100 toc_html = toc_html + ('</div>')
101 toc_html = toc_html + '<div style="clear: both; page-break-after:always; height:1px"></div>'
102 toc_html = toc_html + '<div style="clear: both"></div>'
103 return (BeautifulSoup(toc_html).body.contents)
104
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700105def add_toc(soup):
106 toc_contents = generate_toc(soup)[0]
107 toc_title = BeautifulSoup("<h6>Table of Contents</h6>").body.contents[0]
108 soup.body.insert(0, toc_contents)
109 soup.body.insert(0, toc_title)
110 return soup
111
112def create_id(header_tag):
113 return header_tag.contents[0].lower().replace('. ', '_').replace(' ', '_').replace('.', '_')
114
115# Utilities
116def get_immediate_subdirs(dir):
117 return [name for name in os.listdir(dir)
118 if os.path.isdir(os.path.join(dir, name))]
119
120# Odds and ends
121
122def check_section_numbering(soup):
123 header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
124 for tag in header_tags:
125 headings = soup.find_all(tag)
126 header_numbers = []
127 for heading in headings:
128 header_numbers.append(re.sub(r"([\d.]*).*", r"\1"), heading.contents)
129 return true
130
Gina Dimino8f4279b2017-01-11 16:18:39 -0800131def get_version_branch_and_output():
132
133 # Get command-line args. If there aren't any, then prompt for user input.
134 parser = argparse.ArgumentParser()
135 parser.add_argument('--version', help='Android version')
136 parser.add_argument('--branch', help='AOSP branch')
137 parser.add_argument('--output', help='Base name of output file')
138 args = parser.parse_args()
139
140 if not args.version:
141 args.version = raw_input('Android version for CDD: ')
142 if not args.branch:
143 args.branch = raw_input('Current AOSP branch for changelog: ')
144 if not args.output:
145 args.output = raw_input('Base name of desired output file: ')
146
147 return (args.version, args.branch, args.output)
148
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700149
150def main():
Gina Dimino8f4279b2017-01-11 16:18:39 -0800151 # Read version and branch info and output file name.
152 (ANDROID_VERSION, CURRENT_BRANCH, output_filename) = get_version_branch_and_output()
153
154 # Scan current directory for source files and compile info for the toc..
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700155 my_path = os.getcwd()
156 section_info = get_section_info(my_path)
Gina Dimino8f4279b2017-01-11 16:18:39 -0800157
158 # Generate the HTML
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700159 soup = get_soup(section_info)
160 add_id_to_section_headers(soup)
161 add_toc(soup)
162 html = soup.prettify(formatter='html')
Gina Dimino8f4279b2017-01-11 16:18:39 -0800163
164 # Add version and branch info
165 html = re.sub(re.compile(r"ANDROID_VERSION"), ANDROID_VERSION, html)
166 html = re.sub(re.compile(r"CURRENT_BRANCH"), CURRENT_BRANCH, html)
167
168 # Apply HTML Tidy to output
169 (document, errors) = tidylib.tidy_document(html, options={})
170
171 # Write output file
172 output = open('%s.html' % output_filename, "w")
173 output.write(document.encode('utf-8'))
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700174 output.close()
Gina Diminoee0fa6b2016-04-04 17:30:54 -0700175
176
177if __name__ == '__main__':
178 main()
179
180
181
182