Logo Search packages:      
Sourcecode: zope-atcontenttypes version File versions


"""Migration tools for ATContentTypes

Migration system for the migration from CMFDefault/Event types to archetypes
based CMFPloneTypes (http://sf.net/projects/collective/).

Copyright (c) 2004, Christian Heimes and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the author nor the names of its contributors may be used
   to endorse or promote products derived from this software without specific
   prior written permission.

$Id: Migrator.py,v 1.21 2004/10/14 22:30:52 tiran Exp $

from copy import copy

from Products.CMFCore.utils import getToolByName
from Acquisition import aq_base, aq_parent
from DateTime import DateTime
from Persistence import PersistentMapping
from OFS.Uninstalled import BrokenClass

from common import *


fieldList = [
    # (accessor, mutator, field),
    ('Title', 'setTitle',                    ''),
    ('Creator', '',                          ''),
    ('Subject','setSubject',                 'subject'),
    ('Description','setDescription',         'description'),
    ('Publisher', '',                        ''),
    ('Contributors','setContributors',       'contributors'),
    ('Date', '',                             ''),
    ('CreationDate', '',                     ''),
    ('EffectiveDate','setEffectiveDate',     'effectiveDate'),
    ('ExpirationDate','setExpirationDate',   'expirationDate'),
    ('ModificationDate', '',                 ''),
    ('Type', '',                             ''),
    ('Format', 'setFormat',                  ''),
    ('Identifier', '',                       ''),
    ('Language','setLanguage',               'language'),
    ('Rights','setRights',                   'rights'),

    # allowDiscussion is not part of the official DC metadata set

metadataList = []
for accessor, mutator, field in fieldList:
    if accessor and mutator:
        metadataList.append((accessor, mutator))

def copyPermMap(old):
    """bullet proof copy
    new = PersistentMapping()
    for k,v in old.items():
        nk = copy(k)
        nv = copy(v)
        new[k] = v
    return new

def getTypeOf(obj):
    """returns the type info of a wrapper object or None
    ttool = getToolByName(obj, 'portal_types')
    tinfo = ttool.getTypeInfo(obj)
    if tinfo:
        return tinfo.getId()

00084 class BaseMigrator:
    """Migrates an object to the new type

    Base class
    fromType = ''
    toType   = ''
    map      = {}

    subtransaction = 30

    def __init__(self, obj, **kwargs):
        self.old = obj
        self.orig_id = self.old.getId()

        self.old_id = '%s_MIGRATION_' % self.orig_id

        self.new = None
        self.new_id = self.orig_id

        self.parent = aq_parent(self.old)
        self.kwargs = kwargs

        # safe id generation
        while hasattr(aq_base(self.parent), self.old_id):

        #print "Migrating %s from %s to %s" % (obj.absolute_url(1), self.fromType, self.toType)

00114     def getMigrationMethods(self):
        beforeChange = []
        methods      = []
        lastmethods  = []
        for name in dir(self):
            if name.startswith('beforeChange_'):
                method = getattr(self, name)
                if callable(method):
            if name.startswith('migrate_'):
                method = getattr(self, name)
                if callable(method):
            if name.startswith('last_migrate_'):
                method = getattr(self, name)
                if callable(method):

        afterChange = methods+[self.custom]+lastmethods
        return (beforeChange, afterChange, )

00137     def migrate(self, unittest=0):
        """Migrates the object
        beforeChange, afterChange = self.getMigrationMethods()

        for method in beforeChange:
            __traceback_info__ = (self, method, self.old, self.orig_id)
            # may raise an exception, catch it later


        for method in afterChange:
            __traceback_info__ = (self, method, self.old, self.orig_id)
            # may raise an exception, catch it later


    __call__ = migrate

00159     def renameOld(self):
        """Renames the old object

        Must be implemented by the real Migrator
        raise NotImplementedError

00166     def createNew(self):
        """Create the new object

        Must be implemented by the real Migrator
        raise NotImplementedError

00173     def custom(self):
        """For custom migration

00178     def migrate_properties(self):
        """Migrates zope properties

        Removes the old (if exists) and adds a new
        if not hasattr(aq_base(self.old), 'propertyIds') or \
          not hasattr(aq_base(self.new), '_delProperty'):
            # no properties available
            return None

        for id in self.old.propertyIds():
            LOG("propertyid: " + str(id))
            if id in ('title', 'description'):
                # migrated by dc
            if id in ('content_type', ):
                # has to be taken care of separately
                LOG("property with id: %s not migrated" % str(id))
            value = self.old.getProperty(id)
            type = self.old.getPropertyType(id)
            LOG("value: " + str(value) + "; type: " + str(type))
            if self.new.hasProperty(id):
            LOG("property: " + str(self.new.getProperty(id)))
            __traceback_info__ = (self.new, id, value, type)
            # continue if the object already has this attribute
            if getattr(aq_base(self.new), id, _marker) is not _marker:
            self.new.manage_addProperty(id, value, type)

00211     def migrate_owner(self):
        """Migrates the zope owner
        # getWrappedOwner is not always available
        if hasattr(self.old, 'getWrappedOwner'):
            owner = self.old.getWrappedOwner()
            LOG("changing owner via changeOwnership: %s" % str(self.old.getWrappedOwner()))
            # fallback
            # not very nice but at least it works
            # trying to get/set the owner via getOwner(), changeOwnership(...)
            # did not work, at least not with plone 1.x, at 1.0.1, zope 2.6.2
            LOG("changing owner via property _owner: %s" % str(self.old.getOwner(info = 1)))
            self.new._owner = self.old.getOwner(info = 1)

