L'intérêt de buildout, c'est de pouvoir gérer des dépendances de packages (au sens packages Python) en dehors des dépendances Debian. Pourquoi ? Parceque sur un même système, on peut avoir une instance qui a besoin de Plone 3.1.2, une autre qui a besoin de Plone 3.1.4 ... Et quand on met à jour le package zope-plone3, on ne veut pas que ça casse les instances déjà existantes. De plus, y a plein de gugusses qui filent leurs produits sous forme de eggs (packages Python) et ça intéragit très mal avec le système de packaging Debian, hélas (je suis le premier à le regretter - ou peut-être le 2è si on compte Gaël )
Un des côtés sympas de buildout, c'est d'avoir un buildout.cfg "tout prêt" (attention : il faut quand même se donner la peine de le faire ; et c'est facile de faire un buildout.cfg tout pourri qui ne marchera pas!), et de pouvoir le passer à un autre développeur pour lui dire "tu dois bosser sur le projet trucmuche ? Bah pour te monter ton environnement de développement, tiens, tu prends ce buildout.cfg et ça va tout te mettre en place".
Si vous avez des packages Python qui ne sont pas setuptools-aware (comme PIL, voir plus bas), il faut bidouiller pour que ça marche. Et parfois ça peut très bien ne pas marcher.
Si le buildout.cfg est pourri, ça ne marchera pas, et ça ne sera pas facile de trouver pourquoi si vous ne connaissez pas buildout.
Si vous avez un site qui n'est pas "buildoutisé" et que vous voulez faire un buildout.cfg, ça ne sera pas forcément facile. Il ne faut pas systématiquement essayer de faire rentrer des pièces carrées dans des trous ronds.
Si vous avez un site "buildoutisé" et que vous voulez le mettre sur une autre machine, vous pouvez a priori faire un coup de rsync (ou un tarball) si vous avez utilisé la méthode virtualenv décrite ci-dessous, mais ça n'est pas forcément fait pour (il peut y avoir des effets de bord que je ne connais pas).
Le but de buildout c'est de mettre en place un environnement (une ou plusieurs instances Zope, avec des produits installés dedans) ; pas forcément de permettre de "repacker" un environnement existant pour le "dépacker" quelquepart ailleurs. Autrement dit, pour les projets à la Pilot, où on a un site de dev et qu'on passe ensuite en prod parceque le client a déjà commencé à mettre des contenus dessus, ça ne résout pas le problème de déploiement (pas de manière immédiate en tout cas). Mais je poursuis la réflexion pour savoir ce qu'on peut faire dans ce domaine afin de se simplifier la vie !
Le problème : buildout vautre comme une vieille loutre bourrée si jamais il y a déjà des packages Python installés avec apt/dpkg (ou tout autre système de packaging).
La solution :
Petit exemple d'installation d'un plone avec virtualenv et tout le tralala :
sudo apt-get install python-virtualenv python python-dev python2.4 python2.4-dev ENVPATH=/chemin/vers/mon/environnement python2.4 /usr/bin/virtualenv --no-site-packages $ENVPATH cd $ENVPATH # pour modifier l'environnement du shell afin de n'utiliser que notre virtualenv : source bin/activate # NB 1 : je ne sais pas si Plone a besoin du support jpeg et freetype # dans PIL ; mais si jamais c'est le cas, avant de lancer l'installation # de PIL, il suffit d'installer les deux packages suivants : sudo apt-get install libjpeg62-dev libfreetype6-dev # NB 2 : normalement, on devrait pouvoir faire "bin/easy_install PIL", # mais comme PIL n'est pas "setuptools-aware" on doit faire les 2 lignes suivantes, # la première pour récupérer le source à l'arrache, la seconde pour corriger le namespace. bin/easy_install --find-links http://www.pythonware.com/products/pil/ Imaging ( cd lib/python2.4/site-packages/PIL* ; mkdir PIL ; mv *.py *.pyc *.so PIL ; ) bin/easy_install zc.buildout
Ensuite, on met ce fichier buildout.cfg :
[buildout] parts = plone zope2 instance [plone] recipe = plone.recipe.plone [zope2] recipe = plone.recipe.zope2install url = ${plone:zope2-url} [instance] recipe = plone.recipe.zope2instance zope2-location = ${zope2:location} user = admin:admin http-address = 8000 debug-mode = on products = ${plone:products} eggs = ${plone:eggs}
Ensuite on prie et on tape :
bin/buildout bin/instance fg # rock and roll
Pour faire son buildout à la main, on a juste besoin de deux éléments :
Note : le fichier bootstrap.py peut être récupéré de plusieurs façons différentes :
Le fichier buildout.cfg contient des sections façon "RFC822". Un petit exemple :
# ceci est un commentaire [buildout] # ceci est la section "globale", qui est la seule à être obligatoire parts = titi toto productdistros # ceci indique le nom des autres sections à utiliser develop = src/MonSuperProduit src/MonAutreProduit # si on met plusieurs trucs, faut mettre soit sur une seule ligne, src/UnAutreProduit # soit sur plusieurs, mais alors avec un par ligne ... src/ps.graffiti # et la notation "à la mode" c'est sous forme de chemin Java/Python # "develop" indique les répertoires contenant les sources sur lesquels on est en train de bosser. # Par convention, on place le tout dans "src". # A priori, il faut aussi mettre une section "eggs" contenant au moins les mêmes choses, # et qui pourra être incluse depuis les autres sections. eggs = src/MonSuperProduit src/MonAutreProduit src/UnAutreProduit src/ps.graffiti [titi] # cette section sera bien prise en compte, vu qu'elle est dans "parts" [tutu] # mais pas celle-là, en revanche # lorsqu'on doit inclure des produits "old school" (sous la forme de targz qu'on décompresse # dans le répertoire Products/ de son instance), on utilise souvent une section de cette forme : [productdistros] recipe = plone.recipe.distros urls = http://www.topcoolproduct.com/download/SuperFoo-1.0.5.tar.gz http://www.topcoolproduct.com/download/SuperQuux-2.1.0.tar.gz # Les tarballs aux urls indiqués seront décompressés "comme il faut".
On a un répertoire src dans lequel on met les bouts de code sur lesquels on travaille.
On a un répertoire eggs dans le quel buildout va mettre les eggs téléchargés (sous forme de .egg s'ils sont zip-safe, ou en les décompressant sinon).
On a un répertoire develop-eggs , qui est géré par buildout (pas besoin de taper dedans).
On a un répertoire parts, qui contient toutes les choses "générées" par les différentes sections. Par exemple, si on a une section "toto", et bien on aura un répertoire parts/toto, et ainsi de suite. Dans la définition d'une section, si on utilise la variable ${nomdelasection:location} cela se traduit par le répertoire en question.
On peut utiliser cette recipe :
[zopepy] recipe = zc.recipe.egg eggs = ${instance:eggs} # mettre ici le nom de la section correspondant à l'instance zope # (généralement c'est "instance", mais le modifier si besoin!) interpreter = zopepy extra-paths = ${zope2:location}/lib/python # et là le nom de la section correspondant à Zope 2 # (idem, généralement c'est zope2, mais modifier si on l'a changé!) scripts = zopepy
Puis on lance bin/zopepy et c'est parti.
Littéralement, c'est une recette. À comprendre au sens de « recette de cuisine » : on indique « je veux un risotto aux champignons pour 4 personnes », et la recipe se débrouille pour faire cuire le riz, les champignons, et tout ce qui va avec, en quantités idoines.
Techniquement, c'est un bout de code Python, généralement logé dans un package bien nommé ; ainsi, dans plone.recipe.plone
, se trouve la « recette » permettant d'installer Zope + Plone.
Écrire une recipe est pour l'instant au-dessus de mes compétences, et est donc laissé en exercice au lecteur (quelques informations en anglais sont disponibles sur la toile ; sinon, je vous invite à lire l'excellent blog de Gawel sur lequel vous trouverez quelques informations en français sur le sujet).
Simple (ou presque) : on fait un ln -s /monchemin/blabla/bin/instance /etc/rc2.d/S90instance (par exemple), vu que le script instance est équivalent à zopectl (et qu'on peut donc lui passer les arguments start/stop).
Si ce sont des sources "eggifiées", il y a un moyen sympa de le faire (via la directive develop) ; sinon j'ai réussi à faire la chose suivante, mais je ne sais pas si c'est The Right Thing :
[buildout] parts = plone zope2 instance svn [svn] recipe = infrae.subversion urls = http://sprint.pilotsystems.net/svn/collective.gossip collective.gossip http://sprint.pilotsystems.net/svn/collective.graffiti collective.graffiti http://tracker.trollfot.org/svn/projects/sd.common/trunk sd.common # la recipe infrae.subversion va faire des checkouts des URL ci-dessus, # dans les sous-répertoires indiqués ; ainsi, la dernière repository citée - sd.common/trunk - # se retrouve dans onrepertoirebuildout/parts/svn/sd.common [plone] recipe = plone.recipe.plone [zope2] recipe = plone.recipe.zope2install url = ${plone:zope2-url} [instance] recipe = plone.recipe.zope2instance zope2-location = ${zope2:location} user = admin:admin http-address = 8002 debug-mode = on products = ${plone:products} extra-paths = ${svn:location}/collective.gossip ${svn:location}/collective.graffiti ${svn:location}/sd.common eggs = ${buildout:eggs} ${plone:eggs} zcml = collective.gossipVoir aussi http://pypi.python.org/pypi/gp.svndevelop/
Actions sur le document