appy.shared: improved deployment of a Appy app (creation of a Zope instance is no more required; corresponding folders are created in standard unix locations: /etc for the config file, /var/log for logs, /var/lib for the database, /usr/bin for scripts that start and stop the instance). appy.gen: first draft of a migration script that allows to migrate data from Plone-dependent Appy apps (<= 0.7.1) to Ploneless Appy 0.8.0.
This commit is contained in:
		
							parent
							
								
									95a899f3de
								
							
						
					
					
						commit
						1275df5753
					
				
					 13 changed files with 351 additions and 161 deletions
				
			
		| 
						 | 
					@ -80,8 +80,9 @@ class GeneratorScript:
 | 
				
			||||||
            if options.debian:
 | 
					            if options.debian:
 | 
				
			||||||
                app = args[0]
 | 
					                app = args[0]
 | 
				
			||||||
                appDir = os.path.dirname(app)
 | 
					                appDir = os.path.dirname(app)
 | 
				
			||||||
 | 
					                appName = os.path.basename(app)
 | 
				
			||||||
                # Get the app version from zope/version.txt
 | 
					                # Get the app version from zope/version.txt
 | 
				
			||||||
                f = file(os.path.join(app, 'zope', 'version.txt'))
 | 
					                f = file(os.path.join(app, 'zope', appName, 'version.txt'))
 | 
				
			||||||
                version = f.read()
 | 
					                version = f.read()
 | 
				
			||||||
                f.close()
 | 
					                f.close()
 | 
				
			||||||
                version = version[:version.find('build')-1]
 | 
					                version = version[:version.find('build')-1]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								bin/new.py
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								bin/new.py
									
										
									
									
									
								
							| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
import os, os.path, sys, shutil, re
 | 
					import os, os.path, sys, shutil, re
 | 
				
			||||||
from optparse import OptionParser
 | 
					from optparse import OptionParser
 | 
				
			||||||
from appy.shared.utils import cleanFolder, copyFolder
 | 
					from appy.shared.utils import cleanFolder, copyFolder
 | 
				
			||||||
 | 
					from appy.shared.packaging import ooStart, zopeConf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class NewError(Exception): pass
 | 
					class NewError(Exception): pass
 | 
				
			||||||
| 
						 | 
					@ -34,7 +35,7 @@ exec "$ZDCTL" -C "$CONFIG_FILE" "$@"
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# runzope template file for a pure Zope instance -------------------------------
 | 
					# runzope template file for a pure Zope instance -------------------------------
 | 
				
			||||||
runZope = '''#! /bin/sh
 | 
					runZope = '''#!/bin/sh
 | 
				
			||||||
INSTANCE_HOME="%s"
 | 
					INSTANCE_HOME="%s"
 | 
				
			||||||
CONFIG_FILE="$INSTANCE_HOME/etc/zope.conf"
 | 
					CONFIG_FILE="$INSTANCE_HOME/etc/zope.conf"
 | 
				
			||||||
ZOPE_RUN="/usr/lib/zope2.12/bin/runzope"
 | 
					ZOPE_RUN="/usr/lib/zope2.12/bin/runzope"
 | 
				
			||||||
| 
						 | 
					@ -42,46 +43,6 @@ export INSTANCE_HOME
 | 
				
			||||||
exec "$ZOPE_RUN" -C "$CONFIG_FILE" "$@"
 | 
					exec "$ZOPE_RUN" -C "$CONFIG_FILE" "$@"
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# zope.conf template file for a pure Zope instance -----------------------------
 | 
					 | 
				
			||||||
zopeConf = '''# Zope configuration.
 | 
					 | 
				
			||||||
%%define INSTANCE %s
 | 
					 | 
				
			||||||
%%define HTTPPORT 8080
 | 
					 | 
				
			||||||
%%define ZOPE_USER zope
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
instancehome $INSTANCE
 | 
					 | 
				
			||||||
effective-user $ZOPE_USER
 | 
					 | 
				
			||||||
<eventlog>
 | 
					 | 
				
			||||||
  level info
 | 
					 | 
				
			||||||
  <logfile>
 | 
					 | 
				
			||||||
    path $INSTANCE/log/event.log
 | 
					 | 
				
			||||||
    level info
 | 
					 | 
				
			||||||
  </logfile>
 | 
					 | 
				
			||||||
</eventlog>
 | 
					 | 
				
			||||||
<logger access>
 | 
					 | 
				
			||||||
  level WARN
 | 
					 | 
				
			||||||
  <logfile>
 | 
					 | 
				
			||||||
    path $INSTANCE/log/Z2.log
 | 
					 | 
				
			||||||
    format %%(message)s
 | 
					 | 
				
			||||||
  </logfile>
 | 
					 | 
				
			||||||
</logger>
 | 
					 | 
				
			||||||
<http-server>
 | 
					 | 
				
			||||||
  address $HTTPPORT
 | 
					 | 
				
			||||||
</http-server>
 | 
					 | 
				
			||||||
<zodb_db main>
 | 
					 | 
				
			||||||
  <filestorage>
 | 
					 | 
				
			||||||
    path $INSTANCE/var/Data.fs
 | 
					 | 
				
			||||||
  </filestorage>
 | 
					 | 
				
			||||||
  mount-point /
 | 
					 | 
				
			||||||
</zodb_db>
 | 
					 | 
				
			||||||
<zodb_db temporary>
 | 
					 | 
				
			||||||
  <temporarystorage>
 | 
					 | 
				
			||||||
   name temporary storage for sessioning
 | 
					 | 
				
			||||||
  </temporarystorage>
 | 
					 | 
				
			||||||
  mount-point /temp_folder
 | 
					 | 
				
			||||||
  container-class Products.TemporaryFolder.TemporaryContainer
 | 
					 | 
				
			||||||
</zodb_db>
 | 
					 | 
				
			||||||
'''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# zopectl template for a Plone (4) Zope instance -------------------------------
 | 
					# zopectl template for a Plone (4) Zope instance -------------------------------
 | 
				
			||||||
zopeCtlPlone = '''#!/bin/sh
 | 
					zopeCtlPlone = '''#!/bin/sh
 | 
				
			||||||
PYTHON="%s"
 | 
					PYTHON="%s"
 | 
				
			||||||
