appypod-rattail/gen/migrator.py
2015-10-27 21:58:18 +01:00

84 lines
3.8 KiB
Python

# ------------------------------------------------------------------------------
import os.path, time
from appy.fields.file import FileInfo
from appy.shared import utils as sutils
# ------------------------------------------------------------------------------
class Migrator:
'''This class is responsible for performing migrations, when, on
installation, we've detected a new Appy version.'''
def __init__(self, installer):
self.installer = installer
self.logger = installer.logger
self.app = installer.app
self.tool = self.app.config.appy()
@staticmethod
def migrateBinaryFields(obj):
'''Ensures all file and frozen pod fields on p_obj are FileInfo
instances.'''
migrated = 0 # Count the number of migrated fields
for field in obj.fields:
if field.type == 'File':
oldValue = getattr(obj, field.name)
if oldValue and not isinstance(oldValue, FileInfo):
# A legacy File object. Convert it to a FileInfo instance
# and extract the binary to the filesystem.
setattr(obj, field.name, oldValue)
migrated += 1
elif field.type == 'Pod':
frozen = getattr(obj.o, field.name, None)
if frozen:
# Dump this file on disk.
tempFolder = sutils.getOsTempFolder()
fmt = os.path.splitext(frozen.filename)[1][1:]
fileName = os.path.join(tempFolder,
'%f.%s' % (time.time(), fmt))
f = file(fileName, 'wb')
if frozen.data.__class__.__name__ == 'Pdata':
# The file content is splitted in several chunks.
f.write(frozen.data.data)
nextPart = frozen.data.__next__
while nextPart:
f.write(nextPart.data)
nextPart = nextPart.__next__
else:
# Only one chunk
f.write(frozen.data)
f.close()
f = file(fileName)
field.freeze(obj, template=field.template[0], format=fmt,
noSecurity=True, upload=f,
freezeOdtOnError=False)
f.close()
# Remove the legacy in-zodb file object
setattr(obj.o, field.name, None)
migrated += 1
return migrated
def migrateTo_0_9_0(self):
'''Migrates this DB to Appy 0.9.x.'''
# Put all binaries to the filesystem
tool = self.tool
tool.log('Migrating binary fields...')
context = {'migrate': self.migrateBinaryFields, 'nb': 0}
for className in tool.o.getAllClassNames():
tool.compute(className, context=context, noSecurity=True,
expression="ctx['nb'] += ctx['migrate'](obj)")
tool.log('Migrated %d binary field(s).' % context['nb'])
def run(self, force=False):
'''Executes a migration when relevant, or do it for sure if p_force is
True.'''
appyVersion = self.tool.appyVersion
# appyVersion being None simply means that we are creating a new DB.
if force or (appyVersion and (appyVersion < '0.9.0')):
# Migration is required.
self.logger.info('Appy version (DB) is %s' % appyVersion)
startTime = time.time()
self.migrateTo_0_9_0()
stopTime = time.time()
elapsed = (stopTime-startTime) / 60.0
self.logger.info('Migration done in %d minute(s).' % elapsed)
# ------------------------------------------------------------------------------