]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #!/usr/bin/env python |
2 | ||
3 | # Copyright 2010 Daniel James. | |
4 | # Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | """Boostbook tests | |
8 | ||
9 | Usage: python build_docs.py [--generate-gold] | |
10 | """ | |
11 | ||
12 | import difflib, getopt, os, re, sys | |
13 | import lxml.ElementInclude | |
14 | from lxml import etree | |
15 | from collections import defaultdict | |
16 | ||
17 | # Globals | |
18 | ||
19 | def usage_and_exit(): | |
20 | print __doc__ | |
21 | sys.exit(2) | |
22 | ||
23 | def main(argv): | |
24 | script_directory = os.path.dirname(sys.argv[0]) | |
25 | boostbook_directory = os.path.join(script_directory, "../../xsl") | |
26 | ||
27 | try: | |
28 | opts, args = getopt.getopt(argv, "", | |
29 | ["generate-gold"]) | |
30 | if(len(args)): usage_and_exit() | |
31 | except getopt.GetoptError: | |
32 | usage_and_exit() | |
33 | ||
34 | generate_gold = False | |
35 | ||
36 | for opt, arg in opts: | |
37 | if opt == '--generate-gold': | |
38 | generate_gold = True | |
39 | ||
40 | # Walk the test directory | |
41 | ||
42 | parser = etree.XMLParser() | |
43 | ||
44 | try: | |
45 | boostbook_xsl = etree.XSLT( | |
46 | etree.parse(os.path.join(boostbook_directory, "docbook.xsl"), parser) | |
47 | ) | |
48 | except lxml.etree.XMLSyntaxError, error: | |
49 | print "Error parsing boostbook xsl:" | |
50 | print error | |
51 | sys.exit(1) | |
52 | ||
53 | for root, dirs, files in os.walk(os.path.join(script_directory, 'tests')): | |
54 | for filename in files: | |
55 | (base, ext) = os.path.splitext(filename) | |
56 | if (ext == '.xml'): | |
57 | src_path = os.path.join(root, filename) | |
58 | gold_path = os.path.join(root, base + '.gold') | |
59 | try: | |
60 | doc_text = run_boostbook(parser, boostbook_xsl, src_path) | |
61 | except: | |
62 | # TODO: Need better error reporting here: | |
63 | print "Error running boostbook for " + src_path | |
64 | continue | |
65 | ||
66 | if (generate_gold): | |
67 | file = open(gold_path, 'w') | |
68 | try: | |
69 | file.write(doc_text) | |
70 | finally: file.close() | |
71 | else: | |
72 | file = open(gold_path, 'r') | |
73 | try: | |
74 | gold_text = file.read() | |
75 | finally: | |
76 | file.close() | |
77 | compare_xml(src_path, doc_text, gold_text) | |
78 | ||
79 | def run_boostbook(parser, boostbook_xsl, file): | |
80 | doc = boostbook_xsl(etree.parse(file, parser)) | |
81 | normalize_boostbook_ids(doc) | |
82 | return etree.tostring(doc) | |
83 | ||
84 | def normalize_boostbook_ids(doc): | |
85 | ids = {} | |
86 | id_bases = defaultdict(int) | |
87 | ||
88 | for node in doc.xpath("//*[starts-with(@id, 'id') or contains(@id, '_id')]"): | |
89 | id = node.get('id') | |
90 | ||
91 | if(id in ids): | |
92 | print 'Duplicate id: ' + id | |
93 | ||
94 | match = re.match("(.+_id|id)([mp]?\d+)((?:-bb)?)", id) | |
95 | if(match): | |
96 | # Truncate id name, as it sometimes has different lengths... | |
97 | match2 = re.match("(.*?)([^.]*?)(_?id)", match.group(1)) | |
98 | base = match2.group(1) + match2.group(2)[:7] + match2.group(3) | |
99 | count = id_bases[base] + 1 | |
100 | id_bases[base] = count | |
101 | ids[id] = base + str(count) + match.group(3) | |
102 | ||
103 | for node in doc.xpath("//*[@linkend or @id]"): | |
104 | x = node.get('linkend') | |
105 | if(x in ids): node.set('linkend', ids[x]) | |
106 | x = node.get('id') | |
107 | if(x in ids): node.set('id', ids[x]) | |
108 | ||
109 | def compare_xml(file, doc_text, gold_text): | |
110 | # Had hoped to use xmldiff but it turned out to be a pain to install. | |
111 | # So instead just do a text diff. | |
112 | ||
113 | if (doc_text != gold_text): | |
114 | print "Error: " + file | |
115 | ||
116 | sys.stdout.writelines( | |
117 | difflib.unified_diff( | |
118 | gold_text.splitlines(True), | |
119 | doc_text.splitlines(True) | |
120 | ) | |
121 | ) | |
122 | ||
123 | ||
124 | ||
125 | if __name__ == "__main__": | |
126 | main(sys.argv[1:]) |