| 
						 | 
					@ -153,14 +114,14 @@ class ZopeInstanceCreator:
 | 
				
			||||||
        os.chmod('bin/runzope', 0744) # Make it executable by owner.
 | 
					        os.chmod('bin/runzope', 0744) # Make it executable by owner.
 | 
				
			||||||
        # Create bin/startoo
 | 
					        # Create bin/startoo
 | 
				
			||||||
        f = file('bin/startoo', 'w')
 | 
					        f = file('bin/startoo', 'w')
 | 
				
			||||||
        f.write('#!/bin/sh\nsoffice -invisible -headless -nofirststartwizard '\
 | 
					        f.write(ooStart)
 | 
				
			||||||
                '"-accept=socket,host=localhost,port=2002;urp;"&\n')
 | 
					 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
        os.chmod('bin/startoo', 0744) # Make it executable by owner.
 | 
					        os.chmod('bin/startoo', 0744) # Make it executable by owner.
 | 
				
			||||||
        # Create etc/zope.conf
 | 
					        # Create etc/zope.conf
 | 
				
			||||||
        os.mkdir('etc')
 | 
					        os.mkdir('etc')
 | 
				
			||||||
        f = file('etc/zope.conf', 'w')
 | 
					        f = file('etc/zope.conf', 'w')
 | 
				
			||||||
        f.write(zopeConf % self.instancePath)
 | 
					        f.write(zopeConf % (self.instancePath, '%s/var' % self.instancePath,
 | 
				
			||||||
 | 
					                            '%s/log' % self.instancePath, ''))
 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
        # Create other folders
 | 
					        # Create other folders
 | 
				
			||||||
        for name in ('Extensions', 'log', 'Products', 'var'): os.mkdir(name)
 | 
					        for name in ('Extensions', 'log', 'Products', 'var'): os.mkdir(name)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -424,7 +424,7 @@ class Publisher:
 | 
				
			||||||
        f.write(toc)
 | 
					        f.write(toc)
 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    privateScripts = ('publish.py', 'zip.py', 'runOpenOffice.sh')
 | 
					    privateScripts = ('publish.py', 'zip.py', 'startoo.sh')
 | 
				
			||||||
    def prepareGenFolder(self, minimalist=False):
 | 
					    def prepareGenFolder(self, minimalist=False):
 | 
				
			||||||
        '''Creates the basic structure of the temp folder where the appy
 | 
					        '''Creates the basic structure of the temp folder where the appy
 | 
				
			||||||
           website will be generated.'''
 | 
					           website will be generated.'''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								bin/zopectl.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								bin/zopectl.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					import sys, os, os.path
 | 
				
			||||||
 | 
					import Zope2.Startup.zopectl as zctl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class ZopeRunner:
 | 
				
			||||||
 | 
					    '''This class allows to run a Appy/Zope instance.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        # Check that an arg has been given (start, stop, fg, run)
 | 
				
			||||||
 | 
					        if not sys.argv[3].strip():
 | 
				
			||||||
 | 
					            print 'Argument required.'
 | 
				
			||||||
 | 
					            sys.exit(-1)
 | 
				
			||||||
 | 
					        # Identify the name of the application for which Zope must run.
 | 
				
			||||||
 | 
					        app = os.path.splitext(os.path.basename(sys.argv[2]))[0].lower()
 | 
				
			||||||
 | 
					        # Launch Zope.
 | 
				
			||||||
 | 
					        options = zctl.ZopeCtlOptions()
 | 
				
			||||||
 | 
					        options.realize(None)
 | 
				
			||||||
 | 
					        options.program = ['/usr/bin/%srun' % app]
 | 
				
			||||||
 | 
					        c = zctl.ZopeCmd(options)
 | 
				
			||||||
 | 
					        c.onecmd(" ".join(options.args))
 | 
				
			||||||
 | 
					        return min(c._exitstatus, 1)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,8 @@ class Generator:
 | 
				
			||||||
        # Determine application name
 | 
					        # Determine application name
 | 
				
			||||||
        self.applicationName = os.path.basename(application)
 | 
					        self.applicationName = os.path.basename(application)
 | 
				
			||||||
        # Determine output folder (where to store the generated product)
 | 
					        # Determine output folder (where to store the generated product)
 | 
				
			||||||
        self.outputFolder = os.path.join(application, 'zope')
 | 
					        self.outputFolder = os.path.join(application, 'zope',
 | 
				
			||||||
 | 
					                                         self.applicationName)
 | 
				
			||||||
        self.options = options
 | 
					        self.options = options
 | 
				
			||||||
        # Determine templates folder
 | 
					        # Determine templates folder
 | 
				
			||||||
        genFolder = os.path.dirname(__file__)
 | 
					        genFolder = os.path.dirname(__file__)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import appy.version
 | 
				
			||||||
import appy.gen as gen
 | 
					import appy.gen as gen
 | 
				
			||||||
from appy.gen.po import PoParser
 | 
					from appy.gen.po import PoParser
 | 
				
			||||||
from appy.gen.utils import updateRolesForPermission, createObject
 | 
					from appy.gen.utils import updateRolesForPermission, createObject
 | 
				
			||||||
 | 
					from appy.gen.migrator import Migrator
 | 
				
			||||||
from appy.shared.data import languages
 | 
					from appy.shared.data import languages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -87,14 +88,16 @@ class ZopeInstaller:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installUi(self):
 | 
					    def installUi(self):
 | 
				
			||||||
        '''Installs the user interface.'''
 | 
					        '''Installs the user interface.'''
 | 
				
			||||||
        # Delete the existing folder if it existed.
 | 
					 | 
				
			||||||
        zopeContent = self.app.objectIds()
 | 
					 | 
				
			||||||
        if 'ui' in zopeContent: self.app.manage_delObjects(['ui'])
 | 
					 | 
				
			||||||
        self.app.manage_addFolder('ui')
 | 
					 | 
				
			||||||
        # Some useful imports
 | 
					        # Some useful imports
 | 
				
			||||||
 | 
					        from OFS.Folder import manage_addFolder
 | 
				
			||||||
 | 
					        from OFS.Image import manage_addImage, manage_addFile
 | 
				
			||||||
        from Products.PythonScripts.PythonScript import PythonScript
 | 
					        from Products.PythonScripts.PythonScript import PythonScript
 | 
				
			||||||
        from Products.PageTemplates.ZopePageTemplate import \
 | 
					        from Products.PageTemplates.ZopePageTemplate import \
 | 
				
			||||||
             manage_addPageTemplate
 | 
					             manage_addPageTemplate
 | 
				
			||||||
 | 
					        # Delete the existing folder if it existed.
 | 
				
			||||||
 | 
					        zopeContent = self.app.objectIds()
 | 
				
			||||||
 | 
					        if 'ui' in zopeContent: self.app.manage_delObjects(['ui'])
 | 
				
			||||||
 | 
					        manage_addFolder(self.app, 'ui')
 | 
				
			||||||
        # Browse the physical folder and re-create it in the Zope folder
 | 
					        # Browse the physical folder and re-create it in the Zope folder
 | 
				
			||||||
        j = os.path.join
 | 
					        j = os.path.join
 | 
				
			||||||
        ui = j(j(appy.getPath(), 'gen'), 'ui')
 | 
					        ui = j(j(appy.getPath(), 'gen'), 'ui')
 | 
				
			||||||
| 
						 | 
					@ -106,13 +109,13 @@ class ZopeInstaller:
 | 
				
			||||||
                for name in folderName.strip(os.sep).split(os.sep):
 | 
					                for name in folderName.strip(os.sep).split(os.sep):
 | 
				
			||||||
                    zopeFolder = zopeFolder._getOb(name)
 | 
					                    zopeFolder = zopeFolder._getOb(name)
 | 
				
			||||||
            # Create sub-folders at this level
 | 
					            # Create sub-folders at this level
 | 
				
			||||||
            for name in dirs: zopeFolder.manage_addFolder(name)
 | 
					            for name in dirs: manage_addFolder(zopeFolder, name)
 | 
				
			||||||
            # Create files at this level
 | 
					            # Create files at this level
 | 
				
			||||||
            for name in files:
 | 
					            for name in files:
 | 
				
			||||||
                baseName, ext = os.path.splitext(name)
 | 
					                baseName, ext = os.path.splitext(name)
 | 
				
			||||||
                f = file(j(root, name))
 | 
					                f = file(j(root, name))
 | 
				
			||||||
                if ext in gen.File.imageExts:
 | 
					                if ext in gen.File.imageExts:
 | 
				
			||||||
                    zopeFolder.manage_addImage(name, f)
 | 
					                    manage_addImage(zopeFolder, name, f)
 | 
				
			||||||
                elif ext == '.pt':
 | 
					                elif ext == '.pt':
 | 
				
			||||||
                    manage_addPageTemplate(zopeFolder, baseName, '', f.read())
 | 
					                    manage_addPageTemplate(zopeFolder, baseName, '', f.read())
 | 
				
			||||||
                elif ext == '.py':
 | 
					                elif ext == '.py':
 | 
				
			||||||
| 
						 | 
					@ -120,7 +123,7 @@ class ZopeInstaller:
 | 
				
			||||||
                    zopeFolder._setObject(baseName, obj)
 | 
					                    zopeFolder._setObject(baseName, obj)
 | 
				
			||||||
                    zopeFolder._getOb(baseName).write(f.read())
 | 
					                    zopeFolder._getOb(baseName).write(f.read())
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    zopeFolder.manage_addFile(name, f)
 | 
					                    manage_addFile(zopeFolder, name, f)
 | 
				
			||||||
                f.close()
 | 
					                f.close()
 | 
				
			||||||
        # Update the home page
 | 
					        # Update the home page
 | 
				
			||||||
        if 'index_html' in zopeContent:
 | 
					        if 'index_html' in zopeContent:
 | 
				
			||||||
| 
						 | 
					@ -199,9 +202,10 @@ class ZopeInstaller:
 | 
				
			||||||
        '''Creates the tool and the root data folder if they do not exist.'''
 | 
					        '''Creates the tool and the root data folder if they do not exist.'''
 | 
				
			||||||
        # Create or update the base folder for storing data
 | 
					        # Create or update the base folder for storing data
 | 
				
			||||||
        zopeContent = self.app.objectIds()
 | 
					        zopeContent = self.app.objectIds()
 | 
				
			||||||
 | 
					        from OFS.Folder import manage_addFolder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if 'data' not in zopeContent:
 | 
					        if 'data' not in zopeContent:
 | 
				
			||||||
            self.app.manage_addFolder('data')
 | 
					            manage_addFolder(self.app, 'data')
 | 
				
			||||||
            data = self.app.data
 | 
					            data = self.app.data
 | 
				
			||||||
            # Manager has been granted Add permissions for all root classes.
 | 
					            # Manager has been granted Add permissions for all root classes.
 | 
				
			||||||
            # This may not be desired, so remove this.
 | 
					            # This may not be desired, so remove this.
 | 
				
			||||||
| 
						 | 
					@ -240,7 +244,13 @@ class ZopeInstaller:
 | 
				
			||||||
        appyTool.log('Appy version is "%s".' % appy.version.short)
 | 
					        appyTool.log('Appy version is "%s".' % appy.version.short)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create the admin user if no user exists.
 | 
					        # Create the admin user if no user exists.
 | 
				
			||||||
        if not self.app.acl_users.getUsers():
 | 
					        try:
 | 
				
			||||||
 | 
					            users = self.app.acl_users.getUsers()
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            # When Plone has installed PAS in acl_users this may fail. Plone
 | 
				
			||||||
 | 
					            # may still be in the way for migration purposes.
 | 
				
			||||||
 | 
					            users = ('admin') # We suppose there is at least a user.
 | 
				
			||||||
 | 
					        if not users:
 | 
				
			||||||
            self.app.acl_users._doAddUser('admin', 'admin', ['Manager'], ())
 | 
					            self.app.acl_users._doAddUser('admin', 'admin', ['Manager'], ())
 | 
				
			||||||
            appyTool.log('Admin user "admin" created.')
 | 
					            appyTool.log('Admin user "admin" created.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -399,6 +409,10 @@ class ZopeInstaller:
 | 
				
			||||||
        self.installCatalog()
 | 
					        self.installCatalog()
 | 
				
			||||||
        self.installTool()
 | 
					        self.installTool()
 | 
				
			||||||
        self.installUi()
 | 
					        self.installUi()
 | 
				
			||||||
 | 
					        # Perform migrations if required
 | 
				
			||||||
 | 
					        Migrator(self).run()
 | 
				
			||||||
 | 
					        # Update Appy version in the database
 | 
				
			||||||
 | 
					        self.app.config.appy().appyVersion = appy.version.short
 | 
				
			||||||
        # Empty the fake REQUEST object, only used at Zope startup.
 | 
					        # Empty the fake REQUEST object, only used at Zope startup.
 | 
				
			||||||
        del self.app.config.getProductConfig().fakeRequest.wrappers
 | 
					        del self.app.config.getProductConfig().fakeRequest.wrappers
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										159
									
								
								gen/migrator.py
									
										
									
									
									
								
							
							
						
						
									
										159
									
								
								gen/migrator.py
									
										
									
									
									
								
							| 
						 | 
					@ -7,56 +7,125 @@ class Migrator:
 | 
				
			||||||
       installation, we've detected a new Appy version.'''
 | 
					       installation, we've detected a new Appy version.'''
 | 
				
			||||||
    def __init__(self, installer):
 | 
					    def __init__(self, installer):
 | 
				
			||||||
        self.installer = installer
 | 
					        self.installer = installer
 | 
				
			||||||
 | 
					        self.logger = installer.logger
 | 
				
			||||||
 | 
					        self.app = installer.app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def migrateTo_0_7_1(self):
 | 
					    bypassRoles = ('Authenticated', 'Member')
 | 
				
			||||||
        '''Appy 0.7.1 has its own management of Ref fields. So we must
 | 
					    bypassGroups = ('Administrators', 'Reviewers')
 | 
				
			||||||
           update data structures that store Ref info on instances.'''
 | 
					    def migrateUsers(self, ploneSite):
 | 
				
			||||||
        ins = self.installer
 | 
					        '''Migrate users from Plone's acl_users to Zope acl_users with
 | 
				
			||||||
        ins.info('Migrating to Appy 0.7.1...')
 | 
					           corresponding Appy objects.'''
 | 
				
			||||||
        allClassNames = [ins.tool.__class__.__name__] + ins.config.allClassNames
 | 
					        # First of all, remove the Plone-patched root acl_users by a standard
 | 
				
			||||||
        for className in allClassNames:
 | 
					        # (hum, Appy-patched) Zope UserFolder.
 | 
				
			||||||
            i = -1
 | 
					        tool = self.app.config.appy()
 | 
				
			||||||
            updated = 0
 | 
					        from AccessControl.User import manage_addUserFolder
 | 
				
			||||||
            ins.info('Analysing class "%s"...' % className)
 | 
					        self.app.manage_delObjects(ids=['acl_users'])
 | 
				
			||||||
            refFields = None
 | 
					        manage_addUserFolder(self.app)
 | 
				
			||||||
            for obj in ins.tool.executeQuery(className,\
 | 
					        # Put an admin user into it
 | 
				
			||||||
                                             noSecurity=True)['objects']:
 | 
					        newUsersDb = self.app.acl_users
 | 
				
			||||||
                i += 1
 | 
					        newUsersDb._doAddUser('admin', 'admin', ['Manager'], ())
 | 
				
			||||||
                if i == 0:
 | 
					        # Copy users from Plone acl_users to Zope acl_users
 | 
				
			||||||
                    # Get the Ref fields for objects of this class
 | 
					        for user in ploneSite.acl_users.getUsers():
 | 
				
			||||||
                    refFields = [f for f in obj.getAllAppyTypes() \
 | 
					            id = user.getId()
 | 
				
			||||||
                                 if (f.type == 'Ref') and not f.isBack]
 | 
					            userRoles = user.getRoles()
 | 
				
			||||||
                    if refFields:
 | 
					            for br in self.bypassRoles:
 | 
				
			||||||
                        refNames = ', '.join([rf.name for rf in refFields])
 | 
					                if br in userRoles: userRoles.remove(br)
 | 
				
			||||||
                        ins.info('  Ref fields found: %s' % refNames)
 | 
					            userInfo = ploneSite.portal_membership.getMemberById(id)
 | 
				
			||||||
 | 
					            userName = userInfo.getProperty('fullname') or id
 | 
				
			||||||
 | 
					            userEmail = userInfo.getProperty('email') or ''
 | 
				
			||||||
 | 
					            appyUser = tool.create('users', login=id,
 | 
				
			||||||
 | 
					                password1='fake', password2='fake', roles=userRoles,
 | 
				
			||||||
 | 
					                name=userName, firstName=' ', email=userEmail)
 | 
				
			||||||
 | 
					            appyUser.title = appyUser.title.strip()
 | 
				
			||||||
 | 
					            # Set the correct password
 | 
				
			||||||
 | 
					            password = ploneSite.acl_users.source_users._user_passwords[id]
 | 
				
			||||||
 | 
					            newUsersDb.data[id].__ = password
 | 
				
			||||||
 | 
					            # Manage groups. Exclude not-used default Plone groups.
 | 
				
			||||||
 | 
					            for groupId in user.getGroups():
 | 
				
			||||||
 | 
					                if groupId in self.bypassGroups: continue
 | 
				
			||||||
 | 
					                if tool.count('Group', login=groupId):
 | 
				
			||||||
 | 
					                    # The Appy group already exists, get it
 | 
				
			||||||
 | 
					                    appyGroup = tool.search('Group', login=groupId)[0]
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                        ins.info('  No Ref field found.')
 | 
					                    # Create the group. Todo: get Plone group roles and title
 | 
				
			||||||
 | 
					                    appyGroup = tool.create('groups', login=groupId,
 | 
				
			||||||
 | 
					                                            title=groupId)
 | 
				
			||||||
 | 
					                appyGroup.addUser(appyUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reindexObject(self, obj):
 | 
				
			||||||
 | 
					        obj.reindex()
 | 
				
			||||||
 | 
					        i = 1
 | 
				
			||||||
 | 
					        for subObj in obj.objectValues():
 | 
				
			||||||
 | 
					            i += self.reindexObject(subObj)
 | 
				
			||||||
 | 
					        return i # The number of reindexed (sub-)object(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def migrateTo_0_8_0(self):
 | 
				
			||||||
 | 
					        '''Migrates a Plone-based (<= 0.7.1) Appy app to a Ploneless (0.8.0)
 | 
				
			||||||
 | 
					           Appy app.'''
 | 
				
			||||||
 | 
					        self.logger.info('Migrating to Appy 0.8.0...')
 | 
				
			||||||
 | 
					        # Find the Plone site. It must be at the root of the Zope tree.
 | 
				
			||||||
 | 
					        ploneSite = None
 | 
				
			||||||
 | 
					        for obj in self.app.objectValues():
 | 
				
			||||||
 | 
					            if obj.__class__.__name__ == 'PloneSite':
 | 
				
			||||||
 | 
					                ploneSite = obj
 | 
				
			||||||
                break
 | 
					                break
 | 
				
			||||||
                isUpdated = False
 | 
					        # As a preamble: delete translation objects from self.app.config: they
 | 
				
			||||||
                for field in refFields:
 | 
					        # will be copied from the old tool.
 | 
				
			||||||
                    # Attr for storing UIDs of referred objects has moved
 | 
					        self.app.config.manage_delObjects(ids=self.app.config.objectIds())
 | 
				
			||||||
                    # from _appy_[fieldName] to [fieldName].
 | 
					        # Migrate data objects:
 | 
				
			||||||
                    refs = getattr(obj, '_appy_%s' % field.name)
 | 
					        # - from oldDataFolder to self.app.data
 | 
				
			||||||
                    if refs:
 | 
					        # - from oldTool       to self.app.config (excepted translation
 | 
				
			||||||
                        isUpdated = True
 | 
					        #                         objects that were re-created from i18n files).
 | 
				
			||||||
                        setattr(obj, field.name, refs)
 | 
					        appName = self.app.config.getAppName()
 | 
				
			||||||
                        exec 'del obj._appy_%s' % field.name
 | 
					        for oldFolderName in (appName, 'portal_%s' % appName.lower()):
 | 
				
			||||||
                        # Set the back references
 | 
					            oldFolder = getattr(ploneSite, oldFolderName)
 | 
				
			||||||
                        for refObject in field.getValue(obj):
 | 
					            objectIds = [id for id in oldFolder.objectIds()]
 | 
				
			||||||
                            refObject.link(field.back.name, obj, back=True)
 | 
					            cutted = oldFolder.manage_cutObjects(ids=objectIds)
 | 
				
			||||||
                if isUpdated: updated += 1
 | 
					            if oldFolderName == appName:
 | 
				
			||||||
            if updated:
 | 
					                destFolder = self.app.data
 | 
				
			||||||
                ins.info('  %d/%d object(s) updated.' % (updated, i+1))
 | 
					            else:
 | 
				
			||||||
 | 
					                destFolder = self.app.config
 | 
				
			||||||
 | 
					            destFolder.manage_pasteObjects(cutted)
 | 
				
			||||||
 | 
					            i = 0
 | 
				
			||||||
 | 
					            for obj in destFolder.objectValues():
 | 
				
			||||||
 | 
					                i += self.reindexObject(obj)
 | 
				
			||||||
 | 
					            self.logger.info('%d objects imported into %s.' % \
 | 
				
			||||||
 | 
					                             (i, destFolder.getId()))
 | 
				
			||||||
 | 
					            if oldFolderName != appName:
 | 
				
			||||||
 | 
					                # Re-link objects copied into the self.app.config with the Tool
 | 
				
			||||||
 | 
					                # through Ref fields.
 | 
				
			||||||
 | 
					                tool = self.app.config.appy()
 | 
				
			||||||
 | 
					                pList = tool.o.getProductConfig().PersistentList
 | 
				
			||||||
 | 
					                for field in tool.fields:
 | 
				
			||||||
 | 
					                    if field.type != 'Ref': continue
 | 
				
			||||||
 | 
					                    n = field.name
 | 
				
			||||||
 | 
					                    if n in ('users', 'groups'): continue
 | 
				
			||||||
 | 
					                    uids = getattr(oldFolder, n)
 | 
				
			||||||
 | 
					                    if uids:
 | 
				
			||||||
 | 
					                        # Update the forward reference
 | 
				
			||||||
 | 
					                        setattr(tool.o, n, pList(uids))
 | 
				
			||||||
 | 
					                        # Update the back reference
 | 
				
			||||||
 | 
					                        for obj in getattr(tool, n):
 | 
				
			||||||
 | 
					                            backList = getattr(obj.o, field.back.name)
 | 
				
			||||||
 | 
					                            backList.remove(oldFolder._at_uid)
 | 
				
			||||||
 | 
					                            backList.append(tool.uid)
 | 
				
			||||||
 | 
					                        self.logger.info('config.%s: linked %d object(s)' % \
 | 
				
			||||||
 | 
					                                         (n, len(uids)))
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        self.logger.info('config.%s: no object to link.' % n)
 | 
				
			||||||
 | 
					        self.migrateUsers(ploneSite)
 | 
				
			||||||
 | 
					        self.logger.info('Migration done.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self):
 | 
					    def run(self):
 | 
				
			||||||
        i = self.installer
 | 
					        if self.app.acl_users.__class__.__name__ == 'UserFolder':
 | 
				
			||||||
        installedVersion = i.appyTool.appyVersion
 | 
					            return # Already Ploneless
 | 
				
			||||||
 | 
					        tool = self.app.config.appy()
 | 
				
			||||||
 | 
					        appyVersion = tool.appyVersion
 | 
				
			||||||
 | 
					        if not appyVersion or (appyVersion < '0.8.0'):
 | 
				
			||||||
 | 
					            # Migration is required.
 | 
				
			||||||
            startTime = time.time()
 | 
					            startTime = time.time()
 | 
				
			||||||
        migrationRequired = False
 | 
					            self.migrateTo_0_8_0()
 | 
				
			||||||
        if not installedVersion or (installedVersion <= '0.7.0'):
 | 
					 | 
				
			||||||
            migrationRequired = True
 | 
					 | 
				
			||||||
            self.migrateTo_0_7_1()
 | 
					 | 
				
			||||||
            stopTime = time.time()
 | 
					            stopTime = time.time()
 | 
				
			||||||
        if migrationRequired:
 | 
					            elapsed = (stopTime-startTime) / 60.0
 | 
				
			||||||
            i.info('Migration done in %d minute(s).'% ((stopTime-startTime)/60))
 | 
					            self.logger.info('Migration done in %d minute(s).' % elapsed)
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,7 @@ class ModelClass:
 | 
				
			||||||
class User(ModelClass):
 | 
					class User(ModelClass):
 | 
				
			||||||
    # In a ModelClass we need to declare attributes in the following list.
 | 
					    # In a ModelClass we need to declare attributes in the following list.
 | 
				
			||||||
    _appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
 | 
					    _appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
 | 
				
			||||||
                        'password2', 'roles']
 | 
					                        'password2', 'email', 'roles']
 | 
				
			||||||
    # All methods defined below are fake. Real versions are in the wrapper.
 | 
					    # All methods defined below are fake. Real versions are in the wrapper.
 | 
				
			||||||
    title = gen.String(show=False, indexed=True)
 | 
					    title = gen.String(show=False, indexed=True)
 | 
				
			||||||
    gm = {'group': 'main', 'multiplicity': (1,1), 'width': 25}
 | 
					    gm = {'group': 'main', 'multiplicity': (1,1), 'width': 25}
 | 
				
			||||||
