return compounddef.find('compoundname').text.startswith('md_') and compounddef.find('compoundname').text.endswith(compounddef.find('title').text) and not compounddef.find('briefdescription') and not compounddef.find('detaileddescription')
def extract_metadata(state: State, xml):
- logging.debug("Extracting metadata from {}".format(os.path.basename(xml)))
+ basename = os.path.basename(xml)
+
+ # These early returns should be kept consistent with parse_xml()
+ if basename == 'Doxyfile.xml':
+ logging.debug("Ignoring {}".format(basename))
+ return
+
+ logging.debug("Extracting metadata from {}".format(basename))
try:
tree = ET.parse(xml)
except ET.ParseError as e:
- logging.error("{}: XML parse error, skipping: {}".format(os.path.basename(xml), e))
+ logging.error("{}: XML parse error, skipping whole file: {}".format(basename, e))
return
root = tree.getroot()
- # We need just list of all example files in correct order, nothing else
- if os.path.basename(xml) == 'index.xml':
+ # From index.xml we need just list of all example files in correct order,
+ # nothing else
+ if basename == 'index.xml':
for i in root:
if i.attrib['kind'] == 'example':
compound = Empty()
state.examples += [compound]
return
- compounddef: ET.Element = root.find('compounddef')
+ # From other files we expect <doxygen><compounddef>
+ if root.tag != 'doxygen':
+ logging.warning("{}: root element expected to be <doxygen> but is <{}>, skipping whole file".format(basename, root.tag))
+ return
+ compounddef: ET.Element = root[0]
+ if compounddef.tag != 'compounddef':
+ logging.warning("{}: first child element expected to be <compounddef> but is <{}>, skipping whole file".format(basename, compounddef.tag))
+ return
+ assert len([i for i in root]) == 1
if compounddef.attrib['kind'] not in ['namespace', 'group', 'class', 'struct', 'union', 'dir', 'file', 'page']:
- logging.debug("No useful info in {}, skipping".format(os.path.basename(xml)))
+ logging.debug("No useful info in {}, skipping".format(basename))
return
# In order to show also undocumented members, go through all empty
state.current = os.path.basename(xml)
+ # All these early returns were logged in extract_metadata() already, no
+ # need to print the same warnings/erorrs twice. Keep the two consistent.
+ if state.current == 'Doxyfile.html':
+ return
+
logging.debug("Parsing {}".format(state.current))
try:
tree = ET.parse(xml)
except ET.ParseError as e:
- logging.error("{}: XML parse error, skipping: {}".format(state.current, e))
return
-
root = tree.getroot()
- assert root.tag == 'doxygen'
-
+ if root.tag != 'doxygen':
+ return
compounddef: ET.Element = root[0]
- assert compounddef.tag == 'compounddef'
+ if compounddef.tag != 'compounddef':
+ return
+
assert len([i for i in root]) == 1
# Ignoring private structs/classes and unnamed namespaces
+++ /dev/null
-XML_OUTPUT =
--- /dev/null
+XML_OUTPUT =
+
+##! M_THEME_COLOR =
+##! M_FAVICON =
+##! M_LINKS_NAVBAR1 =
+##! M_LINKS_NAVBAR2 =
+##! M_SEARCH_DISABLED = YES
--- /dev/null
+<> This XML is broken but isn't even opened <>
--- /dev/null
+<!-- this file should get opened but skipped because it doesn't contain a
+ <doxygen> element -->
+<doxyfile>
+ <option/>
+</doxyfile>
--- /dev/null
+<> This XML is broken and should get skipped <>
--- /dev/null
+<doxygenindex version="1.0.666">
+</doxygenindex>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>My Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>Pages</h1>
+ <ul class="m-doc">
+ </ul>
+ <script>
+ function toggle(e) {
+ e.parentElement.className = e.parentElement.className == 'm-doc-collapsible' ?
+ 'm-doc-expansible' : 'm-doc-collapsible';
+ return false;
+ }
+ /* Collapse all nodes marked as such. Doing it via JS instead of
+ directly in markup so disabling it doesn't harm usability. The list
+ is somehow regenerated on every iteration and shrinks as I change
+ the classes. It's not documented anywhere and I'm not sure if this
+ is the same across browsers, so I am going backwards in that list to
+ be sure. */
+ var collapsed = document.getElementsByClassName("collapsed");
+ for(var i = collapsed.length - 1; i >= 0; --i)
+ collapsed[i].className = 'm-doc-expansible';
+ </script>
+ </div>
+ </div>
+ </div>
+</article></main>
+<footer><nav>
+ <div class="m-container">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <p>My Project. Created with <a href="https://doxygen.org/">Doxygen</a> 1.0.666 and <a href="https://mcss.mosra.cz/">m.css</a>.</p>
+ </div>
+ </div>
+ </div>
+</nav></footer>
+</body>
+</html>
--- /dev/null
+<!-- this file should get opened but skipped because it doesn't contain a
+ <compounddef> as the first thing in the <doxygen> element. Might be a bit
+ too tight, but better safe than sorry AGAIN. -->
+<doxygen>
+ <crazyisay/>
+ <compounddef/>
+</doxygen>
self.assertEqual(*self.actual_expected_contents('dot.html', file))
-class ParseError(BaseTestCase):
- def test(self):
- self.run_doxygen(wildcard='broken.xml')
-
- # The index file should be generated, no abort
- self.assertTrue(os.path.exists(os.path.join(self.path, 'html', 'index.html')))
-
class AutobriefCppComments(IntegrationTestCase):
def test(self):
self.run_doxygen(wildcard='File_8h.xml')
--- /dev/null
+#
+# This file is part of m.css.
+#
+# Copyright © 2017, 2018, 2019, 2020, 2021, 2022
+# Vladimír Vondruš <mosra@centrum.cz>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+
+import os
+
+from . import BaseTestCase
+
+class IgnoredXmls(BaseTestCase):
+ def test(self):
+ with self.assertLogs() as cm:
+ self.run_doxygen(wildcard='*.xml')
+
+ self.assertEqual(cm.output, [
+ # The Doxyfile.xml should be completely ignored, producing just a
+ # debug message and not even being opened, as that would spam the
+ # output otherwise
+
+ # This is like Doxyfile.xml, but with a different name, ensure it
+ # gets properly skipped if the root element mismatches
+ "WARNING:root:Foxydile.xml: root element expected to be <doxygen> but is <doxyfile>, skipping whole file",
+
+ # A file that has a XML parse error should get skipped
+ "ERROR:root:broken.xml: XML parse error, skipping whole file: not well-formed (invalid token): line 1, column 1",
+
+ # The index.xml should be parsed and not produce any warning
+
+ # A file that has <doxygen> but something weird inside, skipped
+ # also
+ "WARNING:root:thingsgotcrazy.xml: first child element expected to be <compounddef> but is <crazyisay>, skipping whole file"
+ ])
+
+ # Some index page should be generated, with version 1.0.666 extracted
+ # from index.xml
+ self.assertEqual(*self.actual_expected_contents('pages.html'))