O Buildoucie i Django

Buildout to stworzony w języku Python system służący do zautomatyzowanego budowania oprogramowania. Oprogramowania zwykle złożonego z wielu różnych części, niekoniecznie opartych na Pythonie.

Buildout?

Z Buildoutem zetknąłem się po raz pierwszy wiele lat temu, gdy jeszcze bliżej było mi do Zope niż do Django. Zetknąłem się nie znaczy, że go używałem, ale jak mówi staropolskie powiedzenie “co się odwlecze to nie uciecze” i wygląda na to, że czas Buildouta nastał właśnie teraz. Owo teraz zaczęło się od Dominika “Dominno” Szopy i jego prezentacji na temat Buildouta, którą wygłosił na konferencji PyConPL. Temat na tyle mnie zainteresował, że postanowiłem zapoznać się z buildoutem bliżej i… jestem pozytywnie zaskoczony. W tym wpisie podzielę się kilkoma spostrzeżeniami na temat wykorzystania Buildouta we własnym projekcie Django.

Wprowadzenie do Buildouta

Najciekawsze wprowadzenie do Buildouta w języku polskim to artykuł wspomnianego Dominika Szopy z PyConPL. Niestety nie jest on chyba dostępny w Sieci (a przynajmniej nie potrafię go znaleźć), pozostaje więc zapoznanie się z samą tylko prezentacją Dominika oraz anglojęzycznymi materiałami. Poniżej kilka słów wprowadzenia w temat ode mnie, a potem linki do wybranych tutoriali.

Buildout z bliska

Buildout pozwala na zautomatyzowane instalowanie aplikacji wraz ze wszystkimi zależnościami. Jak można się spodziewać, aby taka zautomatyzowana instalacja zadziałała po pierwsze potrzebny jest Buildout, a po drugie plik konfiguracyjny, w którym znajdą się przepisy wskazujące co ma być zainstalowane. W praktyce oznacza to, że potrzebne są dwa pliki: bootstrap.py oraz buildout.cfg.

Żeby zainstalować Buildouta wystarczy pobrać i uruchomić skrypt bootstrap.py.

[ext@sandarcher buildout]$
    wget http://svn.zope.org/*checkout*/zc.buildout/trunk/bootstrap/bootstrap.py
    (...)
    2009-12-25 23:17:02 (228 KB/s) - zapisano `bootstrap.py' [3807]
[ext@sandarcher buildout]$ touch buildout.cfg
[ext@sandarcher buildout]$ ls
    bootstrap.py buildout.cfg
[ext@sandarcher buildout]$ python bootstrap.py
    Creating directory '/home/ext/tmp/buildout/bin'.
    Creating directory '/home/ext/tmp/buildout/parts'.
    Creating directory '/home/ext/tmp/buildout/eggs'.
    Creating directory '/home/ext/tmp/buildout/develop-eggs'.
    Generated script '/home/ext/tmp/buildout/bin/buildout'.

Następnie należy wywołać polecenie bin/buildout, co spowoduje, że Buildout zainstaluje to co zostało zdefiniowane w pliku konfiguracyjnym buildout.cfg.

W skrótcie to tyle, ale warto jeszcze wspomnieć o tym co znajduje się w pliku konfiguracyjnym. Otóż Buildout oparty jest na recipes czyli przepisach. Każdy przepis powoduje wykonanie różnych czynności, takich jak na przykład: zainstalowanie Django, stworzenie skrótu na dysku, czy zainstalowanie pakietu przez configure, make, make install. Tworząc plik konfiguracyjny wpisuje się w nim konkretne przepisy i podaje im parametry.

Więcej szczegółowych informacji o Buildoucie znaleźć można wśród poniższych materiałów:

Struktura plików i katalogów

Tutoriale tutorialami, ale tym co mnie najbardziej interesowało było to jak “zbuildoutować” mój istniejący, lub właśnie tworzony projekt w Django. Jakie stworzyć katalogi, gdzie umieścić konfig Buildouta, itp itd. Z powyższych materiałów niestety nie wynika to wprost dlatego przedstawię tu mój sposób. Jeśli ktoś zna lepszy lub inny to zapraszam do komentowania.

Jak już wspomniałem Buildout wymaga w zasadzie dwóch plików: konfiguracyjnego buildout.cfg oraz inicjalizującego środowisko bootstrap.py. Ja do tego dokładam jeszcze projekt djangowy i w efekcie moja struktura plików i katalogów wygląda następująco:

- bootstrap.py
- buildout.cfg
- project/ (katalog z moim projektem)

To, że mój projekt nazywa się “project” jest zapisane w konfiguracji dla Buildouta – będzie to widoczne w przedstawionym nieco dalej fragmencie buildout.cfg w sekcji [django].

Powyższe umieszczam w repozytorium, po czym wykonuję np. na innym serwerze checkout (pobranie z repozytorium), odpalam bootstrap.py (instalacja Buildouta) i wywołuję bin/buildout (instalacja projektu i zależności). W efekcie uzyskuję w pełni skonfigurowane środowisko do uruchamiania projektu.

Odrobina customizacji

Wśród wielu przydatnych opcji Buildouta warto wspomnieć o rozszerzaniu plików konfiguracyjnych. Rozszerzanie pozwala na zdefiniowanie różnych plików konfiguracyjnych np. dla środowiska deweloperskiego czy testowego, które bazując na innym pliku konfiguracyjnym modyfikują niektóre spośród zawartych w nim ustawień.

Fragment przykładowego pliku buildout.cfg:

[buildout]
parts = PIL django omlette cms-media

[PIL]
recipe = zc.recipe.egg
eggs = PIL==1.1.6
find-links = http://dist.repoze.org

[django]
recipe = djangorecipe
version = 1.1
project = project
eggs =
     PIL == 1.1.6
     psycopg2
     egenix-mx-base
     south
     django-reversion
     django-tinymce
     django-cms
wsgi = true
settings = production
extra-paths = ${buildout:directory}/project/apps
(...)

Powyższa konfiguracja instaluje PIL oraz kilka bibliotek i aplikacji określonych w sekcji eggs. Warto tu także zwrócić uwagę na ciekawe ustawienia w przepisie dla Django, takie jak “wsgi=True”, które określa czy ma być generowany skrypt .wsgi pozwalający na uruchamianie projektu spod mod_wsgi oraz “settings=production” wskazujące jaki plik jest plikiem konfiguracyjnym projektu. Wpis “extra-paths” pozwala na określenie ścieżek, które zostaną dodane do PYTHONPATH, w tym przypadku jest to folder “apps” w moim projekcie, w którym to folderze trzymam wykonane na potrzeby projektu aplikacje.

Przykładowy plik devel.cfg dla środowiska deweloperskiego:

[buildout]
extends = buildout.cfg

[django]
wsgi=false
settings=development

Plik devel.cfg rozszerza konfigurację zawartą w buildout.cfg poprzez modyfikację ustawień dla sekcji [django]. Sekcja ta to przepis instalujący Django, który zostaje tu ustawiony tak, aby w środowisku deweloperskim nie generował pliku .wsgi oraz aby używał pliku o nazwie development.py jako konfiguracji Django.

Jak korzystać z takich rozszerzających plików konfiguracyjnych? Bardzo prosto:

bin/buildout -c devel.cfg

Uwaga na PIL

PIL czyli Python Imaging Library jest bardzo często wykorzystywany przez różne aplikacje Django (mam tu na myśli głównie aplikacje do wielokrotnego wykorzystania (ang. reusable apps)). Niestety biblioteka ta od zawsze sprawiała kłopoty przy instalacji i tak samo było podczas moich eksperymentów z PILem i Buildoutem. Żaden ze sposobów instalacji PIL podany w podlinkowanych wyżej materiałach nie chciał zadziałać. PIL instalował się w złej wersji, albo w dwóch różnych wersjach i Django nie chciało go “zobaczyć”. Przyczyną problemu okazało się to, że wydana została nowa wersja PIL, a rozwiązanie polegało na określeniu w pliku konfiguracyjnym w dwóch miejscach dokładnej wersji PIL, co widać w przykładzie poniżej.

[PIL]
recipe = zc.recipe.egg
eggs = PIL==1.1.6
find-links = http://dist.repoze.org

[django]
recipe = djangorecipe
version = 1.1
project = project
eggs =
     PIL == 1.1.6

Jeśli więc po przeczytaniu tutoriala do Buildouta występują problemy z instalacją PIL sugeruję wypróbować powyższą konfigurację.

Dlaczego buildout a nie PIP?

PIP czyli Pip Installs Packages to narzędzie zastępujące easy_install. Tym co czyni PIP podobnym do Buildouta są pliki wymagań (ang. requirements), które pozwalają na zdefiniowanie zestawu pakietów do zainstalowania. Taki plik wymagań ma zwykle bardzo prostą postać np.:

MyApp
Framework==0.9.4
Library>=0.2
-e svn+http://myrepo/svn/MyApp#egg=MyApp

Pierwsze trzy wpisy określają konkretne biblioteki do zainstalowania (np. z PyPi), ostatnia linia wskazuje, że zainstalowana ma być aplikacja z repozytorium svn. Jeśli plik wymagań nazywa się requirements.txt to możemy zainstalować zdefiniowane w nim pakiety wydając polecenie:

pip install -r requirements.txt

Co bardzo istotne, zadaniem PIPa jest instalowanie pakietów Pythona, które są stworzone zgodnie ze standarowymi sposobami dystrybucji (zdefiniowanymi w distutils). Oznacza to, że każdy instalowany pakiet musi być pakietem pythonowym oraz musi posiadać prawidłowy plik setup.py.

Chociaż PIP i jego pliki wymagań sprawdzają się w wielu projektach (wiem bo sam korzystam) to jednak PIP ma pewne istotne ograniczenia i tak naprawdę jest narzędziem przeznaczonym do czegoś innego niż Buildout, który ma po prostu znacznie większe możliwości. Najlepszym dowodem na to jest fakt, że istnieje dla Buildouta przepis pozwalający na instalacje pakietów za pomocą PIP.

Dlaczego virtualenv i Buildout?

Na koniec kilka słów na temat virtualenv i Buildouta. Virtualenv to narzędzie do tworzenia wirtualnych wyizolowanych środowisk Pythona. W praktyce Buildout instalując aplikacje i różne pakiety działa nieco podobnie do virtualenva, gdyż umieszcza je w swoich własnych katalogach (wygenerowanych przez bootstrap.py) i nie narusza systemowego Pythona.

Kiedy więc warto połączyć virtualenv z Buildoutem? Otóż wtedy, gdy chcemy aby tworzone środowisko nie korzystało w ogóle z bibliotek z systemowego Pythona. Wówczas należy wygenerować nowe wirtualne środowisko za uruchamiając polecenie virtualenv z parametrem –no-site-packages i dopiero w nim uruchomić Buildouta.

Podsumowanie

Buildout jest narzędziem, którym zdecydowanie warto się zainteresować, po to aby… ułatwić sobie życie. Buildout przydaje się zarówno przy umieszczaniu projektu w wielu różnych środowiskach (deweloperskim, testowym, produkcyjnym) jak i przy pracy grupowej, gdy trzeba zainstalować projekt u kilku deweloperów. Ze swojej strony zdecydowanie zachęcem do wypróbowania Buildouta we własnych projektach.

27. December 2009 by restless_being
Categories: Uncategorized | Tags: , | Leave a comment

Leave a Reply

Required fields are marked *