| 
						 | 
					@ -144,6 +144,7 @@ class User(ModelClass):
 | 
				
			||||||
    password1 = gen.String(format=gen.String.PASSWORD, show=showPassword,
 | 
					    password1 = gen.String(format=gen.String.PASSWORD, show=showPassword,
 | 
				
			||||||
                           validator=validatePassword, **gm)
 | 
					                           validator=validatePassword, **gm)
 | 
				
			||||||
    password2 = gen.String(format=gen.String.PASSWORD, show=showPassword, **gm)
 | 
					    password2 = gen.String(format=gen.String.PASSWORD, show=showPassword, **gm)
 | 
				
			||||||
 | 
					    email = gen.String(group='main', width=25)
 | 
				
			||||||
    gm['multiplicity'] = (0, None)
 | 
					    gm['multiplicity'] = (0, None)
 | 
				
			||||||
    roles = gen.String(validator=gen.Selection('getGrantableRoles'),
 | 
					    roles = gen.String(validator=gen.Selection('getGrantableRoles'),
 | 
				
			||||||
                       indexed=True, **gm)
 | 
					                       indexed=True, **gm)
 | 
				
			||||||
| 
						 | 
					@ -177,7 +178,7 @@ class Translation(ModelClass):
 | 
				
			||||||
    def show(self, name): pass
 | 
					    def show(self, name): pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The Tool class ---------------------------------------------------------------
 | 
					# The Tool class ---------------------------------------------------------------
 | 
				
			||||||
