Migraciones de Plone 2.x a Plone 3.0
Costoso proceso de migración
El ejemplo aquí mostrado no es realmente una migración, consiste en exportar todo el contenido e importarlo en la nueva versión de Plone. Para no ir carpeta por carpeta incluyo unos scripts.
En este procedimiento de migración los objetos mantienen los siguientes datos:
- Estado de publicación
- Fecha efectiva
No se contempla:
- Propietarios de los objetos
Descripción del procedimiento de importación y exportación
El procedimiento consiste en ejecutar el script de exportación mostrado en el cuadro. Después con los datos generados se debe incluir otro script (mostrado posteriormente) en el nuevo Plone.
# Example code:
from Products.PythonScripts.standard import html_quote
request = container.REQUEST
RESPONSE = request.RESPONSE
portal_types=("Folder","Document")
objs=context.getChildNodes()
res=""
obj_list=""
for obj in objs:
portal_type=getattr(obj,'portal_type',None)
if not portal_type:
res=res+"\n*** objeto %s no exportado" % obj_id
continue
if not portal_type in portal_types:
continue
res=res+"\nExportado %s (portal_type=%s) " % (obj.id,portal_type)
obj_list+="'%s'," % obj.id
context.manage_exportObject(id=obj.id)
res=res+"\n\nMueve los ficheros zexp y copia esto al script de importacion:\n"
res=res+"ficheros=(%s)" % obj_list
return res
script de exportación
En el script se debe configurar:
- Los tipos que se quieren exportar: variable portal_types del script.
El basta con copiar el script en la raíz de la instancia de Plone, por ejemplo, con el nombre export_objects. Para ejecutarlo solo hay que escribir la Url del script en el navegador. Tras la ejecución se obtiene lo siguiente:
- En el directorio /var/ de la instancia aparecen tantos ficheros con extensión .zexp como objetos han sido exportados. Hay que copiarlos al directorio /import/ de la instancia donde se importarán.
- En la pantalla del navegador aparece una lista en formato python, hay que copiarla y colocarla en el script de importación en la variable ficheros (ver ejemplo en el script de importación)
Script de importación:
El siguiente script importa los objetos listados en la variable ficheros. Tras incluirlo en la raíz de Plone y ejecutarlo con paciencia terminará apareciendo todo el contenido. Algunos comentarios sobre la importación:
- Todos los tipos de objetos de objetos existentes en el portal origen deben estar instalados en el portal destino. Por ejemplo, en mi caso yo utilizo el producto PloneArticle, para migrar a Plone 3 he tenido que buscar una versión de PloneArticle para Plone 3 e instalarla antes de utilizar este procedimiento.
- Estado inicial de los objetos: Los objetos tras importarse toman el estado inicial de del workflow que tenga asignado cada uno de ellos. Seguidamente indicaré un procedimiento para mantener el estado.
## Script (Python) "import_all"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
from Products.PythonScripts.standard import html_quote
request = container.REQUEST
RESPONSE = request.RESPONSE
#Esta variable fue introducida tras ejecutar el script de exportación, hay que sustituirla por la salida mostrada en el navegador tras la exportación
ficheros=('pruebas','front-page','artwebsite','products','traducciones','docs','cofiguraciones','tutoriales','software-old-version-replaced-24092007-132108','software',)
borrar_si_existen=False
res=""
for fichero in ficheros:
if getattr(context,fichero,None):
if borrar_si_existen:
context.manage_delObjects(ids=(fichero,))
res=res+"Borrado %s\n" % fichero
else:
res=res+"Omitido el fichero %s\n" % fichero
continue
res=res +"Importando %s\n" % fichero
context.manage_importObject(file=fichero+".zexp")
return res
Procedimiento para migrar el estado de los objetos y la fecha efectiva
Para mantener el estado de los objetos en el nuevo portal y la fecha de publicación utilizo un script que recorre el árbol de objetos recursivamente. Del mismo modo que el script trabaja con estado de los objetos y la fecha efectiva, se podría añadir código para mantener otros datos como: propietario, grupo, etc. En mi caso no necesitaba esto.
Script de exportación de atributos
El nuevo script funciona de manera similar al de exportación:
- Se copia en la raíz de Plone
- Tras a ejecución, en la pantalla del navegador aparece una gran lista en formato python que contiene todos los datos de los objetos. Hay que copiarla y pegarla en el script de importación.
## Script (Python) "export_workflow"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
request = container.REQUEST
RESPONSE = request.RESPONSE
pw=context.portal_workflow
def tree(obj,level=0):
childs=obj.getChildNodes()
for child in childs:
try:
state=pw.getInfoFor(child,'review_state')
#Aqui se extraen los datos a migrar
print " ('%s','%s','%s')," % (child.absolute_url(1),state,child.ModificationDate())
print tree(child)
except:
pass
return printed
obj=context
print "estados=(",tree(obj),")"
return printed
Script de importación de atributos
Tras copiar este script en la raiz de Plone hay que configurarlo mediante dos variables:
- Variable transiciones: Hay que mirar en el workflow del nuevo Plone el nombre de la transición que llevá el objeto al estado final deseado. En el ejemplo el estado published se consigue mediante la transición publish y, el estado private no necesita transición, ya que, en mi configuración del workflow todos los objetos comienzan en el estado privado.
- Copiar la variable estados del script anterior tal y como aparece en el navegador
**Detalle importante: Tras este procedimiento se debe recatalogar el portal completo desde el ZMI (objeto portal_catalog).
## Script (Python) "import_workflow"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
# Example code:
# Import a standard function, and get the HTML request and response objects.
from Products.CMFCore.utils import getToolByName
from Products.CMFDefault.exceptions import WorkflowException
from Products.CMFDefault.utils import Message as _
from Products.PythonScripts.standard import html_quote
request = container.REQUEST
RESPONSE = request.RESPONSE
#tansición que hay que hacer para conseguir el estado
#Importante para que plone sepa que transición hacer para alcanzar el estado
transiciones={
'published':'publish',
'private':None,
'obsoleto':'retract'
}
#Esta variable fue copiada desde el script de exportación de atributos
#Aparecía en el navegador
estados=( ('Members','published','2007-06-09 20:30:42'),
('pruebas','private','2007-07-15 23:50:06'),
('front-page','published','2007-09-19 12:55:04'),
('foros','published','2007-08-22 15:25:56'),
('products','published','2007-06-09 20:47:25'),
('products/mainmenu','published','2007-06-09 20:47:27'),
('products/mainmenu/PMainMenu.zip','published','2007-06-09 20:47:26'),
('products/mainmenu/pmainmenu','published','2007-07-22 14:11:21'),
('products/mainmenu/pmainmenu-1-0.1','published','2007-07-22 14:07:59'),
('products/artskins','published','2007-06-09 20:47:28'),
('products/artskins/ArtSkins.zip','published','2007-06-09 20:47:27'),
('products/artskins/artskins','published','2007-06-29 19:55:42'),
('products/productos','published','2007-06-29 19:55:08'),
('products/descripcion-de-algunos-productos','private','2007-05-30 16:31:11'),
('products/plone-3-0.1','published','2007-09-14 09:05:41'),
('traducciones','published','2007-06-09 20:47:45'),
('traducciones/traducciones','published','2007-07-15 15:41:11'),
('traducciones/plonegalleryview-es.zip','published','2007-07-15 14:27:50'),
('traducciones/ultimas','published','2007-07-15 15:46:28'),
('traducciones/PloneArticle-es-4.0.0.zip','published','2007-07-15 14:58:45'),
('docs','published','2007-08-16 15:12:01'),
('docs/anadir-un-portlet-en-plone-3.0','published','2007-09-09 19:18:07'),
('docs/cambio-rapido-de-apariencia-de-plone','published','2007-08-17 22:15:53'),
('docs/portlet','published','2007-09-09 18:55:50'),
('docs/predefiniciones-en-las-plantillas','published','2007-08-14 23:03:07'),
('docs/predefiniciones-en-las-plantillas-new-version','private','2007-08-14 23:14:23'),
('docs/api-de-plone','published','2007-06-27 21:18:31'),
('docs/guia-rapida-de-python','published','2007-08-05 22:29:27'),
('docs/cosas-simples','private','2007-08-13 21:56:33'),
('docs/migraciones','private','2007-11-02 16:52:26'),
)
wtool = getToolByName(script, 'portal_workflow')
for dato in estados:
url,estado,fecha_efectiva = dato
obj=None
try:
obj=context.restrictedTraverse(url)
except:
print "*** Error: objeto %s no encontrado" % url
action=transiciones[estado]
if obj:
if action:
try:
wtool.doActionFor(obj, action, comment='Contenido importado')
except:
pass
obj.setEffectiveDate(fecha_efectiva)
obj.setModificationDate(fecha_efectiva)
print "Tansicion '%s' a '%s'" % (action,url)
return printed

