|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 |
|
4 # Copyright (c) 2003 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
5 # |
|
6 |
|
7 """ |
|
8 Eric4 API Generator |
|
9 |
|
10 This is the main Python script of the API generator. It is |
|
11 this script that gets called via the API generation interface. |
|
12 This script can be used via the commandline as well. |
|
13 """ |
|
14 |
|
15 import glob |
|
16 import os |
|
17 import sys |
|
18 import fnmatch |
|
19 |
|
20 import Utilities.ModuleParser |
|
21 from DocumentationTools.APIGenerator import APIGenerator |
|
22 from UI.Info import Version |
|
23 import Utilities |
|
24 import Preferences |
|
25 import DocumentationTools |
|
26 |
|
27 def usage(): |
|
28 """ |
|
29 Function to print some usage information. |
|
30 |
|
31 It prints a reference of all commandline parameters that may |
|
32 be used and ends the application. |
|
33 """ |
|
34 print "eric4-api" |
|
35 print |
|
36 print "Copyright (c) 2004 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>." |
|
37 print |
|
38 print "Usage:" |
|
39 print |
|
40 print " eric4-api [options] files..." |
|
41 print |
|
42 print "where files can be either python modules, package" |
|
43 print "directories or ordinary directories." |
|
44 print |
|
45 print "Options:" |
|
46 print |
|
47 print " -b name or --base name" |
|
48 print " Use the given name as the name of the base package." |
|
49 print " -h or --help" |
|
50 print " Show this help and exit." |
|
51 print " -o filename or --output=filename" |
|
52 print " Write the API information to the named file. A '%L' placeholder" |
|
53 print " is replaced by the language of the API file (see --language)." |
|
54 print " --oldstyle" |
|
55 print " Generate API files for QScintilla prior to 1.7." |
|
56 print " -p or --private" |
|
57 print " Include private methods and functions." |
|
58 print " -R, -r or --recursive" |
|
59 print " Perform a recursive search for source files." |
|
60 print " -t ext or --extension=ext" |
|
61 print " Add the given extension to the list of file extensions." |
|
62 print " This option may be given multiple times." |
|
63 print " -V or --version" |
|
64 print " Show version information and exit." |
|
65 print " -x directory or --exclude=directory" |
|
66 print " Specify a directory basename to be excluded." |
|
67 print " This option may be repeated multiple times." |
|
68 print " --exclude-file=pattern" |
|
69 print " Specify a filename pattern of files to be excluded." |
|
70 print " This option may be repeated multiple times." |
|
71 print " -l language or --language=language" |
|
72 print " Generate an API file for the given programming language." |
|
73 print " Supported programming languages are:" |
|
74 for lang in sorted(DocumentationTools.supportedExtensionsDictForApis.keys()): |
|
75 print " * %s" % lang |
|
76 print " The default is 'Python'." |
|
77 print " This option may be repeated multiple times." |
|
78 sys.exit(1) |
|
79 |
|
80 def version(): |
|
81 """ |
|
82 Function to show the version information. |
|
83 """ |
|
84 print \ |
|
85 """eric4-api %s |
|
86 |
|
87 Eric4 API generator. |
|
88 |
|
89 Copyright (c) 2004 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
90 This is free software; see the LICENSE.GPL3 for copying conditions. |
|
91 There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A |
|
92 PARTICULAR PURPOSE.""" % Version |
|
93 sys.exit(1) |
|
94 |
|
95 def main(): |
|
96 """ |
|
97 Main entry point into the application. |
|
98 """ |
|
99 global supportedExtensions |
|
100 |
|
101 import getopt |
|
102 |
|
103 try: |
|
104 opts, args = getopt.getopt(sys.argv[1:], "b:hl:o:pRrt:Vx:", |
|
105 ["base=", "exclude=", "exclude-file=", "extension=", "help", |
|
106 "language=", "oldstyle", "output=", "private", "recursive", |
|
107 "version", ]) |
|
108 except getopt.error: |
|
109 usage() |
|
110 |
|
111 excludeDirs = ["CVS", ".svn", "_svn", ".ropeproject", "_ropeproject", |
|
112 ".eric4project", "_eric4project", "dist", "build", "doc", "docs"] |
|
113 excludePatterns = [] |
|
114 outputFileName = "" |
|
115 recursive = False |
|
116 newStyle = True |
|
117 basePackage = "" |
|
118 includePrivate = False |
|
119 progLanguages = [] |
|
120 extensions = [] |
|
121 |
|
122 # Set the applications string encoding |
|
123 try: |
|
124 sys.setappdefaultencoding(str(Preferences.getSystem("StringEncoding"))) |
|
125 except AttributeError: |
|
126 pass |
|
127 |
|
128 for k, v in opts: |
|
129 if k in ["-o", "--output"]: |
|
130 outputFileName = v |
|
131 elif k in ["-R", "-r", "--recursive"]: |
|
132 recursive = True |
|
133 elif k in ["-x", "--exclude"]: |
|
134 excludeDirs.append(v) |
|
135 elif k == "--exclude-file": |
|
136 excludePatterns.append(v) |
|
137 elif k in ["-h", "--help"]: |
|
138 usage() |
|
139 elif k in ["-V", "--version"]: |
|
140 version() |
|
141 elif k in ["-t", "--extension"]: |
|
142 if not v.startswith("."): |
|
143 v = ".%s" % v |
|
144 extensions.append(v) |
|
145 elif k in ["--oldstyle"]: |
|
146 newStyle = False |
|
147 elif k in ["-b", "--base"]: |
|
148 basePackage = v |
|
149 elif k in ["-p", "--private"]: |
|
150 includePrivate = True |
|
151 elif k in ["-l", "--language"]: |
|
152 if v not in progLanguages: |
|
153 if v not in DocumentationTools.supportedExtensionsDictForApis.keys(): |
|
154 sys.stderr.write("Wrong language given: %s. Aborting\n" % v) |
|
155 sys.exit(1) |
|
156 else: |
|
157 progLanguages.append(v) |
|
158 |
|
159 if not args: |
|
160 usage() |
|
161 |
|
162 if outputFileName == "": |
|
163 sys.stderr.write("No output file given. Aborting\n") |
|
164 sys.exit(1) |
|
165 |
|
166 if len(progLanguages) == 0: |
|
167 progLanguages = ["Python"] |
|
168 |
|
169 for progLanguage in sorted(progLanguages): |
|
170 basename = "" |
|
171 apis = [] |
|
172 |
|
173 supportedExtensions = \ |
|
174 DocumentationTools.supportedExtensionsDictForApis[progLanguage] |
|
175 supportedExtensions.extend(extensions) |
|
176 if "%L" in outputFileName: |
|
177 outputFile = outputFileName.replace("%L", progLanguage) |
|
178 else: |
|
179 if len(progLanguages) == 1: |
|
180 outputFile = outputFileName |
|
181 else: |
|
182 root, ext = os.path.splitext(outputFileName) |
|
183 outputFile = "%s-%s%s" % (root, progLanguage.lower(), ext) |
|
184 |
|
185 for arg in args: |
|
186 if os.path.isdir(arg): |
|
187 if os.path.exists(os.path.join(arg, |
|
188 Utilities.joinext("__init__", ".py"))): |
|
189 basename = os.path.dirname(arg) |
|
190 if arg == '.': |
|
191 sys.stderr.write("The directory '.' is a package.\n") |
|
192 sys.stderr.write("Please repeat the call giving its real name.\n") |
|
193 sys.stderr.write("Ignoring the directory.\n") |
|
194 continue |
|
195 else: |
|
196 basename = arg |
|
197 if basename: |
|
198 basename = "%s%s" % (basename, os.sep) |
|
199 |
|
200 if recursive and not os.path.islink(arg): |
|
201 names = [arg] + Utilities.getDirs(arg, excludeDirs) |
|
202 else: |
|
203 names = [arg] |
|
204 else: |
|
205 basename = "" |
|
206 names = [arg] |
|
207 |
|
208 for filename in sorted(names): |
|
209 inpackage = False |
|
210 if os.path.isdir(filename): |
|
211 files = [] |
|
212 for ext in supportedExtensions: |
|
213 files.extend(glob.glob(os.path.join(filename, |
|
214 Utilities.joinext("*", ext)))) |
|
215 initFile = os.path.join(filename, |
|
216 Utilities.joinext("__init__", ext)) |
|
217 if initFile in files: |
|
218 inpackage = True |
|
219 files.remove(initFile) |
|
220 files.insert(0, initFile) |
|
221 elif progLanguage != "Python": |
|
222 # assume package |
|
223 inpackage = True |
|
224 else: |
|
225 if Utilities.isWindowsPlatform() and glob.has_magic(filename): |
|
226 files = glob.glob(filename) |
|
227 else: |
|
228 files = [filename] |
|
229 |
|
230 for file in files: |
|
231 skipIt = False |
|
232 for pattern in excludePatterns: |
|
233 if fnmatch.fnmatch(os.path.basename(file), pattern): |
|
234 skipIt = True |
|
235 break |
|
236 if skipIt: |
|
237 continue |
|
238 |
|
239 try: |
|
240 module = Utilities.ModuleParser.readModule(file, |
|
241 basename = basename, inpackage = inpackage) |
|
242 apiGenerator = APIGenerator(module) |
|
243 api = apiGenerator.genAPI(newStyle, basePackage, includePrivate) |
|
244 except IOError, v: |
|
245 sys.stderr.write("%s error: %s\n" % (file, v[1])) |
|
246 continue |
|
247 except ImportError, v: |
|
248 sys.stderr.write("%s error: %s\n" % (file, v)) |
|
249 continue |
|
250 |
|
251 for apiEntry in api: |
|
252 if not apiEntry in apis: |
|
253 apis.append(apiEntry) |
|
254 sys.stdout.write("-- %s -- %s ok\n" % (progLanguage, file)) |
|
255 |
|
256 outdir = os.path.dirname(outputFile) |
|
257 if outdir and not os.path.exists(outdir): |
|
258 os.makedirs(outdir) |
|
259 try: |
|
260 out = open(outputFile, "wb") |
|
261 out.write(os.linesep.join(sorted(apis))) |
|
262 out.close() |
|
263 except IOError, v: |
|
264 sys.stderr.write("%s error: %s\n" % (outputFile, v[1])) |
|
265 sys.exit(3) |
|
266 |
|
267 sys.stdout.write('\nDone.\n') |
|
268 sys.exit(0) |
|
269 |
|
270 if __name__ == '__main__': |
|
271 main() |