-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdoxygen.py
More file actions
executable file
·115 lines (93 loc) · 4.85 KB
/
doxygen.py
File metadata and controls
executable file
·115 lines (93 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# $Copyright(c) 2013 Progress Software Corporation (PSC). All rights reserved.$
# $Copyright (c) 2013-2017 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$
# Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG
#
# $Id: doxygen.py 392236 2021-06-17 15:25:31Z sgol $
import subprocess, re
from xpybuild.basetarget import BaseTarget
from xpybuild.buildcommon import *
from xpybuild.utils.buildexceptions import *
from xpybuild.utils.fileutils import openForWrite, mkdir
from xpybuild.pathsets import PathSet
from xpybuild.propertysupport import defineOption
defineOption('doxygen.exepath', None)
defineOption('doxygen.warnignores', [])
class Doxygen(BaseTarget):
def __init__(self, target, source, config, internal=False, dependencies=None, failOnWarnings=False):
"""
Uses the doxygen tool to generate a directory of API documentation for languages such as C/C++.
@param target: The destination directory.
@param source: pathset listing the top-level source files to be documented.
To avoid classes appearing twice under different namespaces, use "dependencies" not "source"
for files that are #included by source/documented files where the namespace is provided
around the #include statement but not in the file itself.
@param config: the doxygen configuration file.
@param internal: True if items marked as internal/private should be included.
@param dependencies: optional pathset for files that are implicitly depended upon
by the source files to be documented (e.g. due to #include statements) but should not be
handled as source files in their own right (e.g. if the namespace is provided by the
file that #includes them).
@param failOnWarnings: makes this target fail if any warnings are logged to stderr
(the option doxygen.warnignores can be used to ignore expected warnings)
"""
BaseTarget.__init__(self, target, dependencies=[source, config, dependencies])
self.source = PathSet(source)
self.config = PathSet(config)
self.internal = internal
self.failOnWarnings = failOnWarnings
# todo: ought to be setting hashable implicit inputs
def run(self, context):
configtmpl = self.config.resolve(context)
assert len(configtmpl)==1, configtmpl
configtmpl = configtmpl[0]
sources = " ".join(self.source.resolve(context))
config = os.path.join(self.workDir, 'doxygen.conf')
replace = {
'INPUT' : sources,
'OUTPUT_DIR' : self.path,
'INTERNAL':'YES' if self.internal else 'NO',
'HIDE_INTERNAL':'NO' if self.internal else 'YES',
}
mkdir(self.workDir)
with openForWrite(config, 'wb') as outf:
with open(configtmpl, 'rb') as inf:
for l in inf:
for k in replace:
l = l.replace('@%s@' % k, replace[k])
outf.write(l)
exe = context.mergeOptions(self)['doxygen.exepath']
if not exe: raise BuildException('doxygen.exepath option must be set')
args = [ exe, config ]
args = [ context.expandPropertyValues(x) for x in args ]
#self.log.info('%s doxygen output file is: %s', self, os.path.join(self.workDir, 'doxygen.err'))
with open(os.path.join(self.workDir, 'doxygen.out'), 'wb') as stdout:
with open(os.path.join(self.workDir, 'doxygen.err'), 'wb') as stderr:
subprocess.check_call(args, stdout=stdout, stderr=stderr)
contents = []
with open(os.path.join(self.workDir, 'doxygen.out'), 'r') as stdout:
for l in stdout:
# Generating docs for compound com::softwareag::connectivity::StatusReporter...
if l.startswith('Generating docs for '):
# normalize " nested compound " to " compound " since the sorted list is easier to read that way
l = l.replace(' nested ', ' ').replace('Generating docs for ','').strip().strip('.')
contents.append(l)
if contents:
with open(os.path.join(self.path, 'html/contents.txt'), 'w') as f:
for l in sorted(contents):
print >>f, l
with open(os.path.join(self.workDir, 'doxygen.err'), 'r') as stderr:
errs = []
for l in stderr:
if not l.strip(): continue
if l.startswith(' ') and errs:
errs[-1] += ' - '+l.strip()
else:
errs.append(l.strip())
ignores = context.mergeOptions(self)['doxygen.warnignores']
errs = [e for e in errs if not any([re.match(i, e) for i in ignores])]
if errs:
if self.failOnWarnings:
self.log.error('Doxygen reported %d lines of stderr warnings for %s; see %s: \n%s', len(errs), self, os.path.join(self.workDir, 'doxygen.err'), '\n '.join(errs))
raise BuildException('Doxygen reported %d lines of stderr warnings (see %s), first is: %s'%(len(errs), os.path.join(self.workDir, 'doxygen.err'), errs[0].strip()))
else:
self.log.info('Doxygen reported %d lines of stderr warnings for %s; see %s', len(errs), self, os.path.join(self.workDir, 'doxygen.err'))