| #!/usr/bin/env python |
| |
| """Boostbook tests |
| |
| Usage: python build_docs.py [--generate-gold] |
| """ |
| |
| import difflib, getopt, os, re, sys |
| import lxml.ElementInclude |
| from lxml import etree |
| |
| # Globals |
| |
| def usage_and_exit(): |
| print __doc__ |
| sys.exit(2) |
| |
| def main(argv): |
| script_directory = os.path.dirname(sys.argv[0]) |
| boostbook_directory = os.path.join(script_directory, "../../xsl") |
| |
| try: |
| opts, args = getopt.getopt(argv, "", |
| ["generate-gold"]) |
| if(len(args)): usage_and_exit() |
| except getopt.GetoptError: |
| usage_and_exit() |
| |
| generate_gold = False |
| |
| for opt, arg in opts: |
| if opt == '--generate-gold': |
| generate_gold = True |
| |
| # Walk the test directory |
| |
| parser = etree.XMLParser() |
| |
| try: |
| boostbook_xsl = etree.XSLT( |
| etree.parse(os.path.join(boostbook_directory, "docbook.xsl"), parser) |
| ) |
| except lxml.etree.XMLSyntaxError, error: |
| print "Error parsing boostbook xsl:" |
| print error |
| sys.exit(1) |
| |
| for root, dirs, files in os.walk(os.path.join(script_directory, 'tests')): |
| for filename in files: |
| (base, ext) = os.path.splitext(filename) |
| if (ext == '.xml'): |
| src_path = os.path.join(root, filename) |
| gold_path = os.path.join(root, base + '.gold') |
| try: |
| doc_text = run_boostbook(parser, boostbook_xsl, src_path) |
| except: |
| # TODO: Need better error reporting here: |
| print "Error running boostbook for " + src_path |
| continue |
| |
| if (generate_gold): |
| file = open(gold_path, 'w') |
| try: |
| file.write(doc_text) |
| finally: file.close() |
| else: |
| file = open(gold_path, 'r') |
| try: |
| gold_text = file.read() |
| finally: |
| file.close() |
| compare_xml(filename, doc_text, gold_text) |
| |
| def run_boostbook(parser, boostbook_xsl, file): |
| doc = boostbook_xsl(etree.parse(file, parser)) |
| normalize_boostbook_ids(doc) |
| return etree.tostring(doc) |
| |
| def normalize_boostbook_ids(doc): |
| ids = {} |
| id_bases = {} |
| |
| for node in doc.xpath("//*[starts-with(@id, 'id') or contains(@id, '_id')]"): |
| id = node.get('id') |
| |
| if(id in ids): |
| print 'Duplicate id: ' + id |
| |
| match = re.match("(id|.+_id)(\d+)((?:-bb)?)", id) |
| if(match): |
| count = 1 |
| if(match.group(1) in id_bases): |
| count = id_bases[match.group(1)] + 1 |
| id_bases[match.group(1)] = count |
| ids[id] = match.group(1) + str(count) + match.group(3) |
| |
| for node in doc.xpath("//*[@linkend or @id]"): |
| x = node.get('linkend') |
| if(x in ids): node.set('linkend', ids[x]) |
| x = node.get('id') |
| if(x in ids): node.set('id', ids[x]) |
| |
| def compare_xml(file, doc_text, gold_text): |
| # Had hoped to use xmldiff but it turned out to be a pain to install. |
| # So instead just do a text diff. |
| |
| if (doc_text != gold_text): |
| print "Error: " + file |
| print |
| sys.stdout.writelines( |
| difflib.unified_diff( |
| gold_text.splitlines(True), |
| doc_text.splitlines(True) |
| ) |
| ) |
| |
| if __name__ == "__main__": |
| main(sys.argv[1:]) |