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