[igt-dev] [PATCH i-g-t 5/5] docs: Embed subtest descriptions in the documentation

Arkadiusz Hiler arkadiusz.hiler at intel.com
Mon Jul 1 12:21:53 UTC 2019


This rewrites generate_description_xml in Python, so that we generate
properly escaped XML. The switch also makes the code more manageable.

Changes in the generated docbook:

1. subtests are not simply listed anymore, they are now another (sub)section

2. subtests are now linkable,
   e.g. docs/igt-kms-tests.html#kms_hdmi_inject at inject-4k

3. subtest's section now includes output of --describe

Python is required already by gtk-doc and we are not using anything
other than the standard library.

v2: keep the part of the subtest name after the last match (Simon)
    explicitly require python3 (Petri)
v3: make sure that the tail of the subtest name after the last keyword
    match is included (Simon)

Cc: Daniel Vetter <daniel at ffwll.ch>
Cc: Petri Latvala <petri.latvala at intel.com>
Cc: Simon Ser <simon.ser at intel.com>
Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler at intel.com>
Acked-by: Petri Latvala <petri.latvala at intel.com>
---
 .../igt-gpu-tools/generate_description_xml.py | 114 ++++++++++++++++++
 .../igt-gpu-tools/generate_description_xml.sh |  46 -------
 docs/reference/igt-gpu-tools/meson.build      |   2 +-
 meson.build                                   |   3 +-
 4 files changed, 117 insertions(+), 48 deletions(-)
 create mode 100755 docs/reference/igt-gpu-tools/generate_description_xml.py
 delete mode 100644 docs/reference/igt-gpu-tools/generate_description_xml.sh

