sconsDoxy: Run converters on chapel and doxygen tools

Signed-off-by: Mats Wichmann <mats@linux.com>
This commit is contained in:
Mats Wichmann 2021-03-05 08:55:42 -07:00 committed by Ichthyostega
parent 35e74d755d
commit cce3dad4fe
4 changed files with 93 additions and 46 deletions

View file

@ -1,4 +1,2 @@
env = Environment(tools=["default", "doxygen"], toolpath=".")
env =Environment(tools=['default', 'doxygen'], toolpath='.') env.Doxygen("doxy.cfg")
env.Doxygen('doxy.cfg')

View file

@ -16,5 +16,5 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from doxygen import generate from .doxygen import generate
from doxygen import exists from .doxygen import exists

View file

@ -28,6 +28,7 @@ import os
import os.path import os.path
import glob import glob
from fnmatch import fnmatch from fnmatch import fnmatch
from functools import reduce
# Currently supported output formats and their default # Currently supported output formats and their default
# values and output locations. # values and output locations.
@ -55,6 +56,7 @@ def DoxyfileParse(file_contents, conf_dir, data=None):
data = {} 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", "")
@ -75,10 +77,10 @@ def DoxyfileParse(file_contents, conf_dir, data=None):
data[key][-1] += token data[key][-1] += token
while token: while token:
if token in ['\n']: if token in ["\n"]:
if last_token not in ['\\']: if last_token not in ["\\"]:
key_token = True key_token = True
elif token in ['\\']: elif token in ["\\"]:
pass pass
elif key_token: elif key_token:
key = token key = token
@ -105,7 +107,7 @@ def DoxyfileParse(file_contents, conf_dir, data=None):
if nextfile in data[key]: if nextfile in data[key]:
raise Exception("recursive @INCLUDE in Doxygen config: " + nextfile) raise Exception("recursive @INCLUDE in Doxygen config: " + nextfile)
data[key].append(nextfile) data[key].append(nextfile)
fh = open(nextfile, 'r') fh = open(nextfile, "r")
DoxyfileParse(fh.read(), conf_dir, data) DoxyfileParse(fh.read(), conf_dir, data)
fh.close() fh.close()
else: else:
@ -115,12 +117,12 @@ def DoxyfileParse(file_contents, conf_dir, data=None):
last_token = token last_token = token
token = lex.get_token() token = lex.get_token()
if last_token == '\\' and token != '\n': if last_token == "\\" and token != "\n":
new_data = False new_data = False
append_data(data, key, new_data, '\\') append_data(data, key, new_data, "\\")
# compress lists of len 1 into single strings # compress lists of len 1 into single strings
for (k, v) in data.items(): for (k, v) in list(data.items()):
if len(v) == 0: if len(v) == 0:
data.pop(k) data.pop(k)
@ -140,14 +142,35 @@ def DoxySourceFiles(node, env):
any files used to generate docs to the list of source files. any files used to generate docs to the list of source files.
""" """
default_file_patterns = [ default_file_patterns = [
'*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx', "*.c",
'*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++', "*.cc",
'*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm', "*.cxx",
'*.py', "*.cpp",
"*.c++",
"*.java",
"*.ii",
"*.ixx",
"*.ipp",
"*.i++",
"*.inl",
"*.h",
"*.hh ",
"*.hxx",
"*.hpp",
"*.h++",
"*.idl",
"*.odl",
"*.cs",
"*.php",
"*.php3",
"*.inc",
"*.m",
"*.mm",
"*.py",
] ]
default_exclude_patterns = [ default_exclude_patterns = [
'*~', "*~",
] ]
sources = [] sources = []
@ -181,8 +204,16 @@ def DoxySourceFiles(node, env):
for f in files: for f in files:
filename = os.path.join(root, f) filename = os.path.join(root, f)
pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False) pattern_check = reduce(
exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True) lambda x, y: x or bool(fnmatch(filename, y)),
file_patterns,
False,
)
exclude_check = reduce(
lambda x, y: x and fnmatch(filename, y),
exclude_patterns,
True,
)
if pattern_check and not exclude_check: if pattern_check and not exclude_check:
sources.append(filename) sources.append(filename)
@ -192,12 +223,18 @@ def DoxySourceFiles(node, env):
else: else:
# No INPUT specified, so apply plain patterns only # No INPUT specified, so apply plain patterns only
if recursive: if recursive:
for root, dirs, files in os.walk('.'): for root, dirs, files in os.walk("."):
for f in files: for f in files:
filename = os.path.join(root, f) filename = os.path.join(root, f)
pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False) pattern_check = reduce(
exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True) lambda x, y: x or bool(fnmatch(filename, y)),
file_patterns,
False,
)
exclude_check = reduce(
lambda x, y: x and fnmatch(filename, y), exclude_patterns, True
)
if pattern_check and not exclude_check: if pattern_check and not exclude_check:
sources.append(filename) sources.append(filename)
@ -219,7 +256,7 @@ def DoxySourceFiles(node, env):
# Add additional files to the list of source files: # Add additional files to the list of source files:
def append_additional_source(option, formats): def append_additional_source(option, formats):
for f in formats: for f in formats:
if data.get('GENERATE_' + f, output_formats[f][0]) == "YES": if data.get("GENERATE_" + f, output_formats[f][0]) == "YES":
file = data.get(option, "") file = data.get(option, "")
if file != "": if file != "":
if not os.path.isabs(file): if not os.path.isabs(file):
@ -228,9 +265,9 @@ def DoxySourceFiles(node, env):
sources.append(file) sources.append(file)
break break
append_additional_source("HTML_STYLESHEET", ['HTML']) append_additional_source("HTML_STYLESHEET", ["HTML"])
append_additional_source("HTML_HEADER", ['HTML']) append_additional_source("HTML_HEADER", ["HTML"])
append_additional_source("HTML_FOOTER", ['HTML']) append_additional_source("HTML_FOOTER", ["HTML"])
return sources return sources
@ -241,7 +278,7 @@ def DoxySourceScan(node, env, path):
any files used to generate docs to the list of source files. any files used to generate docs to the list of source files.
""" """
filepaths = DoxySourceFiles(node, env) filepaths = DoxySourceFiles(node, env)
sources = map(lambda path: env.File(path), filepaths) sources = [env.File(path) for path in filepaths]
return sources return sources
@ -262,16 +299,16 @@ def DoxyEmitter(target, source, env):
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
for (k, v) in output_formats.items(): for (k, v) in list(output_formats.items()):
if data.get("GENERATE_" + k, v[0]) == "YES": if data.get("GENERATE_" + k, v[0]) == "YES":
# Initialize output file extension for MAN pages # Initialize output file extension for MAN pages
if k == 'MAN': if k == "MAN":
# Is the given extension valid? # Is the given extension valid?
manext = v[3] manext = v[3]
if v[4] and v[4] in data: if v[4] and v[4] in data:
manext = data.get(v[4]) manext = data.get(v[4])
# Try to strip off dots # Try to strip off dots
manext = manext.replace('.', '') manext = manext.replace(".", "")
# Can we convert it to an int? # Can we convert it to an int?
try: try:
e = int(manext) e = int(manext)
@ -279,7 +316,9 @@ def DoxyEmitter(target, source, env):
# No, so set back to default # No, so set back to default
manext = "3" manext = "3"
od = env.Dir(os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]), "man" + manext)) od = env.Dir(
os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]), "man" + manext)
)
else: else:
od = env.Dir(os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) od = env.Dir(os.path.join(out_dir, data.get(k + "_OUTPUT", v[1])))
# don't clobber target folders # don't clobber target folders
@ -294,7 +333,9 @@ def DoxyEmitter(target, source, env):
fname = v[2] + data.get(v[4]) fname = v[2] + data.get(v[4])
else: else:
fname = v[2] + v[3] fname = v[2] + v[3]
of = env.File(os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]), fname)) of = env.File(
os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]), fname)
)
targets.append(of) targets.append(of)
# don't clean single files, we remove the complete output folders (see above) # don't clean single files, we remove the complete output folders (see above)
env.NoClean(of) env.NoClean(of)
@ -306,10 +347,14 @@ def DoxyEmitter(target, source, env):
filepaths = DoxySourceFiles(source[0], env) filepaths = DoxySourceFiles(source[0], env)
for f in filepaths: for f in filepaths:
if os.path.isfile(f) and f != doxy_fpath: if os.path.isfile(f) and f != doxy_fpath:
of = env.File(os.path.join(out_dir, of = env.File(
data.get(k + "_OUTPUT", v[1]), os.path.join(
"man" + manext, out_dir,
f + "." + manext)) data.get(k + "_OUTPUT", v[1]),
"man" + manext,
f + "." + manext,
)
)
targets.append(of) targets.append(of)
# don't clean single files, we remove the complete output folders (see above) # don't clean single files, we remove the complete output folders (see above)
env.NoClean(of) env.NoClean(of)
@ -336,6 +381,7 @@ def generate(env):
) )
import SCons.Builder import SCons.Builder
doxyfile_builder = SCons.Builder.Builder( doxyfile_builder = SCons.Builder.Builder(
action="cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}", action="cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}",
emitter=DoxyEmitter, emitter=DoxyEmitter,
@ -344,12 +390,14 @@ def generate(env):
source_scanner=doxyfile_scanner, source_scanner=doxyfile_scanner,
) )
env.Append(BUILDERS={ env.Append(
'Doxygen': doxyfile_builder, BUILDERS={
}) "Doxygen": doxyfile_builder,
}
)
env.AppendUnique( env.AppendUnique(
DOXYGEN='doxygen', DOXYGEN="doxygen",
) )

11
test.py
View file

@ -22,11 +22,11 @@
import unittest import unittest
import os import os
import sys 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') test_config_dir = os.path.join(os.path.dirname(__file__), "test_config")
def test_simple_parse(self): def test_simple_parse(self):
text = """ text = """
@ -45,13 +45,14 @@ INPUT = test.h
text = """@INCLUDE=include_test.cfg""" text = """@INCLUDE=include_test.cfg"""
result = DoxyfileParse(text, self.test_config_dir) result = DoxyfileParse(text, self.test_config_dir)
self.assertEqual(["abc"], result["INPUT"]) self.assertEqual(["abc"], result["INPUT"])
self.assertEqual([os.path.join(self.test_config_dir, "include_test.cfg")], self.assertEqual(
result["@INCLUDE"]) [os.path.join(self.test_config_dir, "include_test.cfg")], result["@INCLUDE"]
)
def test_recursive_include_tag(self): def test_recursive_include_tag(self):
text = """@INCLUDE=recursive_include_test.cfg""" text = """@INCLUDE=recursive_include_test.cfg"""
self.assertRaises(Exception, DoxyfileParse, text, self.test_config_dir) self.assertRaises(Exception, DoxyfileParse, text, self.test_config_dir)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()