# Here are the prefixes of the fields generated on the Tool.
 | 
					# Prefixes of the fields generated on the Tool.
 | 
				
			||||||
toolFieldPrefixes = ('defaultValue', 'podTemplate', 'formats', 'resultColumns',
 | 
					toolFieldPrefixes = ('defaultValue', 'podTemplate', 'formats', 'resultColumns',
 | 
				
			||||||
                     'enableAdvancedSearch', 'numberOfSearchColumns',
 | 
					                     'enableAdvancedSearch', 'numberOfSearchColumns',
 | 
				
			||||||
                     'searchFields', 'optionalFields', 'showWorkflow',
 | 
					                     'searchFields', 'optionalFields', 'showWorkflow',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,7 @@
 | 
				
			||||||
    </tal:operator>
 | 
					    </tal:operator>
 | 
				
			||||||
    <tal:comment replace="nothing">The list of values</tal:comment>
 | 
					    <tal:comment replace="nothing">The list of values</tal:comment>
 | 
				
			||||||
    <select tal:attributes="name widgetName; size widget/height" multiple="multiple">
 | 
					    <select tal:attributes="name widgetName; size widget/height" multiple="multiple">
 | 
				
			||||||
      <option tal:repeat="v python:tool.getPossibleValues(name, withTranslations=True, withBlankValue=False, className=contentType)"
 | 
					      <option tal:repeat="v python:tool.getPossibleValues(name, withTranslations=True, withBlankValue=False, className=className)"
 | 
				
			||||||
              tal:attributes="value python:v[0]; title python: v[1]"
 | 
					              tal:attributes="value python:v[0]; title python: v[1]"
 | 
				
			||||||
              tal:content="python: tool.truncateValue(v[1], widget)">
 | 
					              tal:content="python: tool.truncateValue(v[1], widget)">
 | 
				
			||||||
      </option>
 | 
					      </option>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,6 +110,7 @@ class ZopeUserPatches:
 | 
				
			||||||
    def getRolesInContext(self, object):
 | 
					    def getRolesInContext(self, object):
 | 
				
			||||||
        '''Return the list of global and local (to p_object) roles granted to
 | 
					        '''Return the list of global and local (to p_object) roles granted to
 | 
				
			||||||
           this user (or to any of its groups).'''
 | 
					           this user (or to any of its groups).'''
 | 
				
			||||||
 | 
					        if isinstance(object, AbstractWrapper): object = object.o
 | 
				
			||||||
        object = getattr(object, 'aq_inner', object)
 | 
					        object = getattr(object, 'aq_inner', object)
 | 
				
			||||||
        # Start with user global roles
 | 
					        # Start with user global roles
 | 
				
			||||||
        res = self.getRoles()
 | 
					        res = self.getRoles()
 | 
				
			||||||
| 
						 | 
					@ -120,7 +121,8 @@ class ZopeUserPatches:
 | 
				
			||||||
        groups = getattr(self, 'groups', ())
 | 
					        groups = getattr(self, 'groups', ())
 | 
				
			||||||
        for id, roles in localRoles.iteritems():
 | 
					        for id, roles in localRoles.iteritems():
 | 
				
			||||||
            if (id != userId) and (id not in groups): continue
 | 
					            if (id != userId) and (id not in groups): continue
 | 
				
			||||||
            for role in roles: res.add(role)
 | 
					            for role in roles:
 | 
				
			||||||
 | 
					                if role not in res: res.append(role)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def allowed(self, object, object_roles=None):
 | 
					    def allowed(self, object, object_roles=None):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, subprocess, md5, shutil
 | 
					import os, os.path, subprocess, md5, shutil
 | 
				
			||||||
from appy.shared.utils import getOsTempFolder, FolderDeleter
 | 
					from appy.shared.utils import getOsTempFolder, FolderDeleter, cleanFolder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
debianInfo = '''Package: python-appy%s
 | 
					debianInfo = '''Package: python-appy%s
 | 
				
			||||||
| 
						 | 
					@ -8,23 +8,77 @@ Version: %s
 | 
				
			||||||
Architecture: all
 | 
					Architecture: all
 | 
				
			||||||
Maintainer: Gaetan Delannay <gaetan.delannay@geezteem.com>
 | 
					Maintainer: Gaetan Delannay <gaetan.delannay@geezteem.com>
 | 
				
			||||||
Installed-Size: %d
 | 
					Installed-Size: %d
 | 
				
			||||||
Depends: python (>= %s), python (<= %s)%s
 | 
					Depends: python (>= %s)%s
 | 
				
			||||||
Section: python
 | 
					Section: python
 | 
				
			||||||
Priority: optional
 | 
					Priority: optional
 | 
				
			||||||
Homepage: http://appyframework.org
 | 
					Homepage: http://appyframework.org
 | 
				
			||||||
Description: Appy builds simple but complex web Python apps.
 | 
					Description: Appy builds simple but complex web Python apps.
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					appCtl = '''#!/usr/lib/zope2.12/bin/python
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					from appy.bin.zopectl import ZopeRunner
 | 
				
			||||||
 | 
					args = ' '.join(sys.argv[1:])
 | 
				
			||||||
 | 
					sys.argv = [sys.argv[0], '-C', '/etc/%s.conf', args]
 | 
				
			||||||
 | 
					ZopeRunner().run()
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					appRun = '''#!/bin/sh
 | 
				
			||||||
 | 
					exec "/usr/lib/zope2.12/bin/runzope" -C "/etc/%s.conf" "$@"
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					ooStart = '#!/bin/sh\nsoffice -invisible -headless -nofirststartwizard ' \
 | 
				
			||||||
 | 
					          '"-accept=socket,host=localhost,port=2002;urp;"&\n'
 | 
				
			||||||
 | 
					zopeConf = '''# Zope configuration.
 | 
				
			||||||
 | 
					%%define INSTANCE %s
 | 
				
			||||||
 | 
					%%define DATA %s
 | 
				
			||||||
 | 
					%%define LOG %s
 | 
				
			||||||
 | 
					%%define HTTPPORT 8080
 | 
				
			||||||
 | 
					%%define ZOPE_USER zope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instancehome $INSTANCE
 | 
				
			||||||
 | 
					effective-user $ZOPE_USER
 | 
				
			||||||
 | 
					%s
 | 
				
			||||||
 | 
					<eventlog>
 | 
				
			||||||
 | 
					  level info
 | 
				
			||||||
 | 
					  <logfile>
 | 
				
			||||||
 | 
					    path $LOG/event.log
 | 
				
			||||||
 | 
					    level info
 | 
				
			||||||
 | 
					  </logfile>
 | 
				
			||||||
 | 
					</eventlog>
 | 
				
			||||||
 | 
					<logger access>
 | 
				
			||||||
 | 
					  level WARN
 | 
				
			||||||
 | 
					  <logfile>
 | 
				
			||||||
 | 
					    path $LOG/Z2.log
 | 
				
			||||||
 | 
					    format %%(message)s
 | 
				
			||||||
 | 
					  </logfile>
 | 
				
			||||||
 | 
					</logger>
 | 
				
			||||||
 | 
					<http-server>
 | 
				
			||||||
 | 
					  address $HTTPPORT
 | 
				
			||||||
 | 
					</http-server>
 | 
				
			||||||
 | 
					<zodb_db main>
 | 
				
			||||||
 | 
					  <filestorage>
 | 
				
			||||||
 | 
					    path $DATA/Data.fs
 | 
				
			||||||
 | 
					  </filestorage>
 | 
				
			||||||
 | 
					  mount-point /
 | 
				
			||||||
 | 
					</zodb_db>
 | 
				
			||||||
 | 
					<zodb_db temporary>
 | 
				
			||||||
 | 
					  <temporarystorage>
 | 
				
			||||||
 | 
					   name temporary storage for sessioning
 | 
				
			||||||
 | 
					  </temporarystorage>
 | 
				
			||||||
 | 
					  mount-point /temp_folder
 | 
				
			||||||
 | 
					  container-class Products.TemporaryFolder.TemporaryContainer
 | 
				
			||||||
 | 
					</zodb_db>
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Debianizer:
 | 
					class Debianizer:
 | 
				
			||||||
    '''This class allows to produce a Debian package from a Python (Appy)
 | 
					    '''This class allows to produce a Debian package from a Python (Appy)
 | 
				
			||||||
       package.'''
 | 
					       package.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, app, out, appVersion='0.1.0',
 | 
					    def __init__(self, app, out, appVersion='0.1.0',
 | 
				
			||||||
                 pythonVersions=('2.6', '2.7'),
 | 
					                 pythonVersions=('2.6',),
 | 
				
			||||||
                 depends=('zope2.12', 'openoffice.org', 'imagemagick')):
 | 
					                 depends=('zope2.12', 'openoffice.org', 'imagemagick')):
 | 
				
			||||||
        # app is the path to the Python package to Debianize.
 | 
					        # app is the path to the Python package to Debianize.
 | 
				
			||||||
        self.app = app
 | 
					        self.app = app
 | 
				
			||||||
        self.appName = os.path.basename(app)
 | 
					        self.appName = os.path.basename(app)
 | 
				
			||||||
 | 
					        self.appNameLower = self.appName.lower()
 | 
				
			||||||
        # out is the folder where the Debian package will be generated.
 | 
					        # out is the folder where the Debian package will be generated.
 | 
				
			||||||
        self.out = out
 | 
					        self.out = out
 | 
				
			||||||
        # What is the version number for this app ?
 | 
					        # What is the version number for this app ?
 | 
				
			||||||
| 
						 | 
					@ -33,6 +87,8 @@ class Debianizer:
 | 
				
			||||||
        self.pythonVersions = pythonVersions
 | 
					        self.pythonVersions = pythonVersions
 | 
				
			||||||
        # Debian package dependencies
 | 
					        # Debian package dependencies
 | 
				
			||||||
        self.depends = depends
 | 
					        self.depends = depends
 | 
				
			||||||
 | 
					        # Zope 2.12 requires Python 2.6
 | 
				
			||||||
 | 
					        if 'zope2.12' in depends: self.pythonVersions = ('2.6',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self):
 | 
					    def run(self):
 | 
				
			||||||
        '''Generates the Debian package.'''
 | 
					        '''Generates the Debian package.'''
 | 
				
			||||||
| 
						 | 
					@ -49,19 +105,74 @@ class Debianizer:
 | 
				
			||||||
        for version in self.pythonVersions:
 | 
					        for version in self.pythonVersions:
 | 
				
			||||||
            libFolder = j(srcFolder, 'python%s' % version)
 | 
					            libFolder = j(srcFolder, 'python%s' % version)
 | 
				
			||||||
            os.makedirs(libFolder)
 | 
					            os.makedirs(libFolder)
 | 
				
			||||||
            shutil.copytree(self.app, j(libFolder, self.appName))
 | 
					            destFolder = j(libFolder, self.appName)
 | 
				
			||||||
        # Create data.tar.gz based on it.
 | 
					            shutil.copytree(self.app, destFolder)
 | 
				
			||||||
        os.chdir(debFolder)
 | 
					            # Clean dest folder (.svn/.bzr files)
 | 
				
			||||||
        os.system('tar czvf data.tar.gz ./usr')
 | 
					            cleanFolder(destFolder, folders=('.svn', '.bzr'))
 | 
				
			||||||
 | 
					        # When packaging Appy itself, everything is in /usr/lib/pythonX. When
 | 
				
			||||||
 | 
					        # packaging an Appy app, we will generate more files for creating a
 | 
				
			||||||
 | 
					        # running instance.
 | 
				
			||||||
 | 
					        if self.appName != 'appy':
 | 
				
			||||||
 | 
					            # Create the folders that will collectively represent the deployed
 | 
				
			||||||
 | 
					            # Zope instance.
 | 
				
			||||||
 | 
					            binFolder = j(debFolder, 'usr', 'bin')
 | 
				
			||||||
 | 
					            os.makedirs(binFolder)
 | 
				
			||||||
 | 
					            # <app>ctl
 | 
				
			||||||
 | 
					            name = '%s/%sctl' % (binFolder, self.appNameLower)
 | 
				
			||||||
 | 
					            f = file(name, 'w')
 | 
				
			||||||
 | 
					            f.write(appCtl % self.appNameLower)
 | 
				
			||||||
 | 
					            os.chmod(name, 0744) # Make it executable by owner.
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # <app>run
 | 
				
			||||||
 | 
					            name = '%s/%srun' % (binFolder, self.appNameLower)
 | 
				
			||||||
 | 
					            f = file(name, 'w')
 | 
				
			||||||
 | 
					            f.write(appRun % self.appNameLower)
 | 
				
			||||||
 | 
					            os.chmod(name, 0744) # Make it executable by owner.
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # startoo
 | 
				
			||||||
 | 
					            name = '%s/startoo' % binFolder
 | 
				
			||||||
 | 
					            f = file(name, 'w')
 | 
				
			||||||
 | 
					            f.write(ooStart)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            os.chmod(name, 0744) # Make it executable by owner.
 | 
				
			||||||
 | 
					            # /var/lib/<app> (will store Data.fs, lock files, etc)
 | 
				
			||||||
 | 
					            varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower)
 | 
				
			||||||
 | 
					            os.makedirs(varLibFolder)
 | 
				
			||||||
 | 
					            f = file('%s/README' % varLibFolder, 'w')
 | 
				
			||||||
 | 
					            f.write('This folder stores the %s database.\n' % self.appName)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # /var/log/<app> (will store event.log and Z2.log)
 | 
				
			||||||
 | 
					            varLogFolder = j(debFolder, 'var', 'log', self.appNameLower)
 | 
				
			||||||
 | 
					            os.makedirs(varLogFolder)
 | 
				
			||||||
 | 
					            f = file('%s/README' % varLogFolder, 'w')
 | 
				
			||||||
 | 
					            f.write('This folder stores the log files for %s.\n' % self.appName)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # /etc/<app>.conf (Zope configuration file)
 | 
				
			||||||
 | 
					            etcFolder = j(debFolder, 'etc')
 | 
				
			||||||
 | 
					            os.makedirs(etcFolder)
 | 
				
			||||||
 | 
					            name = '%s/%s.conf' % (etcFolder, self.appNameLower)
 | 
				
			||||||
 | 
					            n = self.appNameLower
 | 
				
			||||||
 | 
					            f = file(name, 'w')
 | 
				
			||||||
 | 
					            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,
 | 
				
			||||||
 | 
					                                'products %s\n' % productsFolder))
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
        # Get the size of the app, in Kb.
 | 
					        # Get the size of the app, in Kb.
 | 
				
			||||||
        cmd = subprocess.Popen(['du', '-b', '-s', 'usr'],stdout=subprocess.PIPE)
 | 
					        os.chdir(tempFolder)
 | 
				
			||||||
 | 
					        cmd = subprocess.Popen(['du', '-b', '-s', 'debian'],
 | 
				
			||||||
 | 
					                               stdout=subprocess.PIPE)
 | 
				
			||||||
        size = int(int(cmd.stdout.read().split()[0])/1024.0)
 | 
					        size = int(int(cmd.stdout.read().split()[0])/1024.0)
 | 
				
			||||||
 | 
					        os.chdir(debFolder)
 | 
				
			||||||
 | 
					        # Create data.tar.gz based on it.
 | 
				
			||||||
 | 
					        os.system('tar czvf data.tar.gz *')
 | 
				
			||||||
        # Create the control file
 | 
					        # Create the control file
 | 
				
			||||||
        f = file('control', 'w')
 | 
					        f = file('control', 'w')
 | 
				
			||||||
        nameSuffix = ''
 | 
					        nameSuffix = ''
 | 
				
			||||||
        dependencies = []
 | 
					        dependencies = []
 | 
				
			||||||
        if self.appName != 'appy':
 | 
					        if self.appName != 'appy':
 | 
				
			||||||
            nameSuffix = '-%s' % self.appName.lower()
 | 
					            nameSuffix = '-%s' % self.appNameLower
 | 
				
			||||||
            dependencies.append('python-appy')
 | 
					            dependencies.append('python-appy')
 | 
				
			||||||
        if self.depends:
 | 
					        if self.depends:
 | 
				
			||||||
            for d in self.depends: dependencies.append(d)
 | 
					            for d in self.depends: dependencies.append(d)
 | 
				
			||||||
