Czytając początkowe zdania artykułu, Twoją uwagę mogły przykuć angielskie terminy w nawiasach - lifecycle, phase, plugin oraz goal. Wplotłem je świadomie, ponieważ reprezentują podstawowe pojęcia Maven2, które odpowiadają pojęciom projektowym - sekwencja (również cykl), etap, wtyczka (również narzędzie) oraz zadanie, odpowiednio. Zrozumienie działania Maven2 to zrozumienie istoty tych pojęć. Usystematyzowanie działań podczas tworzenia oprogramowania, wprowadzone wdrożeniem Maven2, ma zauważalnie pozytywny efekt na kondycję i postępy projeku. Pozwala skorzystać z dobrych praktyk projektowych i programistycznych bez dodatkowych nakładów czasowych oraz finansowych na ich dogłębne poznanie. Prostota korzystania z Maven2 ma niebagatelne znaczenie do osiągnięcia zamierzonego celu - ukończenia projektu na czas z jakością tworzenia "z górnej półki". I wszystko za darmo (pomijając aspekt czasu, który wierzę, że dzięki temu artykułowi spadnie do niezbędnego minimum).
Jako narzędzie pretendujące do miana narzędzia wspierającego zarządzanie projektem informatycznym, Maven2 dostarcza 3 predefiniowanie sekwencje projektowe: default, clean oraz site. Każda sekwencja składa się z etapów. Ilość etapów jest specyficzna dla sekwencji, ale istnieje możliwość ich zmiany. Poniższa tabela przedstawia nazwy etapów dla predefiniowanych sekwencji projektowych w Maven2.
Sekwencja | Etap | |||||||||||||||||||||
default |
| |||||||||||||||||||||
clean |
| |||||||||||||||||||||
site |
|
Z sekwencją i poszczególnym jej etapem związane są pewne wtyczki i ich zadania (aka czynności). Jednym z bardzo trafnych stwierdzeń z jakim się spotkałem to określenie Maven jako środowiska do uruchamiania wtyczek, które z kolei dostarczają zadań (porównać to można do wirtualnej maszyny Javy, która jest środowiskiem uruchomieniowym klas, bądź też do kontenera serwletów, które jest środowiskiem dla serwletów). Etap może nie posiadać przypisanego zadania wtyczki, albo może istnieć ich więcej. Istnieje dodatkowo możliwość przypisania zadania wtyczki do etapu sekwencji w konfiguracji projektu (pom.xml) za pomocą znacznika execution (który będzie tematem przewodnim kolejnego artykułu). Sam typ projektu (wartość znacznika packaging, tj. pom, jar, maven-plugin, ejb, war, ear, rar, par, ejb3) również wyznacza określone wtyczki i ich zadania do poszczególnych etapów. Poniższa tabela przedstawia nazwy etapów dla wspomnianych typów packaging.
packaging | sekwencja | etap | wtyczka:zadanie | ||
pom | default | package | org.apache.maven.plugins:maven-site-plugin:attach-descriptor | ||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
jar | default | process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-jar-plugin:jar | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
maven-plugin | default | generate-resources | org.apache.maven.plugins:maven-plugin-plugin:descriptor | ||
process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package |
| ||||
install |
| ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
ejb | default | process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-ejb-plugin:ejb | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
war | default | process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-war-plugin:war | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
ear | default | generateresources | org.apache.maven.plugins:maven-ear-plugin:generate-application-xml | ||
process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||||
package | org.apache.maven.plugins:maven-ear-plugin:ear | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
rar | default | process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-rar-plugin:rar | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
par | default | process-resources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-test-resources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-par-plugin:par | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy | ||||
ejb3 | default | processresources | org.apache.maven.plugins:maven-resources-plugin:resources | ||
compile | org.apache.maven.plugins:maven-compiler-plugin:compile | ||||
process-testresources | org.apache.maven.plugins:maven-resources-plugin:testResources | ||||
test-compile | org.apache.maven.plugins:maven-compiler-plugin:testCompile | ||||
test | org.apache.maven.plugins:maven-surefire-plugin:test | ||||
package | org.apache.maven.plugins:maven-ejb3-plugin:ejb3 | ||||
install | org.apache.maven.plugins:maven-install-plugin:install | ||||
deploy | org.apache.maven.plugins:maven-deploy-plugin:deploy |
Rozpoczynając pracę, Maven2 rozpoczyna od wyznaczenia sekwencji i jej etapów. Następnie mapuje je na odpowiednie zadania wtyczek (w tym celu odczytuje predefiniowaną konfigurację sekwencji i nakłada na to definicję etapów związaną z packaging i executions) i ostatecznie wykonuje zadania zgodnie z ich kolejnością wyznaczoną przez etapy w sekwencji. Kolejność wykonywania zadań można prześledzić podczas uruchomienia mvn, gdzie każda wtyczka i jej zadanie wypisywane są w schemacie [INFO] [wtyczka:zadanie], np. [INFO] [jar:jar]. Poza wyspecyfikowaniem etapu istnieje również możliwość uruchomienia Maven2 z konkretnym zadaniem wtyczki. Definicja domyślnie wykonywanego zadania bądź etapu w projekcie może również zostać wyspecyfikowana w sekcji <build> jako <defaultGoal> w pom.xml. Jeśli nie podano etapu bądź zadania na linii poleceń, Maven2 oczekuje wspomnianej konfiguracji projektu w sekcji <defaultGoal>.
Przyjrzyjmy się kilku przykładom dla zobrazowania przedstawionego materiału. Zakłada się, że wykonanie poniższych poleceń odbywa się w projekcie obsługiwanym przez Maven2 (innymi słowy istnieje plik pom.xml).
- Uruchamiamy polecenie mvn bez wyspecyfikowanego etapu bądź zadania wtyczki.
$ mvn
Osobiście uważam, że komunikat jest mylący, gdyż install nie jest zadaniem (goal), ale etapem (phase) w sekwencji (lifecycle) default. Należy zatem rozumieć ten komunikat jako wskazanie do wykonania wszystkich zadań przypisanych do etapów w sekwencji default, począwszy od pierwszego a skończywszy na install.
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ----------------------------------------------------------------------------
[INFO] You must specify at least one goal. Try 'install'
[INFO] ----------------------------------------------------------------------------
...
Sprawdźmy, czy istnieje Polskie tłumaczenie, które może być bardziej adekwatne.$ mvn -Duser.language=pl_PL
Niestety w tym przypadku takie tłumaczenie nie istnieje i uruchomienie z opcją -e również nie dostarcza więcej informacji. Niektóre jednak komentarze Maven2 zostały spolonizowane.
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ----------------------------------------------------------------------------
[INFO] You must specify at least one goal. Try 'install'
[INFO] ----------------------------------------------------------------------------
... - Uruchommy polecenie mvn z nazwą nieistniejącego etapu, np. etap.
$ mvn etap
Komunikat jest tym razem bardziej dokładny i dowiadujemy się, że konieczne jest podanie istniejącego etapu bądź zadania w odpowiednim formacie (temat wtyczek będzie tematem jednego z kolejnych artykułów).
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ----------------------------------------------------------------------------
[INFO] Invalid task 'etap': you must specify a valid lifecycle phase, or a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal
[INFO] ----------------------------------------------------------------------------
... - Uruchommy polecenie mvn z poprawnym etapem w sekwencji default, np. test.
$ mvn test
Jak można zauważyć wykonanie etapu test zakończy się pomyślnie, a w trakcie wykonywania kolejnych etapów zostaną wykonane zadania wtyczek przypisanych do nich.
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Projekt Demonstracyjny Maven2
[INFO] task-segment: [test]
[INFO] ----------------------------------------------------------------------------
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
...
[INFO] [resources:testResources]
...
[INFO] [compiler:testCompile]
...
[INFO] [surefire:test]
...
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
... - Uruchommy powyższe polecenie ponownie zmodyfikowawszy wartość packaging w pom.xml, np. maven-plugin.
$ mvn test
Tym razem wykonane zadania różnią się o początkową wtyczkę plugin. Jest to potwierdzenie wpływu konfiguracji sekcji packaging na listę zadań do wykonania.
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[INFO] Building Projekt Demonstracyjny Maven2
[INFO] task-segment: [test]
[INFO] ----------------------------------------------------------------------------
...
[INFO] [plugin:descriptor]
...
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
...
[INFO] [resources:testResources]
...
[INFO] [compiler:testCompile]
...
[INFO] [surefire:test]
...
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ---------------------------------------------------------------------------- - Uruchommy polecenie mvn z podaniem wtyczki surefire bez wskazania jej zadania.
$ mvn surefire
Zgodnie z komunikatem parametr bez dwukropka traktowany jest jako nazwa etapu, a skoro taki nie istnieje Maven2 kończy działanie z komunikatem błędu.
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ----------------------------------------------------------------------------
[INFO] Invalid task 'surefire': you must specify a valid lifecycle phase, or a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal
[INFO] ----------------------------------------------------------------------------
[INFO] For more information, run Maven with the -e switch
[INFO] ---------------------------------------------------------------------------- - Uruchommy polecenie mvn z wyspecyfikowaną wtyczką surefire z zadanym zadaniem, np. test, który mogliśmy zauważyć uruchamiany we wcześniejszych przykładach (wraz z innymi poprzedzającymi zadaniami).
$ mvn surefire:test
Na uwagę zasługuje fakt, że wykonanie wtyczki nie zostało poprzedzone wykonaniem żadnego innego zadania, co pozwala na uruchomienie wtyczek pojedyńczo. Jest to szczególnie przydatne z wtyczkami, które nie są przypisane do żadnej sekwencji.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'surefire'.
[INFO] ----------------------------------------------------------------------------
[INFO] Building Projekt Demonstracyjny Maven2
[INFO] task-segment: [surefire:test]
[INFO] ----------------------------------------------------------------------------
[INFO] [surefire:test]
...
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ---------------------------------------------------------------------------- - Na koniec uruchommy polecenie mvn z 2 etapami należącymi do różnych sekwencji oraz zadanie wtyczki, której wykonanie jest częścią uruchamiania etapów.
$ mvn clean package surefire:test
Wszystkie etapy oraz zadanie zostały poprawnie rozpoznane przez Maven2. Wykonanie etapów wiąże się z wyznaczeniem wtyczek i ich zadań, a następnie uruchomieniu zgodnie z kolejnością związanych z nimi etapów. Wyjątek stanowi wykonanie zadania surefire:test, który jest wykonany zgodnie z jego pozycją na linii poleceń, czyli po pomyślnym uruchomieniu zadań związanych z etapami.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'surefire'.
[INFO] ----------------------------------------------------------------------------
[INFO] Building Projekt Demonstracyjny Maven2
[INFO] task-segment: [clean, package, surefire:test]
[INFO] ----------------------------------------------------------------------------
[INFO] [clean:clean]
...
[INFO] [plugin:descriptor]
...
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
...
[INFO] [resources:testResources]
...
[INFO] [compiler:testCompile]
...
[INFO] [surefire:test]
...
[INFO] [jar:jar]
...
[INFO] [plugin:addPluginArtifactMetadata]
[INFO] [surefire:test]
...
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
Znajomość wtyczek i dostarczanych przez nie zadań jest istotnym elementem zrozumienia działania Apache Maven. Wersja druga projektu - Maven2 - wprowadza kolejne pojęcia - sekwencja (lifecycle) oraz etap (phase). Wyróżniamy 3 predefiniowane sekwencje z zadanymi etapami, do których przypisane są zadania wtyczek. Dzięki takiemu podejściu projekty mogą skorzystać z dobrych praktyk inżynierskich podnoszących jakość projektu niewielkim kosztem. Znajomość Maven2 i jego konfiguracji oraz umiejętność zrozumienia zawartości pom.xml pozwala na łatwe wdrożenie nowych osób do projektu z punktu widzenia jego zarządzania. Poza samym tworzeniem elementów składowych projektu - klasy, konfiguracje, modele, etc. - jest to kluczowy składnik wpływający na czasowe zakończenie projektu. Znosi to również konieczność wprowadzania tych samych ustawień z projektu na projekt (nawet mimo możliwości ich kopiowania, które zazwyczaj kończy się błędami trudnymi do zdiagnozowania). Temat jest stosunkowo zawiły, ale sądzę, że lektura artykułu pozwoli na łatwiejsze zrozumienie działania Maven2.
ADNOTACJA: Nie spotkałem się jeszcze z polskimi odpowiednikami pojęć - lifecycle, phase oraz goal w kontekście Maven, więc pokusiłem się na ich własne spolszczenie. Jeśli znasz lepsze dla nich polskie tłumaczenia, koniecznie się ze mną skontaktuj. Jako rekompensatę mogę jedynie obiecać opublikowanie imienia i nazwiska wraz z ciekawymi propozycjami w kolejnych artykułach.
Komentarze, spostrzeżenia mile widziane. Skorzystaj z możliwości komentowania artykułu, poniżej, albo wyślij komentarz na moją skrzynkę.
Ostatnia prezentacja Maven2 na PLBUG odbyła się bez slajdów. Przyznaję, że gdyby były, to zdecydowanie poprawiłoby to wartość prezentacji i zamierzam to na kolejnych spotkaniach zmienić. Przygotowanie interesującej prezentacji samo w sobie jest już nie lada wysiłkiem i zabiera czas, a w lato zawsze go mało ;)
OdpowiedzUsuńNapisz, co by Cię interesowało odnośnie Maven2 i innych projektów wolnodostępnych. Takie komentarze jak ten świadczą o potrzebie tego typu artykułów i póki, co nie planuję zaprzestania ich pisania.
Wielkie dzięki za noty!
Jacek
Najwiekszym problemem Maven2 jest brak sensownej dokumentacji.
OdpowiedzUsuńZ tego powodu proste rzeczy jest zrobic bardzo latwo, a przy trudniejszych sprawach rozbijamy sie o sciane.
Wkurzaja mnie rowniez "niespojnosci" na defaultowych repository. Dodalem do projektu zaleznosc od hibernate 3.1.x, ten wymaga ejb3, a w repository brakuje "jar"'ow i proces budowania lezy. Koniecznoscia staje sie zatem utrzymywanie lokalnego repository. To znaczaco zwieksza stopien skomplikowania projektu, bo juz nie wystarczy ze dam komus zrodla, trzeba zadbac jeszcze o zaleznosci.
Kolejna sprawa to "sztywnosc" zaleznosci. Uzywalem commons-email wymagajacego JavaMail API 1.33. Tymczasem mamy juz JavaMail 1.4. Aby przetestowac obie biblioteki ze soba trzeba zmieniac recznie zaleznosci w repository. Dlaczego na poziomie projektu nie moge wymusic takiej zaleznosci? A moze moge, tylko jeszcze nie znalazlem jak?
Mimo tego wszystkiego, Maven2 to na pewno dobry krok w celu standaryzacji procesu wytwarzania oprogramowania.
Osobiscie poczytalbym chetnie o integracji Mavena2 z zadaniami Anta do realizacji niestandardowych wymagan klienta.
Początek artykułu z wielkim zadęciem, ale szybko się zgubiłem. Zaczynasz tak jakby maven był procesem (metodologią) prowadzenia projektów, a potem zaraz jest o skryptach do wykonywania buildu. No i co takiego niesamowitego jest w tym narzędziu - nie znam go, ale nie widzę czym różni się od ant-a czy innych skryptów buildujących. Skąd zatem pomysł że jak ktoś go nie używa to marnuje czas, albo że to taki przełom - nie przełom, tylko wybór jednego z wielu narzędzi według mnie.
OdpowiedzUsuń'Anonymous' zycze powodzenia przy tworzeniu duzego projektu bez kontroli wersji nad ktora tak ciezko przeciez zapanowac w przypadu Ant'a. Poza tym kontrola dowiazan w Maven jest bardzo przydatna. Maven jest zbyt skomplikowany dla malych projektow i powinno sie go stosowac tam gdzie kontrola wersji i zaleznosci stanowi kluczowa role.
OdpowiedzUsuńSam artykul bardzo mi sie podobal, jak wiele innych zreszta. Szkoda, ze nie bylo mowy o Maven1.x(i Jelly oczywiscie, ktorgo w Maven2.x chyba juz nie ma), bo poki co wlasnie z tej wersji jestem zmuszony korzystac. Moze w nastepnej publikacji bedzie wicej o roznicach miedzy 1.x a 2.x - poza tym, ze jest szybszy, lepszy doskonalszy ;-)
Serdecznie pozdrawiam