--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6_api.py Sat Jul 05 11:41:14 2014 +0200 @@ -0,0 +1,311 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2003 - 2014 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Eric5 API Generator. + +This is the main Python script of the API generator. It is +this script that gets called via the API generation interface. +This script can be used via the commandline as well. +""" + +from __future__ import unicode_literals +try: # Only for Py2 + import Utilities.compatibility_fixes # __IGNORE_WARNING__ +except (ImportError): + pass + +import glob +import os +import sys +import fnmatch + +import Utilities.ModuleParser +from DocumentationTools.APIGenerator import APIGenerator +from UI.Info import Version +import Utilities +import DocumentationTools + + +def usage(): + """ + Function to print some usage information. + + It prints a reference of all commandline parameters that may + be used and ends the application. + """ + print("eric5_api") + print() + print("Copyright (c) 2004 - 2014 Detlev Offenbach" + " <detlev@die-offenbachs.de>.") + print() + print("Usage:") + print() + print(" eric5_api [options] files...") + print() + print("where files can be either python modules, package") + print("directories or ordinary directories.") + print() + print("Options:") + print() + print(" -b name or --base=name") + print(" Use the given name as the name of the base package.") + print(" -e eol-type or --eol=eol-type") + print(" Use the given eol type to terminate lines.") + print(" Valid values are 'cr', 'lf' and 'crlf'.") + print(" --exclude-file=pattern") + print(" Specify a filename pattern of files to be excluded.") + print(" This option may be repeated multiple times.") + print(" -h or --help") + print(" Show this help and exit.") + print(" -l language or --language=language") + print(" Generate an API file for the given programming language.") + print(" Supported programming languages are:") + for lang in sorted( + DocumentationTools.supportedExtensionsDictForApis.keys()): + print(" * {0}".format(lang)) + print(" The default is 'Python3'.") + print(" This option may be repeated multiple times.") + print(" -o filename or --output=filename") + print(" Write the API information to the named file." + " A '%L' placeholder") + print(" is replaced by the language of the API file" + " (see --language).") + print(" -p or --private") + print(" Include private methods and functions.") + print(" -R, -r or --recursive") + print(" Perform a recursive search for source files.") + print(" -t ext or --extension=ext") + print(" Add the given extension to the list of file extensions.") + print(" This option may be given multiple times.") + print(" -V or --version") + print(" Show version information and exit.") + print(" -x directory or --exclude=directory") + print(" Specify a directory basename to be excluded.") + print(" This option may be repeated multiple times.") + sys.exit(1) + + +def version(): + """ + Function to show the version information. + """ + print( + """eric5_api {0}\n""" + """\n""" + """Eric5 API generator.\n""" + """\n""" + """Copyright (c) 2004 - 2014 Detlev Offenbach""" + """ <detlev@die-offenbachs.de>\n""" + """This is free software; see the LICENSE.GPL3 for copying""" + """ conditions.\n""" + """There is NO warranty; not even for MERCHANTABILITY or FITNESS""" + """ FOR A\n""" + """PARTICULAR PURPOSE.""".format(Version)) + sys.exit(1) + + +def main(): + """ + Main entry point into the application. + """ + global supportedExtensions + + import getopt + + try: + opts, args = getopt.getopt( + sys.argv[1:], "b:e:hl:o:pRrt:Vx:", + ["base=", "eol=", "exclude=", "exclude-file=", "extension=", + "help", "language=", "output=", "private", "recursive", + "version", ]) + except getopt.error: + usage() + + excludeDirs = ["CVS", ".svn", "_svn", ".ropeproject", "_ropeproject", + ".eric5project", "_eric5project", "dist", "build", "doc", + "docs"] + excludePatterns = [] + outputFileName = "" + recursive = False + basePackage = "" + includePrivate = False + progLanguages = [] + extensions = [] + newline = None + + for k, v in opts: + if k in ["-o", "--output"]: + outputFileName = v + elif k in ["-R", "-r", "--recursive"]: + recursive = True + elif k in ["-x", "--exclude"]: + excludeDirs.append(v) + elif k == "--exclude-file": + excludePatterns.append(v) + elif k in ["-h", "--help"]: + usage() + elif k in ["-V", "--version"]: + version() + elif k in ["-t", "--extension"]: + if not v.startswith("."): + v = ".{0}".format(v) + extensions.append(v) + elif k in ["-b", "--base"]: + basePackage = v + elif k in ["-p", "--private"]: + includePrivate = True + elif k in ["-l", "--language"]: + if v not in progLanguages: + if v not in \ + DocumentationTools.supportedExtensionsDictForApis: + sys.stderr.write( + "Wrong language given: {0}. Aborting\n".format(v)) + sys.exit(1) + else: + progLanguages.append(v) + elif k in ["-e", "--eol"]: + if v.lower() == "cr": + newline = '\r' + elif v.lower() == "lf": + newline = '\n' + elif v.lower() == "crlf": + newline = '\r\n' + + if not args: + usage() + + if outputFileName == "": + sys.stderr.write("No output file given. Aborting\n") + sys.exit(1) + + if len(progLanguages) == 0: + progLanguages = ["Python3"] + + for progLanguage in sorted(progLanguages): + basename = "" + apis = [] + basesDict = {} + + supportedExtensions = \ + DocumentationTools.supportedExtensionsDictForApis[progLanguage] + supportedExtensions.extend(extensions) + if "%L" in outputFileName: + outputFile = outputFileName.replace("%L", progLanguage) + else: + if len(progLanguages) == 1: + outputFile = outputFileName + else: + root, ext = os.path.splitext(outputFileName) + outputFile = "{0}-{1}{2}".format(root, progLanguage.lower(), + ext) + basesFile = os.path.splitext(outputFile)[0] + '.bas' + + for arg in args: + if os.path.isdir(arg): + if os.path.exists(os.path.join( + arg, Utilities.joinext("__init__", ".py"))): + basename = os.path.dirname(arg) + if arg == '.': + sys.stderr.write("The directory '.' is a package.\n") + sys.stderr.write( + "Please repeat the call giving its real name.\n") + sys.stderr.write("Ignoring the directory.\n") + continue + else: + basename = arg + if basename: + basename = "{0}{1}".format(basename, os.sep) + + if recursive and not os.path.islink(arg): + names = [arg] + Utilities.getDirs(arg, excludeDirs) + else: + names = [arg] + else: + basename = "" + names = [arg] + + for filename in sorted(names): + inpackage = False + if os.path.isdir(filename): + files = [] + for ext in supportedExtensions: + files.extend(glob.glob(os.path.join( + filename, Utilities.joinext("*", ext)))) + initFile = os.path.join( + filename, Utilities.joinext("__init__", ext)) + if initFile in files: + inpackage = True + files.remove(initFile) + files.insert(0, initFile) + elif progLanguage != "Python3": + # assume package + inpackage = True + else: + if Utilities.isWindowsPlatform() and \ + glob.has_magic(filename): + files = glob.glob(filename) + else: + files = [filename] + + for file in files: + skipIt = False + for pattern in excludePatterns: + if fnmatch.fnmatch(os.path.basename(file), pattern): + skipIt = True + break + if skipIt: + continue + + try: + module = Utilities.ModuleParser.readModule( + file, + basename=basename, inpackage=inpackage) + apiGenerator = APIGenerator(module) + api = apiGenerator.genAPI(True, basePackage, + includePrivate) + bases = apiGenerator.genBases(includePrivate) + except IOError as v: + sys.stderr.write("{0} error: {1}\n".format(file, v[1])) + continue + except ImportError as v: + sys.stderr.write("{0} error: {1}\n".format(file, v)) + continue + + for apiEntry in api: + if apiEntry not in apis: + apis.append(apiEntry) + for basesEntry in bases: + if bases[basesEntry]: + basesDict[basesEntry] = bases[basesEntry][:] + sys.stdout.write("-- {0} -- {1} ok\n".format( + progLanguage, file)) + + outdir = os.path.dirname(outputFile) + if outdir and not os.path.exists(outdir): + os.makedirs(outdir) + try: + out = open(outputFile, "w", encoding="utf-8", newline=newline) + out.write("\n".join(sorted(apis)) + "\n") + out.close() + except IOError as v: + sys.stderr.write("{0} error: {1}\n".format(outputFile, v[1])) + sys.exit(3) + try: + out = open(basesFile, "w", encoding="utf-8", newline=newline) + for baseEntry in sorted(basesDict.keys()): + out.write("{0} {1}\n".format( + baseEntry, " ".join(sorted(basesDict[baseEntry])))) + out.close() + except IOError as v: + sys.stderr.write("{0} error: {1}\n".format(basesFile, v[1])) + sys.exit(3) + + sys.stdout.write('\nDone.\n') + sys.exit(0) + +if __name__ == '__main__': + main()