| 
						 | 
					@ -69,12 +180,15 @@ class Debianizer:
 | 
				
			||||||
        if dependencies:
 | 
					        if dependencies:
 | 
				
			||||||
            depends = ', ' + ', '.join(dependencies)
 | 
					            depends = ', ' + ', '.join(dependencies)
 | 
				
			||||||
        f.write(debianInfo % (nameSuffix, self.appVersion, size,
 | 
					        f.write(debianInfo % (nameSuffix, self.appVersion, size,
 | 
				
			||||||
                              self.pythonVersions[0], self.pythonVersions[1],
 | 
					                              self.pythonVersions[0], depends))
 | 
				
			||||||
                              depends))
 | 
					 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
        # Create md5sum file
 | 
					        # Create md5sum file
 | 
				
			||||||
        f = file('md5sums', 'w')
 | 
					        f = file('md5sums', 'w')
 | 
				
			||||||
        for dir, dirnames, filenames in os.walk('usr'):
 | 
					        toWalk = ['usr']
 | 
				
			||||||
 | 
					        if self.appName != 'appy':
 | 
				
			||||||
 | 
					            toWalk += ['etc', 'var']
 | 
				
			||||||
 | 
					        for folderToWalk in toWalk:
 | 
				
			||||||
 | 
					            for dir, dirnames, filenames in os.walk(folderToWalk):
 | 
				
			||||||
                for name in filenames:
 | 
					                for name in filenames:
 | 
				
			||||||
                    m = md5.new()
 | 
					                    m = md5.new()
 | 
				
			||||||
                    pathName = j(dir, name)
 | 
					                    pathName = j(dir, name)
 | 
				
			||||||