diff --git a/docs/reference/igt-gpu-tools/generate_description_xml.py b/docs/reference/igt-gpu-tools/generate_description_xml.py
new file mode 100755
index 00000000..8bb0989a
--- /dev/null
+++ b/docs/reference/igt-gpu-tools/generate_description_xml.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+
+import re
+import sys
+import os.path
+import subprocess
+import xml.etree.cElementTree as ET
+
+from collections import namedtuple
+
+Subtest = namedtuple("Subtest", "name description")
+KEYWORDS=re.compile(r'\b(invalid|hang|swap|thrash|crc|tiled|tiling|rte|ctx|render|blt|bsd|vebox|exec|rpm)\b')
+
+
+def get_testlist(path):
+    "read binaries' names from test-list.txt"
+    with open(path, 'r') as f:
+        assert(f.readline() == "TESTLIST\n")
+        tests = f.readline().strip().split(" ")
+        assert(f.readline() == "END TESTLIST\n")
+
+    return tests
+
+
+def keywordize(root, text, keywords):
+    "set text for root element and wrap KEYWORDS in a <acronym>"
+    matches = list(keywords.finditer(text))
+
+    if not matches:
+        root.text = text
+        return
+
+    pos = 0
+    last_element = None
+    root.text = ""
+
+    for match in matches:
+        if match.start() > pos:
+            to_append = text[pos:match.start()]
+
+            if last_element == None:
+                root.text += to_append
+            else:
+                last_element.tail += to_append
+
+        last_element = ET.SubElement(root, "acronym")
+        last_element.tail = ""
+        last_element.text=match.group()
+        pos = match.end()
+
+    last_element.tail = text[pos:]
+
+
+def get_subtests(testdir, test):
+    "execute test and get subtests with their descriptions via --describe"
+    output = []
+    full_test_path = os.path.join(testdir, test)
+    proc = subprocess.run([full_test_path, "--describe"], stdout=subprocess.PIPE)
+    description = ""
+    current_subtest = None
+
+    for line in proc.stdout.decode().splitlines():
+        if line.startswith("SUB "):
+            output += [Subtest(current_subtest, description)]
+            description = ""
+            current_subtest = line.split(' ')[1]
+        else:
+            description += line
+
+    output += [Subtest(current_subtest, description)]
+
+    return output
+
+def main():
+    output_file   = sys.argv[1]
+    test_filter   = re.compile(sys.argv[2])
+    testlist_file = sys.argv[3]
+    testdir       = os.path.abspath(os.path.dirname(testlist_file))
+
+    root = ET.Element("refsect1")
+    ET.SubElement(root, "title").text = "Description"
+
+    tests = get_testlist(testlist_file)
+
+    for test in tests:
+        if not test_filter.match(test):
+            continue
+
+        test_section = ET.SubElement(root, "refsect2", id=test)
+        test_title = ET.SubElement(test_section, "title")
+        keywordize(test_title, test, KEYWORDS)
+
+        subtests = get_subtests(testdir, test)
+
+        # we have description with no subtest name, add it at the top level
+        if subtests and not subtests[0].name:
+            ET.SubElement(test_section, "para").text = subtests[0].description
+
+        if len(subtests) > 100:
+            ET.SubElement(test_section, "para").text = "More than 100 subtests, skipping listing"
+            continue
+
+        for name, description in subtests:
+            if not name:
+                continue
+
+            subtest_section = ET.SubElement(test_section, "refsect3", id="{}@{}".format(test, name))
+            subtest_title = ET.SubElement(subtest_section, "title")
+            keywordize(subtest_title, name, KEYWORDS)
+            ET.SubElement(subtest_section, "para").text = description
+
+    ET.ElementTree(root).write(output_file)
+
+main()
diff --git a/docs/reference/igt-gpu-tools/generate_description_xml.sh b/docs/reference/igt-gpu-tools/generate_description_xml.sh
deleted file mode 100644
index 705a7bf3..00000000
--- a/docs/reference/igt-gpu-tools/generate_description_xml.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-output=$1
-filter=$2
-testlist=$3
-testdir=$(dirname $testlist)
-
-KEYWORDS="(invalid|hang|swap|thrash|crc|tiled|tiling|rte|ctx|render|blt|bsd|vebox|exec|rpm)"
-
-echo "<?xml version=\"1.0\"?>" > $output
-echo "<!DOCTYPE refsect1 PUBLIC \"-//OASIS//DTD DocBook XML V4.3//EN\"" >> $output
-echo "               \"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd\"" >> $output
-echo "[" >> $output
-echo "  <!ENTITY % local.common.attrib \"xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'\">" >> $output
-echo "  <!ENTITY version SYSTEM \"version.xml\">" >> $output
-echo "]>" >> $output
-echo "<refsect1>" >> $output
-echo "<title>Description</title>" >> $output
-for test in `cat $testlist | tr ' ' '\n' | grep "^$filter" | sort`; do
-	echo "<refsect2 id=\"$test\"><title>" >> $output;
-	echo "$test" | perl -pe "s/(?<=_)$KEYWORDS(?=(_|\\W))/<acronym>\\1<\\/acronym>/g" >> $output;
-	echo "</title><para><![CDATA[" >> $output;
-	testprog=$testdir/$test;
-	 ./$testprog --help-description >> $output;
-	echo "]]></para>" >> $output;
-	if ./$testprog --list-subtests > /dev/null ; then
-		echo "<refsect3><title>Subtests</title>" >> $output;
-		subtest_list=`./$testprog --list-subtests`;
-		subtest_count=`echo $subtest_list | wc -w`;
-		if [ $subtest_count -gt 100 ]; then
-			echo "<para>This test has over 100 subtests. " >> $output;
-			echo "Run <command>$test</command> <option>--list-subtests</option> to list them.</para>" >> $output;
-		else
-			echo "<simplelist>" >> $output;
-			for subtest in $subtest_list; do
-				echo "<member>" >> $output;
-				echo "$subtest" | perl -pe "s/\\b$KEYWORDS\\b/<acronym>\\1<\\/acronym>/g" >> $output;
-				echo "</member>" >> $output;
-			done;
-			echo "</simplelist>" >> $output;
-		fi;
-		echo "</refsect3>" >> $output;
-	fi;
-	echo "</refsect2>" >> $output;
-done;
-echo "</refsect1>" >> $output
diff --git a/docs/reference/igt-gpu-tools/meson.build b/docs/reference/igt-gpu-tools/meson.build
index 4d177e49..e2bdc495 100644
--- a/docs/reference/igt-gpu-tools/meson.build
+++ b/docs/reference/igt-gpu-tools/meson.build
@@ -45,7 +45,7 @@ test_groups = [
 	'vgem',
 ]
 
-gen_description = find_program('generate_description_xml.sh')
+gen_description = find_program('generate_description_xml.py')
 gen_programs = find_program('generate_programs_xml.sh')
 
 generated_docs = []
diff --git a/meson.build b/meson.build
index f0cb2543..0629d441 100644
--- a/meson.build
+++ b/meson.build
@@ -303,7 +303,8 @@ subdir('overlay')
 subdir('man')
 
 gtk_doc = dependency('gtk-doc', required : build_docs)
-if build_tests and gtk_doc.found()
+python3 = find_program('python3', required : build_docs)
+if build_tests and gtk_doc.found() and python3.found()
 	subdir('docs')
 elif build_docs.enabled()
 	error('Documentation requires building tests')
-- 
2.21.0



More information about the igt-dev mailing list