Przyszedł czas na drugie spojrzenie na Phing – czym on jest napisałem w skrócie w poprzednim wpisie.
Parametry uruchomienia
To narzędzie konsolowe, więc jest uruchamiane za pomocą wywołania phing [opcje] [cel]
w konsoli (najlepiej w katalogu zawierającym plik build.xml
). W wywołaniu można umieścić parametry/opcje:
[nazwa celu]
– nazwa celu, który ma zostać wywołany; jeżeli się nie pojawi zostanie uruchomiony cel domyślny projektu (<project ... default="domyslny_cel"/>
);-h
/-help
– wyświetlenie ogólnej pomocy aplikacji;-l
/-list
– wyświetlenie listy celów zdefiniowanych wbuild.xml
;-f [plik]
/-buildfile [plik]
– nazwa pliku skryptu, jeżeli inna niżbuild.xml
;-D[właściwość]=[wartość]
– przekazanie do skryptu właściwości o podanej wartości;-propertyfile [plik]
– wczytanie podanego pliku z deklaracjami właściwości;
Cele
W poprzedniej sekcji wspomniałem o parametrze pozwalającym wyświetlić listę dostępnych celów. Jednak nie każdy cel powinien być uruchamiany „samodzielnie” – czasem jest potrzebny tylko do spełnienia jakichś podstawowych wymagań dla innego celu, który wykonuje faktyczne operacje. Przykładem może być cel, który wczytuje/ustala odpowiednie właściwości konfiguracyjne (np. ścieżki do katalogów, dane FTP etc.), wywołanie takiego celu samodzielnie do niczego nie doprowadzi. Dlatego takie „prywatne” cele można ukryć na liście za pomocą atrybutu <target ... hidden="true"/>
.
Kolejną i chyba nabardziej przydatną możliwością celów jest ustalanie dla nich zależności – na przykład, żeby wykonać cel „deploy” (który wgrywa pliki na serwer), należy najpierw te pliki/katalogi przygotować (np. usunąć pliki tymczasowe). W skrypcie Phing nie trzeba deklarować dodatkowo wywołań celów, od których zależy wykonanie bieżącego lub samemu wywoływać ręcznie cele w odpowiedniej kolejności. W tym celu wykorzystuje się atrybut <target ... depends="cel1,cel2,cel3"/>
Są jeszcze dwa pomocne atrybuty celów – if
, unless
. Pierwszy uruchamia cel tylko w momencie, kiedy zmienna o podanej nazwie jest zadeklarowana. Drugi ma działanie odwrotnie. Poniżej przykład:
<?xml version="1.0" encoding="UTF-8"?> <project name="HelloWorld" default="hello"> <property name="uruchomione" value="" /> <target name="hello" depends="cel1,cel2"> <echo>Hello</echo> </target> <target name="cel1" if="uruchomione"> <echo>cel 1</echo> </target> <target name="cel2" unless="uruchomione"> <echo>cel 2</echo> </target> </project>
Poniżej wynik uruchomienia (pojawiają się nagłówki wszystkich wywołanych celów, ale kod cel2
nie został wykonany ze względu na warunek zawarty w atrybucie unless
.
cim@cim-k52:~/public_html/Phing$ phing Buildfile: /home/cim/public_html/Phing/build.xml HelloWorld > cel1: [echo] cel 1 HelloWorld > cel2: HelloWorld > hello: [echo] Hello BUILD FINISHED Total time: 0.0581 seconds
Właściwości
Właściwości są swego rodzaju zmiennymi dla skryptu Phing i zostały już użyte w poprzednich przykładach. Warto pamiętać, że odwołania do właściwości mają budowę ${nazwaWlasciwosci}
, np. <echo>Wartość zmiennej: ${nazwa}</echo>
. Przydatne jest używanie kropek dla budowania hierarchii – ${aplikacja.baza.host}%
– można w ten sposób grupować właściwości co mocno zwiększa czytelność.
Do tej pory w przykładach pojawiały się właściwości z wartościami zadeklarowanymi w pliku build.xml
, jednak to nie jedyne możliwe źródła danych:
<property name="nazwa" value="wartosc" />
– pokazywany wcześniej sposób deklarowania zmiennej, w deklaracjach można odwoływać się do innych zmiennych (np. do jakiejś ścieżki dodać nazwe kolejnego katalogu);<property file="plik.properties" />
– wczytuje do skryptu właściwości zdefiniowane w podanym pliku; można użyć również dodatkowego atrybutu<property file="plik.properties" prefix="zPliku" />
co spowoduje dodanie prefiksu do wszystkich nazw właściwości znajdujących się w pliku;<echo>${env.PATH}</echo>
– odwołania z prefiksemenv.
pozwalają na dostęp do zmiennych środowiskowych (zależne od systemu);
W przypadku zdublowania nazw właściwości Phing będzie zwracał pierwszą wartość właściwości, żeby zmienić to zachowanie trzeba dodać do drugiej deklaracji atrybut <property ... override="yes" />
.
Podczas tworzenia ścieżek lub operacji plikowych pomocny może okazać się dostęp do ścieżki do katalogu projektu (zadeklarowanej w tagu <project ... basedir="/var/www/Projekt">
lub domyśnie ustawianej przez Phing). Ścieżka jest dostępna pod nazwą ${project.basedir}
.
FileSet
Ponieważ Phing ma ułatwiać wdrożenia projektu posiada wsparcie do operowania na zbiorach plików – FileSet
. Jeżeli na jakichś plikach mają zostać wykonane operacje można je wskazać bardzo dokładnie:
<target name="copy"> <copy todir="kopia"> <fileset dir="."> <exclude name="*.xml" /> <include name="*.properties" /> <include name="*.php" /> </fileset> </copy> </target>
Powyższa definicja przedstawia cel kopiujący pliki do katalogu „kopia” za pomocą polecenia copy
. Natomiast miejsce z którego pliki są kopiowane („.
” – czyli bieżący katalog) oraz deklaracje, które pliki (w tym wypadku według rozszerzeń) mają być kopiowane lub pomijane definiuje typ FileSet
.
Definiowanie dołączeń/wykluczeń jest elastyczne:
- można wykorzystywać atrybuty:
<fileset ... includes="..."/>
i<fileset ... excludes="..."/>
z wykorzystaniem przecinków lub spacji podawać wzorce, jednak powyżej kilku wzorców ta metoda sprawia, że skrypt jest mniej czytelny; - można wykorzystać atrybuty:
<fileset ... includesfile="..."/>
i<fileset ... excludesfile="..."/>
podając ścieżki do plików, w których każda linijka zawiera jeden wzorzec; jednak wymaga to utrzymywania dodatkowych plików oprócz niezbędnegobuild.xml
; - można użyć tagów
<include/>
i<exclude/>
w taguFileSet
tak jak w przykładzie powyżej; chociaż przy wielu operacjach powtarzanie tego samego zestawu dołączeń/wykluczeń i późniejsze ich utrzymywanie różnież może być kłopotliwe; - można użyć typu
PatternSet.
Deklarowanie wzroców dopasowań nazw plików opiera się na gwiazkach („*” lub „**”). Jedna gwiazka pozwala na dopasowanie nazwy pliku/katalogu jednak w ramach tego dopasowania mogą się znajdować tylko pliki/katalogi bezpośrednio w danym katalogu. Natomiast dwie gwiazdki pozwalają na dopasowania również z uwzględnieniem zawartości podkatalogów. Przykłady z opisem są w oficjalnej dokumentacji.
PatternSet
W poprzenim akapicie wymieniłem kilka możliwości definiowania dołączeń/wykluczeń dla typu FileSet
wraz z ich niedogodnościami. Ostatnią opcją jest typ PatternSet
, który najprościej można opisać jako zbiór wzorców dla FileSet
. Poniżej zmodyfikowany kod celu kopiującego pliki:
<patternset id="ogolne"> <exclude name="*.xml" /> <include name="*.properties" /> <include name="*.php" /> </patternset> <target name="copy"> <copy todir="kopia"> <fileset dir="."> <patternset refid="ogolne" /> </fileset> </copy> </target>
Wynik wykonania celu przedstawionego powyżej i z poprzedniego przykładu są identyczne. Różnia polega na tym, że wykorzystanie PatternSet
ułatwia zapanowanie nad definicjami warunków – można je zdefiniować globalnie i tylko odwoływać się w razie potrzeby, a zmiany ograniczają się do jednego miejsca. Warto też zauważyć, że PatternSet
w przeciwieństwie do FileSet
jest niezależny od katalogu. Można zdefiniować warunki takie jak dołączanie plików PHP, HTML, TPL, pomijanie plików logów, plików tymczasowych etc. i używać ich w kontekście różnych katalogów. Sposoby definiowania warunków w PatternSet
są takie same jak w FileSet
z wyjątkiem możliwości odwoływania się do typu PatternSet
.
Przydatne linki:
Ciekawe narzędzie, przeważnie tworzyłem swoje skrypty tego rodzaju, podobne do narzędzi z ZF, ale za często ich nie używam. Często wolę skopiować sobie jakiś istniejący już kod i pozmieniać co trzeba.
Udało mi się wdrożyć Phinga w pracy i używamy go przy każdym wdrożeniu nowej wersji. Przede wszystkim: na podstawie szablonów generuje pliki konfiguracyjne dla różnych środowisk, katalogi plików tymczasowych, czyści cache etc. a później wgrywa je na serwer (przez FTP/rsync). Mam nadzieję, że niedługo znajdę czas żeby przygotować kolejne wpisy na ten temat.