| 
						 | 
					@ -90,7 +204,7 @@ class Debianizer:
 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
        # Create postinst, a script that will:
 | 
					        # Create postinst, a script that will:
 | 
				
			||||||
        # - bytecompile Python files after the Debian install
 | 
					        # - bytecompile Python files after the Debian install
 | 
				
			||||||
        # - create a Zope instance (excepted if we are installing Appy itself).
 | 
					        # - change ownership of some files if required
 | 
				
			||||||
        f = file('postinst', 'w')
 | 
					        f = file('postinst', 'w')
 | 
				
			||||||
        content = '#!/bin/sh\nset -e\n'
 | 
					        content = '#!/bin/sh\nset -e\n'
 | 
				
			||||||
        for version in self.pythonVersions:
 | 
					        for version in self.pythonVersions:
 | 
				
			||||||
| 
						 | 
					@ -98,22 +212,16 @@ class Debianizer:
 | 
				
			||||||
            lib = '/usr/lib/python%s' % version
 | 
					            lib = '/usr/lib/python%s' % version
 | 
				
			||||||
            cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib,
 | 
					            cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib,
 | 
				
			||||||
                                                                  self.appName)
 | 
					                                                                  self.appName)
 | 
				
			||||||
            if self.appName != 'appy':
 | 
					 | 
				
			||||||
                inst = '/home/zope/%sInstance' % self.appName
 | 
					 | 
				
			||||||
                cmds += '  if [ -e %s ]\n  then\n' % inst
 | 
					 | 
				
			||||||
                # If the Zope instance already exists, simply restart it.
 | 
					 | 
				
			||||||
                cmds += '    %s/bin/zopectl restart\n  else\n' % inst
 | 
					 | 
				
			||||||
                # Else, create a Zope instance in the home of user "zope".
 | 
					 | 
				
			||||||
                cmds += '    %s %s/appy/bin/new.py zope /usr/lib/zope2.12 ' \
 | 
					 | 
				
			||||||
                        '%s\n' % (bin, lib, inst)
 | 
					 | 
				
			||||||
                # Within this instance, create a symlink to the Zope product
 | 
					 | 
				
			||||||
                cmds += '    ln -s %s/%s/zope %s/Products/%s\n' % \
 | 
					 | 
				
			||||||
                        (lib, self.appName, inst, self.appName)
 | 
					 | 
				
			||||||
                # Launch the instance
 | 
					 | 
				
			||||||
                cmds += '    %s/bin/zopectl start\n' % inst
 | 
					 | 
				
			||||||
                # Launch OpenOffice in server mode
 | 
					 | 
				
			||||||
                cmds += '    %s/bin/startoo\n  fi\n' % inst
 | 
					 | 
				
			||||||
            content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds)
 | 
					            content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds)
 | 
				
			||||||
 | 
					        if self.appName != 'appy':
 | 
				
			||||||
 | 
					            # Allow user "zope", that runs the Zope instance, to write the
 | 
				
			||||||
 | 
					            # database and log files.
 | 
				
			||||||
 | 
					            content += 'chown -R zope:root /var/lib/%s\n' % self.appNameLower
 | 
				
			||||||
 | 
					            content += 'chown -R zope:root /var/log/%s\n' % self.appNameLower
 | 
				
			||||||
 | 
					            # (re-)start the app
 | 
				
			||||||
 | 
					            content += '%sctl restart\n' % self.appNameLower
 | 
				
			||||||
 | 
					            # (re-)start oo
 | 
				
			||||||
 | 
					            content += 'startoo\n'
 | 
				
			||||||
        f.write(content)
 | 
					        f.write(content)
 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
        # Create prerm, a script that will remove all pyc files before removing
 | 
					        # Create prerm, a script that will remove all pyc files before removing
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,18 +36,28 @@ class FolderDeleter:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
extsToClean = ('.pyc', '.pyo', '.fsz', '.deltafsz', '.dat', '.log')
 | 
					extsToClean = ('.pyc', '.pyo', '.fsz', '.deltafsz', '.dat', '.log')
 | 
				
			||||||
