Add support for @INCLUDE tags in doxyfiles
Doxygen configs can include other doxygen configs. Add support for @INCLUDE tag.
This commit is contained in:
parent
22dfdfb824
commit
c876fe0044
4 changed files with 52 additions and 16 deletions
48
doxygen.py
48
doxygen.py
|
|
@ -43,16 +43,17 @@ output_formats = {
|
||||||
"XML": ("NO", "xml", "index", ".xml", ""),
|
"XML": ("NO", "xml", "index", ".xml", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
def DoxyfileParse(file_contents):
|
def DoxyfileParse(file_contents, conf_dir, data=None):
|
||||||
"""
|
"""
|
||||||
Parse a Doxygen source file and return a dictionary of all the values.
|
Parse a Doxygen source file and return a dictionary of all the values.
|
||||||
Values will be strings and lists of strings.
|
Values will be strings and lists of strings.
|
||||||
"""
|
"""
|
||||||
data = {}
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
|
||||||
import shlex
|
import shlex
|
||||||
lex = shlex.shlex(instream = file_contents, posix = True)
|
lex = shlex.shlex(instream = file_contents, posix = True)
|
||||||
lex.wordchars += "*+./-:"
|
lex.wordchars += "*+./-:@"
|
||||||
lex.whitespace = lex.whitespace.replace("\n", "")
|
lex.whitespace = lex.whitespace.replace("\n", "")
|
||||||
lex.escape = ""
|
lex.escape = ""
|
||||||
|
|
||||||
|
|
@ -87,12 +88,28 @@ def DoxyfileParse(file_contents):
|
||||||
if key == "TAGFILES" and data.has_key(key):
|
if key == "TAGFILES" and data.has_key(key):
|
||||||
append_data( data, key, False, "=" )
|
append_data( data, key, False, "=" )
|
||||||
new_data=False
|
new_data=False
|
||||||
|
elif key == "@INCLUDE" and data.has_key(key):
|
||||||
|
# don't reset the @INCLUDE list when we see a new @INCLUDE line.
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
data[key] = list()
|
data[key] = list()
|
||||||
|
elif key == "@INCLUDE":
|
||||||
|
# special case for @INCLUDE key: read the referenced
|
||||||
|
# file as a doxyfile too.
|
||||||
|
nextfile = token
|
||||||
|
if not os.path.isabs(nextfile):
|
||||||
|
nextfile = os.path.join(conf_dir, nextfile)
|
||||||
|
if nextfile in data[key]:
|
||||||
|
raise Exception("recursive @INCLUDE in Doxygen config: "+nextfile)
|
||||||
|
data[key].append(nextfile)
|
||||||
|
fh = open(nextfile,'r')
|
||||||
|
DoxyfileParse(fh.read(), conf_dir, data)
|
||||||
|
fh.close()
|
||||||
else:
|
else:
|
||||||
append_data( data, key, new_data, token )
|
append_data( data, key, new_data, token )
|
||||||
new_data = True
|
new_data = True
|
||||||
|
|
||||||
|
|
||||||
last_token = token
|
last_token = token
|
||||||
token = lex.get_token()
|
token = lex.get_token()
|
||||||
|
|
||||||
|
|
@ -106,7 +123,7 @@ def DoxyfileParse(file_contents):
|
||||||
data.pop(k)
|
data.pop(k)
|
||||||
|
|
||||||
# items in the following list will be kept as lists and not converted to strings
|
# items in the following list will be kept as lists and not converted to strings
|
||||||
if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS", "TAGFILES"]:
|
if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS", "TAGFILES", "@INCLUDE"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(v) == 1:
|
if len(v) == 1:
|
||||||
|
|
@ -132,7 +149,13 @@ def DoxySourceFiles(node, env):
|
||||||
|
|
||||||
sources = []
|
sources = []
|
||||||
|
|
||||||
data = DoxyfileParse(node.get_contents())
|
# We're running in the top-level directory, but the doxygen
|
||||||
|
# configuration file is in the same directory as node; this means
|
||||||
|
# that relative pathnames in node must be adjusted before they can
|
||||||
|
# go onto the sources list
|
||||||
|
conf_dir = os.path.dirname(str(node))
|
||||||
|
|
||||||
|
data = DoxyfileParse(node.get_contents(), conf_dir)
|
||||||
|
|
||||||
if data.get("RECURSIVE", "NO") == "YES":
|
if data.get("RECURSIVE", "NO") == "YES":
|
||||||
recursive = True
|
recursive = True
|
||||||
|
|
@ -142,12 +165,6 @@ def DoxySourceFiles(node, env):
|
||||||
file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
|
file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
|
||||||
exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
|
exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
|
||||||
|
|
||||||
# We're running in the top-level directory, but the doxygen
|
|
||||||
# configuration file is in the same directory as node; this means
|
|
||||||
# that relative pathnames in node must be adjusted before they can
|
|
||||||
# go onto the sources list
|
|
||||||
conf_dir = os.path.dirname(str(node))
|
|
||||||
|
|
||||||
input = data.get("INPUT")
|
input = data.get("INPUT")
|
||||||
if input:
|
if input:
|
||||||
for node in data.get("INPUT", []):
|
for node in data.get("INPUT", []):
|
||||||
|
|
@ -185,6 +202,10 @@ def DoxySourceFiles(node, env):
|
||||||
for pattern in file_patterns:
|
for pattern in file_patterns:
|
||||||
sources.extend(glob.glob(pattern))
|
sources.extend(glob.glob(pattern))
|
||||||
|
|
||||||
|
# Add @INCLUDEd files to the list of source files:
|
||||||
|
for node in data.get("@INCLUDE", []):
|
||||||
|
sources.append(node)
|
||||||
|
|
||||||
# Add tagfiles to the list of source files:
|
# Add tagfiles to the list of source files:
|
||||||
for node in data.get("TAGFILES", []):
|
for node in data.get("TAGFILES", []):
|
||||||
file = node.split("=")[0]
|
file = node.split("=")[0]
|
||||||
|
|
@ -226,12 +247,12 @@ def DoxySourceScanCheck(node, env):
|
||||||
def DoxyEmitter(target, source, env):
|
def DoxyEmitter(target, source, env):
|
||||||
"""Doxygen Doxyfile emitter"""
|
"""Doxygen Doxyfile emitter"""
|
||||||
doxy_fpath = str(source[0])
|
doxy_fpath = str(source[0])
|
||||||
data = DoxyfileParse(source[0].get_contents())
|
conf_dir = os.path.dirname(doxy_fpath)
|
||||||
|
data = DoxyfileParse(source[0].get_contents(), conf_dir)
|
||||||
|
|
||||||
targets = []
|
targets = []
|
||||||
out_dir = data.get("OUTPUT_DIRECTORY", ".")
|
out_dir = data.get("OUTPUT_DIRECTORY", ".")
|
||||||
if not os.path.isabs(out_dir):
|
if not os.path.isabs(out_dir):
|
||||||
conf_dir = os.path.dirname(doxy_fpath)
|
|
||||||
out_dir = os.path.join(conf_dir, out_dir)
|
out_dir = os.path.join(conf_dir, out_dir)
|
||||||
|
|
||||||
# add our output locations
|
# add our output locations
|
||||||
|
|
@ -291,7 +312,6 @@ def DoxyEmitter(target, source, env):
|
||||||
tagfile = data.get("GENERATE_TAGFILE", "")
|
tagfile = data.get("GENERATE_TAGFILE", "")
|
||||||
if tagfile != "":
|
if tagfile != "":
|
||||||
if not os.path.isabs(tagfile):
|
if not os.path.isabs(tagfile):
|
||||||
conf_dir = os.path.dirname(str(source[0]))
|
|
||||||
tagfile = os.path.join(conf_dir, tagfile)
|
tagfile = os.path.join(conf_dir, tagfile)
|
||||||
targets.append(env.File(tagfile))
|
targets.append(env.File(tagfile))
|
||||||
|
|
||||||
|
|
|
||||||
18
test.py
18
test.py
|
|
@ -9,19 +9,33 @@ import sys
|
||||||
from doxygen import DoxyfileParse
|
from doxygen import DoxyfileParse
|
||||||
|
|
||||||
class TestParser(unittest.TestCase):
|
class TestParser(unittest.TestCase):
|
||||||
|
test_config_dir = os.path.join(os.path.dirname(__file__),'test_config')
|
||||||
|
|
||||||
def test_simple_parse(self):
|
def test_simple_parse(self):
|
||||||
text="""
|
text="""
|
||||||
# comment
|
# comment
|
||||||
INPUT = test.h
|
INPUT = test.h
|
||||||
"""
|
"""
|
||||||
result = DoxyfileParse(text)
|
result = DoxyfileParse(text, self.test_config_dir)
|
||||||
self.assertEqual(["test.h"], result["INPUT"])
|
self.assertEqual(["test.h"], result["INPUT"])
|
||||||
|
|
||||||
def test_parse_tag_on_first_line(self):
|
def test_parse_tag_on_first_line(self):
|
||||||
text="""INPUT=."""
|
text="""INPUT=."""
|
||||||
result = DoxyfileParse(text)
|
result = DoxyfileParse(text, self.test_config_dir)
|
||||||
self.assertEqual(["."], result["INPUT"])
|
self.assertEqual(["."], result["INPUT"])
|
||||||
|
|
||||||
|
def test_include_tag(self):
|
||||||
|
text="""@INCLUDE=include_test.cfg"""
|
||||||
|
result = DoxyfileParse(text, self.test_config_dir)
|
||||||
|
self.assertEqual(["abc"], result["INPUT"])
|
||||||
|
self.assertEqual([os.path.join(self.test_config_dir,
|
||||||
|
"include_test.cfg")],
|
||||||
|
result["@INCLUDE"])
|
||||||
|
|
||||||
|
def test_recursive_include_tag(self):
|
||||||
|
text="""@INCLUDE=recursive_include_test.cfg"""
|
||||||
|
self.assertRaises(Exception, DoxyfileParse, text, self.test_config_dir)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
1
test_config/include_test.cfg
Normal file
1
test_config/include_test.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
INPUT="abc"
|
||||||
1
test_config/recursive_include_test.cfg
Normal file
1
test_config/recursive_include_test.cfg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
@INCLUDE=recursive_include_test.cfg
|
||||||
Loading…
Reference in a new issue