00227     def migrate_withmap(self):
        """Migrates other attributes from obj.__dict__ using a map

        The map can contain both attribute names and method names

        'oldattr' : 'newattr'
            new.newattr = oldattr
        'oldattr' : ''
            new.oldattr = oldattr
        'oldmethod' : 'newattr'
            new.newattr = oldmethod()
        'oldattr' : 'newmethod'
        'oldmethod' : 'newmethod'
        for oldKey, newKey in self.map.items():
            LOG("oldKey: " + str(oldKey) + ", newKey: " + str(newKey))
            if not newKey:
                newKey = oldKey
            oldVal = getattr(self.old, oldKey)
            newVal = getattr(self.new, newKey)
            if callable(oldVal):
                value = oldVal()
                value = oldVal
            if callable(newVal):
                setattr(self.new, newKey, value)

00258     def remove(self):
        """Removes the old item

        Must be implemented by the real Migrator
        raise NotImplementedError

00265 class BaseCMFMigrator(BaseMigrator):
    """Base migrator for CMF objects

00269     def migrate_dc(self):
        """Migrates dublin core metadata
        # doesn't work!
        # shure? works for me
        for accessor, mutator in metadataList:
            oldAcc = getattr(self.old, accessor)
            newMut = getattr(self.new, mutator)
            #newAcc = getattr(self.new, accessor)

00280     def migrate_workflow(self):
        """migrate the workflow state
        wfh = getattr(self.old, 'workflow_history', None)
        if wfh:
            wfh = copyPermMap(wfh)
            self.new.workflow_history = wfh

00288     def migrate_allowDiscussion(self):
        """migrate allow discussion bit
        if getattr(aq_base(self.old), 'allowDiscussion', _marker) is not _marker and \
          getattr(aq_base(self.new), 'isDiscussable', _marker)  is not _marker:

00295     def migrate_discussion(self):
        """migrate talkback discussion bit
        talkback = getattr(self.old.aq_inner.aq_explicit, 'talkback', _marker)
        if talkback is _marker:
            self.new.talkback = talkback

00304     def beforeChange_storeDates(self):
        """Safe creation date and modification date
        self.old_creation_date = self.old.CreationDate()
        self.old_mod_date = self.old.ModificationDate()

00310     def last_migrate_date(self):
        """migrate creation / last modified date

        Must be called as *last* migration
        self.new.creation_date = DateTime(self.old_creation_date)

00318 class ItemMigrationMixin:
    """Migrates a non folderish object

00322     def renameOld(self):
        """Renames the old object
        LOG("renameOld | orig_id: " + str(self.orig_id) + "; old_id: " + str(self.old_id))
        self.parent.manage_renameObject(self.orig_id, self.old_id)

00329     def createNew(self):
        """Create the new object
        ttool = getToolByName(self.parent, 'portal_types')
        typeInfo = ttool.getTypeInfo(self.toType)
        typeInfo.constructInstance(self.parent, self.new_id)

        self.new = getattr(self.parent, self.new_id)

00338     def remove(self):
        """Removes the old item
        if REMOVE_OLD:

00344 class FolderMigrationMixin(ItemMigrationMixin):
    """Migrates a folderish object

00348     def XXX_migrate_children(self):
        """Copy childish objects from the old folder to the new one

        XXX: Oh hell that's very inefficient and I'm very shure that it will
        blow up the zodb. See alternative
        for obj in self.old.objectValues():
            self.new.manage_clone(obj, obj.getId())

00357     def migrate_alternativeChildren(self):
        """Just an idea

        I don't know wether it works or fails due the ExtensionClass, ZODB and
        acquisition stuff of zope

        It seems to work for me very well :)
        #for obj in self.old.objectValues():
        #    if isinstance(obj, BrokenClass):
        #        log('WARNING: Loosing BrokenObject in %s' % \
        #            self.old.absolute_url(1))
        #        continue
        #    id = obj.getId()
        #    self.new._setObject(id, aq_base(obj))

        # using objectIds() should be safe with BrokenObjects
        for id in self.old.objectIds():
            obj = getattr(self.old.aq_inner.aq_explicit, id)
            self.new._setObject(id, aq_base(obj))

00378 class CMFItemMigrator(ItemMigrationMixin, BaseCMFMigrator):

00382 class CMFFolderMigrator(FolderMigrationMixin, BaseCMFMigrator):

Generated by  Doxygen 1.6.0   Back to index