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

Annotation of /trunk/scons/doxygen.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2651 - (hide 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 johnpye 766 # 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 jpye 2651 # 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 johnpye 766
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 jpye 2315 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 johnpye 766 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 jpye 2315 if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS", "TAGFILES"]:
88 johnpye 766 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 jpye 2315 # 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 johnpye 766 for node in data.get("INPUT", []):
130 jpye 2315 if not os.path.isabs(node):
131     node = os.path.join(conf_dir, node)
132 johnpye 766 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 jpye 2315 # 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 johnpye 766 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 jpye 2315 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 johnpye 766
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 jpye 2315 # 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 johnpye 766 # 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 jpye 2315 import SCons.Builder
231     doxyfile_builder = SCons.Builder.Builder(
232     action = "cd ${SOURCE.dir} && ${DOXYGEN} ${SOURCE.file}",
233 johnpye 766 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