diff --git a/bin/generate.py b/bin/generate.py index b45bedd..6df776e 100644 --- a/bin/generate.py +++ b/bin/generate.py @@ -5,7 +5,7 @@ import sys, os.path from optparse import OptionParser from appy.gen.generator import GeneratorError, ZopeGenerator from appy.shared.utils import LinesCounter -from appy.shared.packaging import Debianizer +from appy.shared.packaging import Debianizer, Cortexer import appy.version # ------------------------------------------------------------------------------ @@ -34,6 +34,9 @@ S_OPTION = 'Sorts all i18n labels. If you use this option, among the ' \ 'set of translation files.' D_OPTION = 'Generates a Debian package for this app. The Debian package will ' \ 'be generated at the same level as the root application folder.' +X_OPTION = 'Generates a Cortex application definition for this app, in a ' \ + 'folder "cortex.admin" that will be generated at the same level ' \ + 'as the root application folder.' class GeneratorScript: '''usage: %prog [options] app @@ -68,6 +71,8 @@ class GeneratorScript: dest='i18nSort', default=False, help=S_OPTION) optParser.add_option("-d", "--debian", action='store_true', dest='debian', default=False, help=D_OPTION) + optParser.add_option("-x", "--cortex", action='store_true', + dest='cortex', default=False, help=X_OPTION) (options, args) = optParser.parse_args() try: self.manageArgs(optParser, options, args) @@ -87,6 +92,9 @@ class GeneratorScript: f.close() version = version[:version.find('build')-1] Debianizer(app, appDir, appVersion=version).run() + # Generates a Cortex application definition if required + if options.cortex: + Cortexer(args[0]).run() except GeneratorError, ge: sys.stderr.write(str(ge)) sys.stderr.write('\n') diff --git a/bin/new.py b/bin/new.py index c81a6eb..749a04a 100644 --- a/bin/new.py +++ b/bin/new.py @@ -121,7 +121,7 @@ class ZopeInstanceCreator: os.mkdir('etc') f = file('etc/zope.conf', 'w') f.write(zopeConf % (self.instancePath, '%s/var' % self.instancePath, - '%s/log' % self.instancePath, '')) + '%s/log' % self.instancePath, '8080', '')) f.close() # Create other folders for name in ('Extensions', 'log', 'Products', 'var'): os.mkdir(name) diff --git a/shared/packaging.py b/shared/packaging.py index b903129..5078c70 100644 --- a/shared/packaging.py +++ b/shared/packaging.py @@ -1,5 +1,5 @@ # ------------------------------------------------------------------------------ -import os, os.path, subprocess, md5, shutil +import os, os.path, subprocess, md5, shutil, random from appy.shared.utils import getOsTempFolder, FolderDeleter, cleanFolder # ------------------------------------------------------------------------------ @@ -31,7 +31,7 @@ zopeConf = '''# Zope configuration. %%define INSTANCE %s %%define DATA %s %%define LOG %s -%%define HTTPPORT 8080 +%%define HTTPPORT %s %%define ZOPE_USER zope instancehome $INSTANCE @@ -106,7 +106,7 @@ class Debianizer: package.''' def __init__(self, app, out, appVersion='0.1.0', - pythonVersions=('2.6',), + pythonVersions=('2.6',), zopePort=8080, depends=('zope2.12', 'openoffice.org', 'imagemagick')): # app is the path to the Python package to Debianize. self.app = app @@ -118,6 +118,8 @@ class Debianizer: self.appVersion = appVersion # On which Python versions will the Debian package depend? self.pythonVersions = pythonVersions + # Port for Zope + self.zopePort = zopePort # Debian package dependencies self.depends = depends # Zope 2.12 requires Python 2.6 @@ -189,7 +191,7 @@ class Debianizer: productsFolder = '/usr/lib/python%s/%s/zope' % \ (self.pythonVersions[0], self.appName) f.write(zopeConf % ('/var/lib/%s' % n, '/var/lib/%s' % n, - '/var/log/%s' % n, + '/var/log/%s' % n, str(self.zopePort), 'products %s\n' % productsFolder)) f.close() # /etc/init.d/ (start the app at boot time) @@ -305,4 +307,90 @@ class Debianizer: # Clean temp files FolderDeleter.delete(debFolder) os.chdir(curdir) + +# ------------------------------------------------------------------------------ +definitionJson = '''{ + "name": "%s", + "description": "%s, a Appy-based application", + "packages": [{"name": "python-appy" }, {"name": "python-appy-%s" }], + "files": [ + { "group": "root", "mode": "644", "name": "%s.conf", + "owner": "root", "path": "/etc/%s.conf", + "template": "%s" + }], + "handlers": [ + { "on": ["_install"] }, + { "on": ["_uninstall" ] }, + { "on": ["%s_http_port"], + "do": [ + { "action": "update", "resource": "file://%s.conf" }, + { "action": "restart", "resource": "service://%s" } + ]}, + ], + "services": [ + { "name": "%s", "enabled": "true", "running": "false" }, + { "name": "oo", "enabled": "true", "running": "false" }], +} +''' +definitionJsonConf = '''{ + "name": "%s.conf", + "uuid": "%s", + "parameters": [ + { "key": "%s_http_port", "name": "%s HTTP port", + "description": "%s HTTP port for the Zope process", + "value": "8080"} + ], +} +''' + +class Cortexer: + '''This class allows to produce a Cortex application definition for + a Debianized Python/Appy application.''' + def __init__(self, app, pythonVersions=('2.6',)): + self.appName = os.path.basename(app) + self.pythonVersions = pythonVersions + appFolder = os.path.dirname(app) + # Prepare the output folder (remove any existing one) + cortexFolder = os.path.join(appFolder, 'cortex.admin') + if os.path.exists(cortexFolder): + FolderDeleter.delete(cortexFolder) + allFolders = os.path.join(cortexFolder, 'applications', self.appName) + os.makedirs(allFolders) + self.out = allFolders + + uuidChars= ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'] + def generateUid(self): + '''Generates a 32-chars-wide UID for identifying the configuration file + in the Cortex DB.''' + res = '' + for i in range(32): + res += self.uuidChars[random.randint(0,15)] + return res + + def run(self): + # Create the root app description file "definition.json". + uid = self.generateUid() + name = os.path.join(self.out, 'definition.json') + f = file(name, 'w') + n = self.appName + nl = self.appName.lower() + f.write(definitionJson % (n, n, nl, nl, nl, uid, nl, nl, nl, nl)) + f.close() + # Create the folder corresponding to the config file, and its content. + confFolder = os.path.join(self.out, '%s.conf' % nl) + os.mkdir(confFolder) + # Create the definition file for this config file, that will contain + # the names of Cortex-managed variables within the configuration file. + name = os.path.join(confFolder, 'definition.json') + f = file(name, 'w') + f.write(definitionJsonConf % (nl, uid, nl, n, n)) + f.close() + # Create the Zope config file, with Cortex-like variables within in. + name = os.path.join(confFolder, '%s.conf' % nl) + f = file(name, 'w') + productsFolder='/usr/lib/python%s/%s/zope' % (self.pythonVersions[0],n) + f.write(zopeConf % ('/var/lib/%s' % n, '/var/lib/%s' % n, + '/var/log/%s' % n, '${%s_http_port}' % nl, + 'products %s\n' % productsFolder)) + f.close() # ------------------------------------------------------------------------------