Docs: Add CDD docs and the build script, and test examples
Bug: 25199595
This is based on the amended final CDD for M, hosted as commit
1846a9622485855d572705a7972116caf0be3669 on the AOSP master branch.
Change-Id: Ic3bd96cd652f7d7b13def03a4ca1f04645c34255
diff --git a/make_cdd.py b/make_cdd.py
new file mode 100644
index 0000000..396769d
--- /dev/null
+++ b/make_cdd.py
@@ -0,0 +1,176 @@
+"""
+Utility for building the CDD from component markdown files.
+
+From the compatibility/cdd directory, run python make-cdd.py.
+
+Each generated CDD file is marked with a hash based on the content of the input files.
+
+TODO(gdimino): Clean up and comment this code.
+"""
+
+from bs4 import BeautifulSoup
+import hashlib
+import markdown
+import os
+import pprint
+import re
+import tidylib
+import subprocess
+
+# TODO (gdimino): Clean up this code using templates
+# from jinja2 import Template
+
+HEADERS_FOR_TOC = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
+ANDROID_VERSION = "7.0, (N)"
+TOC_PER_COL = 34
+
+def get_section_info(my_path):
+ # (_, _, filenames) = os.walk(my_path).next()
+ section_info = [];
+ # Get section info from every file whose name contains a number. TODO: fix
+ # this ugly hack.
+ # for rootdir, subdirs, files in os.walk(my_path):
+ for dir in get_immediate_subdirs(my_path):
+ # for dir in subdirs:
+ if (not dir.isalpha() and dir != 'older-versions'):
+ child_data = []
+ print 'dir = ' + dir
+ for file in os.listdir(dir):
+ if '.md' in file:
+ if file == 'index.md':
+ number = 0
+ else:
+ number = int((file.split('_')[1]))
+ print 'file = ' + file + ', dir = ' + dir
+ html_string = markdown.markdown(unicode(open(my_path + '/' + dir + '/' + file, 'r').read(), 'utf-8'))
+ child_data.append({'file': file,
+ 'number': number,
+ 'title': dir.split('_')[-1],
+ 'html': html_string,
+ 'children':[]})
+ child_data.sort(key=lambda child: child['number'])
+ section_info.append({'id': dir,
+ 'number': int(''.join((dir.split('_')[:-1])).replace("_", ".")),
+ 'title': dir.split('_')[-1],
+ 'html': '',
+ 'children':child_data})
+ section_info.sort(key=lambda section: section['number'])
+ return section_info
+
+
+def get_soup(section_info):
+ html_body_text = '''<!DOCTYPE html>
+<head>
+<title>Android ''' + ANDROID_VERSION + ''' Compatibility Definition</title>
+<link rel="stylesheet" type="text/css" href="source/android-cdd.css"/>
+</head>
+<body>
+<div id="main">'''
+
+ for section in section_info:
+ for child in section['children']:
+ html_body_text += child['html']
+ html_body_text += '</div></body><html>'
+ return BeautifulSoup(html_body_text)
+
+
+def add_id_to_section_headers(soup):
+ header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
+ for tag in soup.find_all(header_tags):
+ tag['id'] = create_id(tag)
+
+def old_generate_toc(soup):
+ toc_html = ''
+ header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
+ for tag in soup.find_all(header_tags):
+ tag_html = '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
+ toc_html = toc_html + tag_html
+ return (BeautifulSoup(toc_html).body.contents, '')
+
+def generate_toc(soup):
+ toc_html = '<div id="toc">'
+ header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
+ toc_entries = soup.find_all(header_tags)
+ toc_chunks = [toc_entries[i:i + TOC_PER_COL] for i in xrange(0, len(toc_entries), TOC_PER_COL)]
+ print 'Number of chunks = %d' % len(toc_chunks)
+ for chunk in toc_chunks:
+ if not toc_chunks.index(chunk) %2:
+ toc_html = toc_html + ('<div id="toc_left">')
+ for tag in chunk:
+ toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
+ toc_html = toc_html + ('</div>')
+ else:
+ toc_html = toc_html + ('<div id="toc_right">')
+ for tag in chunk:
+ toc_html = toc_html + '<p class="toc_' + tag.name + '"><a href= "#' + create_id(tag) + '">' + tag.contents[0] + '</a></p>'
+ toc_html = toc_html + ('</div>')
+ toc_html = toc_html + '<div style="clear: both; page-break-after:always; height:1px"></div>'
+ toc_html = toc_html + '<div style="clear: both"></div>'
+ return (BeautifulSoup(toc_html).body.contents)
+
+def old_add_toc(soup):
+ toc = soup.new_tag('div', id='toc')
+ toc_left = soup.new_tag('div', id='toc_left')
+ toc_right = soup.new_tag('div', id='toc_right')
+ toc.append(toc_left)
+ toc.append(toc_right)
+ # toc_left.contents, toc_right.contents = generate_toc(soup)
+ toc_left.contents, toc_right.contents = generate_toc(soup)
+ toc_title = BeautifulSoup("<h6>Table of Contents</h6>").body.contents[0]
+ soup.body.insert(0,toc)
+ soup.body.insert(0, toc_title)
+ return soup
+
+def add_toc(soup):
+ toc_contents = generate_toc(soup)[0]
+ toc_title = BeautifulSoup("<h6>Table of Contents</h6>").body.contents[0]
+ soup.body.insert(0, toc_contents)
+ soup.body.insert(0, toc_title)
+ return soup
+
+def create_id(header_tag):
+ return header_tag.contents[0].lower().replace('. ', '_').replace(' ', '_').replace('.', '_')
+
+# Utilities
+def get_immediate_subdirs(dir):
+ return [name for name in os.listdir(dir)
+ if os.path.isdir(os.path.join(dir, name))]
+
+# Odds and ends
+
+def check_section_numbering(soup):
+ header_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']
+ for tag in header_tags:
+ headings = soup.find_all(tag)
+ header_numbers = []
+ for heading in headings:
+ header_numbers.append(re.sub(r"([\d.]*).*", r"\1"), heading.contents)
+ return true
+
+def elim_para_whitespace(html):
+ 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)
+ return new_html
+
+def main():
+ my_path = os.getcwd()
+ section_info = get_section_info(my_path)
+ soup = get_soup(section_info)
+ add_id_to_section_headers(soup)
+ add_toc(soup)
+ html = soup.prettify(formatter='html')
+ # Add a hash to the filename, so that identidal inputs produce the same output
+ # file.
+ output_filename = "test-generated-cdd-%s.html" % hashlib.md5(html).hexdigest()[0:5]
+ output = open(output_filename, "w")
+ output.write(html.encode('utf-8'))
+ output.close()
+ # Code to generate PDF, needs work.
+ # 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')
+
+
+if __name__ == '__main__':
+ main()
+
+
+
+