def cleanFolder(folder, exts=extsToClean, verbose=False):
 | 
					def cleanFolder(folder, exts=extsToClean, folders=(), verbose=False):
 | 
				
			||||||
    '''This function allows to remove, in p_folder and subfolders, any file
 | 
					    '''This function allows to remove, in p_folder and subfolders, any file
 | 
				
			||||||
       whose extension is in p_exts.'''
 | 
					       whose extension is in p_exts, and any folder whose name is in
 | 
				
			||||||
 | 
					       p_folders.'''
 | 
				
			||||||
    if verbose: print 'Cleaning folder', folder, '...'
 | 
					    if verbose: print 'Cleaning folder', folder, '...'
 | 
				
			||||||
    # Remove files with an extension listed in exts
 | 
					    # Remove files with an extension listed in p_exts
 | 
				
			||||||
 | 
					    if exts:
 | 
				
			||||||
        for root, dirs, files in os.walk(folder):
 | 
					        for root, dirs, files in os.walk(folder):
 | 
				
			||||||
            for fileName in files:
 | 
					            for fileName in files:
 | 
				
			||||||
                ext = os.path.splitext(fileName)[1]
 | 
					                ext = os.path.splitext(fileName)[1]
 | 
				
			||||||
                if (ext in exts) or ext.endswith('~'):
 | 
					                if (ext in exts) or ext.endswith('~'):
 | 
				
			||||||
                    fileToRemove = os.path.join(root, fileName)
 | 
					                    fileToRemove = os.path.join(root, fileName)
 | 
				
			||||||
                if verbose: print 'Removing %s...' % fileToRemove
 | 
					                    if verbose: print 'Removing file %s...' % fileToRemove
 | 
				
			||||||
                    os.remove(fileToRemove)
 | 
					                    os.remove(fileToRemove)
 | 
				
			||||||
 | 
					    # Remove folders whose names are in p_folders.
 | 
				
			||||||
 | 
					    if folders:
 | 
				
			||||||
 | 
					        for root, dirs, files in os.walk(folder):
 | 
				
			||||||
 | 
					            for folderName in dirs:
 | 
				
			||||||
 | 
					                if folderName in folders:
 | 
				
			||||||
 | 
					                    toDelete = os.path.join(root, folderName)
 | 
				
			||||||
 | 
					                    if verbose: print 'Removing folder %s...' % toDelete
 | 
				
			||||||
 | 
					                    FolderDeleter.delete(toDelete)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
def copyFolder(source, dest, cleanDest=False):
 | 
					def copyFolder(source, dest, cleanDest=False):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue