Transmogrifier: una catena di montaggio per generare contenuti

28 febbraio 2010




(immagine da: http://waxinandmilkin.com/post/148087178/velma-by-quickhoney)

Plone 4 è alle porte e alcuni siti potranno essere rapidamente aggiornati con gli script di migrazione rilasciati con Plone (anzi, affrettatevi a provare la migrazione del vostro portale! eventuali problemi segnalati in questa fase potrebbero essere risolti direttamente dai core developer, senza alcun dispendio di energie da parte vostra :)).

In altre situazioni, dove la versione di partenza di Plone è troppo vecchia, o dove sono state operate delle personalizzazioni spinte, gli script di migrazione (cfr. http://plone.org/documentation/faq/upgrade-plone) di Plone non basteranno.. cosa fare?

Transmogrifier (http://pypi.python.org/pypi/collective.transmogrifier) potrebbe essere la risposta più corretta e “divertente“… 😀

Per capire di che si tratta immaginate una catena di montaggio, in cui entrano dei pezzi che lungo la catena vengono trasformati fino ad ottenere il prodotto finito. Se ci state pensando, è esatto: sebbene sia nato per importare contenuti in Plone, nessuno impedisce di usarlo come modulo python puro per quello che ci serve. Di fatto in questo articolo annoto alcune considerazioni relative alla migrazione di contenuti da un vecchio sito Plone ad uno di nuova generazione.

Perchè usare transmogrifier? (e non piuttosto un proprio script, magari già pronto, come nel mio caso..)

  1. un semplice file di configurazione basta a costruire la nostra pipeline di trasformazione/importazione (la nostra catena di montaggio, appunto),
  2. molti dei pezzi necessari a costruire la pipeline, chiamati blueprint, sono disponibili, in particolare per generare e manipolare oggetti Plone,
  3. la riusabilità dei singoli blueprint è molto maggiore rispetto ad avere un unico script da manipolare e modificare di volta in volta.

Qualche Direzione

Il pacchetto base di transmogrifier si chiama collective.transmogrifier, e contiene l’infrastruttura di base e i blueprint principali.
Tutti i blueprint dedicati a Plone sono stati spostati in plone.app.transmogrifier.
Infine un pacchetto molto utile è collective.blueprint.base (non ancora rilasciato: si trova nel collective), contenente delle classi di base che rendono velocissima la creazione di nuovi blueprint.

Istruire una pipeline di “transmogrifica” consiste nel definirla in un file zcml dandogli un nome e indicando il file di configurazione:


<transmogrifier:registerConfig
name="migrazione"
title="Migrazione"
description="pipeline di migrazione"
configuration="migration.cfg" />

Lanciare in esecuzione la pipeline è facile come creare un oggetto Transmogrifier passandogli il contesto e mandarne in esecuzione la __call__ indicando il nome della pipeline da lanciare:


from collective.transmogrifier.transmogrifier import Transmogrifier
transmogrifier = Transmogrifier(self.context)
transmogrifier(u'migrazione')

Dove mettere questo codice è una vostra scelta, io ho creato una Browser View e lo eseguo alla __call__ della vista.

Il mio caso, come detto, consiste nel prelevare contenuti e informazioni correlate da un portale Plone versione 2.x e importarli in un Plone versione 3.x. Chiaramente nel mezzo ho diverse “transmogrificazioni“, in particolare nel sorgente ho sempre pagine e cartelle a cui nella destinazione corrispondono diversi nuovi archetype, a seconda delle sezioni.

Blueprint sorgente per importare i contenuti esterni

Veniamo al primo problema: si trovano già pronti blueprint che generano gli item da importare partendo da oggetti Archetype locali, da file CSV, da DB relazionale, addirittura da siti web statici. Ma nel caso di portali Plone esterni al nostro Zope destinazione, nulla di “ufficiale”.

Come ho risolto? Sullo Zope sorgente, via http, richiamo sull’oggetto da migrare un Page Template che produce l’XML con tutti i dati necessari, ottenuti tramite un external method che impacchetta anche i file binari encodati base64. Il trucco consiste nel mettere nell’XML anche alcune info “non banali”, come la lista delle url da richiamare per esportare gli eventuali figli dell’oggetto specifico.

Tale XML viene usato dal mio blueprint sorgente che in configurazione ha l’url del plone sorgente e i dati di autenticazione. Ad ogni file xml corrisponde un item inserito nella pipeline.

Manipolare i contenuti in ingresso

Le informazioni nell’XML hanno chiaramente una struttura “piatta”: sono tutte stringhe. Per non stare a infilare il tipo di dato nell’XML il mio blueprint di update nella configurazione mi permette di indicare i nomi degli attributi che vanno trasformati in tipi python (basta un eval per ricreare liste, tuple, date, etc.), di quelli che vanno decodificati in base64 e di quelli che rappresentano file o immagini.

Inoltre il blueprint di update ha in configurazione la base_path del nostro portale destinazione, in modo da sapere dove andare a rigenerare i contenuti.

Un particolare che non sono riuscito a trovare già risolto “in letteratura” consiste nel trattamento dei file da caricare negli oggetti di tipo File e Immagine. In plone.app.transmogrifier ho trovato un blueprint chiamato mimeencapsulator, capace di infilare il mimetype all’interno di attributi di tipo file, ma il filename rimane scoperto.

Come ho risolto? l’XML contiene per ogni file una terna di attributi, es. “_image_filename”, “_image_contenttype”, “_image_data”, il blueprint in configurazione sa quali attributi sono da trasformare in file, es. “image”, e piazza nell’item della pipeline un attributo con chiave “image” e valore un oggetti di classe:

    from StringIO import StringIO

    class fakeFile(StringIO):
        def __init__(self, data, filename, mimetype):
        StringIO.__init__(self, data)
        self.filename = filename
        self.content_type = mimetype

Il resto della pipeline

Ci siamo presi i dati sul Plone sorgente e li abbiamo manipolati per ottenere dei dati di partenza validi. Cosa manca?

Be’.. creare i contenuti, aggiornarli con le informazioni in arrivo dal sorgente, aggiornare le UID in modo da riavere le stesse presenti sui contenuti sorgente, aggiornare il workflow, sistemare le viste di default, reindicizzare gli oggetti appena creati.

Tutto questo senza sviluppare nessun ulteriore blueprint! plone.app.transmogrifier ha tutto il necessario.

Una nota a parte la merita la gestione dell’attributo “relatedItems“, e la problematica intrinseca di non poterlo aggiornare con UID che non corrispondono ancora a nessun oggetto, nel caso in cui l’oggetto destinazione non sia ancora passato nella pipeline.

Esistono un paio di soluzioni a riguardo: quella da preferire credo sia l’utilizzo del blueprint pathresolver, che posticipa la gestione di un oggetto fino a che non sia verificata l’esistenza di determinate path. (occhio ad eventuali referenze incrociate!)

Di fatto io mi limito a lanciare lo script di migrazione due volte, eliminando la chiave relativa ai relatedItems al primo passaggio.

la lista dei blueprint di questa seconda parte della pipeline è la seguente:

  • collective.transmogrifier.sections.manipulator (per eliminare dall’item la chiave “relatedItem”)
  • collective.transmogrifier.sections.constructor (per creare l’oggetto archetype nella posizione desiderata)
  • plone.app.transmogrifier.uidupdater (per aggiornare l’UID con il valore provieniente dal sorgente)
  • plone.app.transmogrifier.atschemaupdater (per aggiornare l’oggetto creato in tutti i suoi attributi)
  • plone.app.transmogrifier.browserdefault (per assegnare la vista di default sull’oggetto creato)
  • plone.app.transmogrifier.workflowupdater (per lanciare le transizioni di workflow corrispondenti a quelle presenti sull’oggetto sorgente)
  • plone.app.transmogrifier.reindexobject (per reindicizzare l’oggetto appena creato)

Note Finali

Sicuramente la pipeline presentata non risolve tutte le situazioni possibili, ma vi da una buona idea di quel che si puo’ fare.

Una considerazione negativa rispetto all’uso di transmogrifier consiste nella difficoltà di operare in debug nel momento in cui le cose non vanno come ci aspettiamo. Una considerazione positiva è invece data dalla quantità di materiale di esempio che trovate in giro per la rete 🙂

Riferimenti:

Talk di Lennart Regebro su Transmogrifier alla Plone Conference 2009:

Talk di Quintagroup alla Plone Conference 2008 :

Dal codice:

Dai un bello sguardo ai vari blueprint presenti in collective nei pacchetti collective.transmogrifier, plone.app.transmogrifier, collective.blueprint.base. (cfr. http://dev.plone.org/collective/browser/)

Ispirazione ulteriore dal progetto Funnelweb, che offre un’interfaccia web per importare siti statici in Plone:

Buone transmogrificazioni a tutti!!

Annunci

2 Risposte to “Transmogrifier: una catena di montaggio per generare contenuti”


  1. Ottimo articolo! finalmente ci ho capito qualcosa! 🙂


  2. […] Transmogrifier: una catena di montaggio per generare contenuti […]


Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger hanno fatto clic su Mi Piace per questo: