'''This script allows to generate a product from a Appy application.''' # ------------------------------------------------------------------------------ import sys, os.path from optparse import OptionParser from appy.gen.generator import GeneratorError from appy.shared.utils import LinesCounter # ------------------------------------------------------------------------------ ERROR_CODE = 1 VALID_PRODUCT_TYPES = ('plone25', 'odt') APP_NOT_FOUND = 'Application not found at %s.' WRONG_NG_OF_ARGS = 'Wrong number of arguments.' WRONG_OUTPUT_FOLDER = 'Output folder not found. Please create it first.' PRODUCT_TYPE_ERROR = 'Wrong product type. Product type may be one of the ' \ 'following: %s' % str(VALID_PRODUCT_TYPES) C_OPTION = 'Removes from i18n files all labels that are not automatically ' \ 'generated from your gen-application. It can be useful during ' \ 'development, when you do lots of name changes (classes, ' \ 'attributes, states, transitions, etc): in this case, the Appy ' \ 'i18n label generation machinery produces lots of labels that ' \ 'then become obsolete.' S_OPTION = 'Sorts all i18n labels. If you use this option, among the ' \ 'generated i18n files, you will find first all labels ' \ 'that are automatically generated by appy.gen, in some logical ' \ 'order (ie: field-related labels appear together, in the order ' \ 'they are declared in the gen-class). Then, if you have added ' \ 'labels manually, they will appear afterwards. Sorting labels ' \ 'may not be desired under development. Indeed, when no sorting ' \ 'occurs, every time you add or modify a field, class, state, etc, ' \ 'newly generated labels will all appear together at the end of ' \ 'the file; so it will be easy to translate them all. When sorting ' \ 'occurs, those elements may be spread at different places in the ' \ 'i18n file. When the development is finished, it may be a good ' \ 'idea to sort the labels to get a clean and logically ordered ' \ 'set of translation files.' class GeneratorScript: '''usage: %prog [options] app productType outputFolder "app" is the path to your Appy application, which may be a Python module (= a file than ends with .py) or a Python package (= a folder containing a file named __init__.py). Your app may reside anywhere (but it needs to be accessible by the underlying application server, ie Zope), excepted within the generated product. Typically, if you generate a Plone product, it may reside within /lib/python, but not within the generated product (typically stored in /Products). "productType" is the kind of product you want to generate (currently, only "plone25" and 'odt' are supported; in the near future, the "plone25" target will also produce Plone 3-compliant code that will still work with Plone 2.5). "outputFolder" is the folder where the product will be generated. For example, if you specify /my/output/folder for your application /home/gde/MyApp.py, this script will create a folder /my/output/folder/MyApp and put in it the generated product. Example: generating a Plone product ----------------------------------- In your Zope instance named myZopeInstance, create a folder "myZopeInstance/lib/python/MyApp". Create into it your Appy application (we suppose here that it is a Python package, containing a __init__.py file and other files). Then, chdir into this folder and type "python /gen/generator.py . plone25 ../../../Products" and the product will be generated in myZopeInstance/Products/MyApp. "python" must refer to a Python interpreter that knows package appy.''' def generateProduct(self, options, application, productType, outputFolder): exec 'from appy.gen.%s.generator import Generator' % productType Generator(application, outputFolder, options).run() def manageArgs(self, parser, options, args): # Check number of args if len(args) != 3: print WRONG_NG_OF_ARGS parser.print_help() sys.exit(ERROR_CODE) # Check productType if args[1] not in VALID_PRODUCT_TYPES: print PRODUCT_TYPE_ERROR sys.exit(ERROR_CODE) # Check existence of application if not os.path.exists(args[0]): print APP_NOT_FOUND % args[0] sys.exit(ERROR_CODE) # Check existence of outputFolder basic type if not os.path.exists(args[2]): print WRONG_OUTPUT_FOLDER sys.exit(ERROR_CODE) # Convert all paths in absolute paths for i in (0,2): args[i] = os.path.abspath(args[i]) def run(self): optParser = OptionParser(usage=GeneratorScript.__doc__) optParser.add_option("-c", "--i18n-clean", action='store_true', dest='i18nClean', default=False, help=C_OPTION) optParser.add_option("-s", "--i18n-sort", action='store_true', dest='i18nSort', default=False, help=S_OPTION) (options, args) = optParser.parse_args() try: self.manageArgs(optParser, options, args) print 'Generating %s product in %s...' % (args[1], args[2]) self.generateProduct(options, *args) # Give the user some statistics about its code LinesCounter(args[0]).run() except GeneratorError, ge: sys.stderr.write(str(ge)) sys.stderr.write('\n') optParser.print_help() sys.exit(ERROR_CODE) # ------------------------------------------------------------------------------ if __name__ == '__main__': GeneratorScript().run() # ------------------------------------------------------------------------------