/[ascend]/trunk/scons/doxygen.py
ViewVC logotype

Contents of /trunk/scons/doxygen.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2651 - (show annotations) (download) (as text)
Thu Dec 13 07:29:48 2012 UTC (11 years, 11 months ago) by jpye
File MIME type: text/x-python
File size: 7537 byte(s)
Fixing GPL header, removing postal address (rpmlint incorrect-fsf-address)
1 # vim: set et sw=3 tw=0 fo=awqorc ft=python:
2 #
3 # Astxx, the Asterisk C++ API and Utility Library.
4 # Copyright (C) 2005, 2006 Matthew A. Nicholson
5 # Copyright (C) 2006 Tim Blechmann
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License version 2.1 as published by the Free Software Foundation.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 import os
20 import os.path
21 import glob
22 from fnmatch import fnmatch
23
24 def DoxyfileParse(file_contents):
25 """
26 Parse a Doxygen source file and return a dictionary of all the values.
27 Values will be strings and lists of strings.
28 """
29 data = {}
30
31 import shlex
32 lex = shlex.shlex(instream = file_contents, posix = True)
33 lex.wordchars += "*+./-:"
34 lex.whitespace = lex.whitespace.replace("\n", "")
35 lex.escape = ""
36
37 lineno = lex.lineno
38 token = lex.get_token()
39 key = token # the first token should be a key
40 last_token = ""
41 key_token = False
42 next_key = False
43 new_data = True
44
45 def append_data(data, key, new_data, token):
46 if new_data or len(data[key]) == 0:
47 data[key].append(token)
48 else:
49 data[key][-1] += token
50
51 while token:
52 if token in ['\n']:
53 if last_token not in ['\\']:
54 key_token = True
55 elif token in ['\\']:
56 pass
57 elif key_token:
58 key = token
59 key_token = False
60 else:
61 if token == "+=":
62 if not data.has_key(key):
63 data[key] = list()
64 elif token == "=":
65 if key == "TAGFILES" and data.has_key(key):
66 append_data( data, key, False, "=" )
67 new_data=False
68 else:
69 data[key] = list()
70 else:
71 append_data( data, key, new_data, token )
72 new_data = True
73
74 last_token = token
75 token = lex.get_token()
76
77 if last_token == '\\' and token != '\n':
78 new_data = False
79 append_data( data, key, new_data, '\\' )
80
81 # compress lists of len 1 into single strings
82 for (k, v) in data.items():
83 if len(v) == 0:
84 data.pop(k)
85
86 # items in the following list will be kept as lists and not converted to strings
87 if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS", "TAGFILES"]:
88 continue
89
90 if len(v) == 1:
91 data[k] = v[0]
92
93 return data
94
95 def DoxySourceScan(node, env, path):
96 """
97 Doxygen Doxyfile source scanner. This should scan the Doxygen file and add
98 any files used to generate docs to the list of source files.
99 """
100 default_file_patterns = [
101 '*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx',
102 '*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++',
103 '*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm',
104 '*.py',
105 ]
106
107 default_exclude_patterns = [
108 '*~',
109 ]
110
111 sources = []
112
113 data = DoxyfileParse(node.get_contents())
114
115 if data.get("RECURSIVE", "NO") == "YES":
116 recursive = True
117 else:
118 recursive = False
119
120 file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
121 exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
122
123 # We're running in the top-level directory, but the doxygen
124 # configuration file is in the same directory as node; this means
125 # that relative pathnames in node must be adjusted before they can
126 # go onto the sources list
127 conf_dir = os.path.dirname(str(node))
128
129 for node in data.get("INPUT", []):
130 if not os.path.isabs(node):
131 node = os.path.join(conf_dir, node)
132 if os.path.isfile(node):
133 sources.append(node)
134 elif os.path.isdir(node):
135 if recursive:
136 for root, dirs, files in os.walk(node):
137 for f in files:
138 filename = os.path.join(root, f)
139
140 pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False)
141 exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True)
142
143 if pattern_check and not exclude_check:
144 sources.append(filename)
145 else:
146 for pattern in file_patterns:
147 sources.extend(glob.glob("/".join([node, pattern])))
148
149 # Add tagfiles to the list of source files:
150 for node in data.get("TAGFILES", []):
151 file = node.split("=")[0]
152 if not os.path.isabs(file):
153 file = os.path.join(conf_dir, file)
154 sources.append(file)
155
156 # Add additional files to the list of source files:
157 def append_additional_source(option):
158 file = data.get(option, "")
159 if file != "":
160 if not os.path.isabs(file):
161 file = os.path.join(conf_dir, file)
162 if os.path.isfile(file):
163 sources.append(file)
164
165 append_additional_source("HTML_STYLESHEET")
166 append_additional_source("HTML_HEADER")
167 append_additional_source("HTML_FOOTER")
168
169 sources = map( lambda path: env.File(path), sources )
170 return sources
171
172
173 def DoxySourceScanCheck(node, env):
174 """Check if we should scan this file"""
175 return os.path.isfile(node.path)
176
177 def DoxyEmitter(source, target, env):
178 """Doxygen Doxyfile emitter"""
179 # possible output formats and their default values and output locations
180 output_formats = {
181 "HTML": ("YES", "html"),
182 "LATEX": ("YES", "latex"),
183 "RTF": ("NO", "rtf"),
184 "MAN": ("YES", "man"),
185 "XML": ("NO", "xml"),
186 }
187
188 data = DoxyfileParse(source[0].get_contents())
189
190 targets = []
191 out_dir = data.get("OUTPUT_DIRECTORY", ".")
192 if not os.path.isabs(out_dir):
193 conf_dir = os.path.dirname(str(source[0]))
194 out_dir = os.path.join(conf_dir, out_dir)
195
196 # add our output locations
197 for (k, v) in output_formats.items():
198 if data.get("GENERATE_" + k, v[0]) == "YES":
199 targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) )
200
201 # add the tag file if neccessary:
202 tagfile = data.get("GENERATE_TAGFILE", "")
203 if tagfile != "":
204 if not os.path.isabs(tagfile):
205 conf_dir = os.path.dirname(str(source[0]))
206 tagfile = os.path.join(conf_dir, tagfile)
207 targets.append(env.File(tagfile))
208
209 # don't clobber targets
210 for node in targets:
211 env.Precious(node)
212
213 # set up cleaning stuff
214 for node in targets:
215 env.Clean(node, node)
216
217 return (targets, source)
218
219 def generate(env):
220 """
221 Add builders and construction variables for the
222 Doxygen tool. This is currently for Doxygen 1.4.6.
223 """
224 doxyfile_scanner = env.Scanner(
225 DoxySourceScan,
226 "DoxySourceScan",
227 scan_check = DoxySourceScanCheck,
228 )
229
230 import SCons.Builder
231 doxyfile_builder = SCons.Builder.Builder(
232 action = "cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}",
233 emitter = DoxyEmitter,
234 target_factory = env.fs.Entry,
235 single_source = True,
236 source_scanner = doxyfile_scanner,
237 )
238
239 env.Append(BUILDERS = {
240 'Doxygen': doxyfile_builder,
241 })
242
243 env.AppendUnique(
244 DOXYGEN = 'doxygen',
245 )
246
247 def exists(env):
248 """
249 Make sure doxygen exists.
250 """
251 return env.Detect("doxygen")

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22