JAVA exPress logo Opublikowane na JAVA exPress (http://www.javaexpress.pl)

Gradle - Mocarne narzędzie do budowy projektów

Tomasz Kaczanowski

Numer 6 (2009-12-09)

Wstęp

"Jakiego narzędzia używasz do budowy projektu i dlaczego?" W świecie Javy, na tak zadane pytanie można spodziewać się jednej z dwóch odpowiedzi:

Używam Mavena. Świetne pluginy pozwalają mi w trzech liniach uzyskać efekt, na który potrzebowałbym kilkadziesiąt linii XMLa, gdybym używał Anta. Czasami przeszkadza mi brak elastyczności Mavena, ale radzę sobię wówczas używając plugina AntRun.

-- użytkownik Mavena

Używam Anta i dzięki jego elastyczności mogę zrobić wszystko - co tylko zechcę. Maven zdobył popularność dzięki zarządzaniu dependencjami, ale ja mam Apache Ivy, który potrafi o wiele więcej.

-- użytkownik Anta

Nie mam zamiaru powtarzać tu argumentów, którymi zwolennicy Anta i Mavena wymieniali się wielokrotnie w niezliczonych dyskusjach na czatach, forach i blogach. Po pierwsze dlatego, że nie pojawiły się żadne nowe argumenty na rzecz któregokolwiek z tych dwóch rozwiazań. Po drugie dlatego (i to jest główny powód), że na scenie narzędzi do budowy projektów pojawił się nowy zawodnik - Gradle. I jest to gracz tak silny, że ma wszelkie szanse by usunąć w cień zarówno Anta jak i Mavena, a dyskusję o wyższości jednego nad drugim przesunąć do historii komputerowych "flame wars".

Jakiego narzędzia używasz do budowy projektu i dlaczego?

Nim zajmiemy się Gradlem, przyjrzyjmy się najbardziej znanym (czyt. uciążliwym) słabościom Anta i Mavena:

Aby móc w pełni skorzystać z lektury tego artykułu, zachęcam do instalacji Gradle. Instrukcja instalacji znajduje się na stronie projektu. Dla Twojej wygody do artykułu dołączone są kody źródłowe. Zarówno artykuł jak i kod źródłowy jest zgodny z wersją 0.8 Gradle (najnowszą w momencie pisania artykułu).

Celem tego artykułu jest przedstawienie projektu Gradle i sprawienie, byś zapragnął poznać go lepiej. Nie zamierzam konkurować z wyczerpującą dokumentacją ani z dołączonymi do dystrybucji Gradle przykładami.

Gradle - krótkie wprowadzenie

W artykule przedstawię Gradle prezentując kilka z życia wziętych przykładów jego zastosowania. Jednak nim to nastąpi, pozwolę sobie pokrótce scharakteryzować ten projekt, tak byś wiedział czego możesz oczekiwać.

Gradle jest bardzo elastycznym narzędziem do budowy projektów, w szczególności projektów Javy. Umożliwia pisanie skryptów budujących w opartym na Groovym DSLu, co sprawia, że wyrażenie w nich algorytmów staje się banalnie proste. Gradle pozwala na tworzenie zależności między zadaniami (taskami) i opiera się na paradygmacie "convention over configuration" (z tym że konfiguracja jest zawsze możliwa i łatwa do przeprowadzenia). Gradle wykracza poza możliwości innych narzędzi, jednocześnie stosuje się do przyjętych przez społeczność Javy niepisanych standardów, obniżając w ten sposób koszt związany ze zmianą narzędzia budującego.

Gradle jest nadal w trakcie developmentu, osiągnął już jednak stabilność, pozwalającą na jego produkcyjne użycie. Lista zaimplementowanych funkcjonalności jest już obecnie imponująca (na uwagę zasługuje m.in. zaawansowane wsparcie dla projektów wielomodułowych), a do realizacji czeka jeszcze wielu wartościowych pomysłów (m.in. możliwość pisania skryptów budujących w DSLach opartych o inne niż Groovy języki JVM - np. Scala, JRuby).

Pierwszy skrypt budujący

Obiecałem zaprezentować Gradle poprzez przykłady jego użycia, zajmijmy się więc napisaniem kawałka kodu. Zaczniemy od bardzo prostej aplikacji webowej. Następnie rozszerzę ten przykład, co pozwoli mi zaprezentować różne cechy Gradle - przede wszystkim dynamicznę naturę jego skryptów oraz wsparcie dla projektów wielomodułowych.

Najmniejsza na świecie aplikacja webowa ;)

Layout naszego projektu prezentuje się następująco:

    myWebApp
    `-- src
        `-- main
            |-- java
            |   `-- org
            |       `-- gradle
            |           `-- sample
            |               `-- Greeter.java
            `-- webapp
                `-- index.jsp

Jak widać projekt jest prosty aż do bólu. Ma tylko jedną klasę (Greeter.java), która wykorzystuje metody z biblioteki Commons Lang ze zbioru Apache Commons, oraz jedną stronę JSP - index.jsp - która używa tejże klasy.

build.gradle

Czas dodać skrypt budujący - nadamy mu domyślną nazwę build.gradle. Skrypt ten powinien wykonać następujące zadania:

Gradle jest bardzo elastycznym narzędziem
do budowy projektów, w szczególności projektów Javy.

A więc proszę - przed nami pierwszy skrypt budujący napisany z użyciem Gradle.

    usePlugin 'war'
    version = 0.1

    repositories {
        mavenCentral()
    }

    dependencies {
        compile "commons-lang:commons-lang:2.4"
    }

Informacje o procesie budowania

Używając Gradle możesz z łatwością dowiedzieć się wielu użytecznych informacji na temat procesu budowania projektu. Wykonaj komendę gradle --tasks aby poznać dostępne zadania (te napisane przez Ciebie i dostarczone przez zadeklarowane w skrypcie budującym pluginy). Wykonaj gradle --properties żeby poznać wszystkie propertiesy i gradle --dependencies by dowiedzieć się o wszystkich zależnościach projektu. Ale przede wszystkim wykonaj komendę gradle -? by poznać mnóstwo innych przydatnych komend.

Umieść ten plik w głównym folderze projektu myWebApp main i uruchom pisząc w linii komend gradle war. Wynikowy plik myWebApp-0.1.war znajdziesz w folderze build/libs. Zdeployuj go w dowolnym kontenerze webowym (np. Tomcatcie) i rozkoszuj się aplikacją działającą pod adresem http://YourHostName/myWebApp-0.1.

Podejrzewam, że w powyższym skrypcie Twoją uwagę przykuło kilka spraw:

Gradle stosuje rozpowszechnioną przez Mavena
strukturę projektu.

Powiedz to tak po prostu

Chciałbyś użyć w skrypcie plugina War ? Chciałbyś ustawić wersję na 1.0 ? Po prostu to powiedz:

    usePlugin 'war'
    version = 0.1
    

Chciałbyś wypisać komunikat jeżeli zajdzie pewien warunek ? Po prostu to powiedz:

    if (someCondition) {
      println "some message"
    }
    

Jeżeli zastanowisz się nad tymi dwoma przykładami, dojdziesz do wniosku, że nie ma w nich nic niezwykłego. "Tak to powinno wyglądać". Masz rację. A jednak, wyrażenie tych jakże prostych rzeczy jest bardzo trudne w Antcie i Mavenie. Gradle, używając mieszanki DSL i Groovyego, daje możliwość bezpośredniego wyrażania tego, co pragniesz powiedzieć.

Tak, to wszystko prawda, ale zapewniam że to dopiero początek. Póki co, przyjrzyjmy się dokładniej temu, co (i jak) robi ten skrypt.

DSL i "convention over configuration"

Prawdopodobnie zauważyłeś, że zaprezentowany plik build.gradle jest bardzo zwięzły. Jest to możliwe dzięki dwóm cechom Gradle:

Przykładowo, Gradle stosuje rozpowszechnioną przez Mavena strukturę projektu, i domyślnie zakłada, że pliki źródłowe znajdują się w następujacych folderach:[1]

 

    `-- src
        |-- main
        |   |-- groovy    // kod źródłowy pisany w Groovym
        |   |-- java      // kod źródłowy pisany w Javie
        |   |-- resources // zasoby aplikacji
        |   `-- webapp    // kod źródłowy aplikacji webowej
        `-- test
            |-- groovy    // testy napisane w Groovym
            |-- java      // testy napisane w Javie
            `-- resources // zasoby testowe

Inna konwencja sprawia, że stworzony przez Gradle plik WAR domyślnie nosi nazwę tworzoną według wzorca nazwaProjektu-wersja.war (z kolei nazwa projektu jest identyczna z nazwą folderu, w którym projekt się znajduje, o ile nie wyspecyfikowano inaczej). Inną domyślną wartością jest użycie kompilatora Javy w wersji 1.5.

Konfiguracja jest możliwa i łatwa do wykonania

Jeżeli zajdzie taka potrzeba, wówczas wszystkie powyższe domyślne ustawienia można z łatwością zmodyfikować. Przykładowo, załóżmy że chcemy, by wszelkie artefakty (pliki JAR i WAR) trafiały do katalogu build/artifacts zamiast do domyślnego build/libs. Wystarczy ustawić wartość zmiennej libsDirName na "artifacts":

    libsDirName = "artifacts"

Aby zmienić nazwę generowanego pliku JAR czy WAR należy z kolei ustawić wartość zmiennej archivesBaseName:

    archivesBaseName = "i-dont-like-the-default-name"

Ponieważ prezentowana aplikacja myWebApp wykorzystuje domyślne ustawienia, nie ma więc potrzeby modyfikowania wartości tych zmiennych, skutkiem czego plik budujący jest bardzo krótki.

Gradle pluginami stoi.

W pluginach siła

Zgodnie z aktualną modą, Gradle pluginami stoi. :) Każdy plugin może rozszerzyć zasób funkcji oferowanych przez Gradle na trzy sposoby. Dla przykładu, użycie w skrypcie budującym pluginu Java niesie za sobą następujące konsekwencje:

W zaprezentowanym skrypcie użyty został plugin War, co ma następujące konsekwencje:

Obecnie Gradle oferuje 9 pluginów (Java, Groovy, War, OSGi, Eclipse, Jetty, Maven, Project-reports, Code-quality), a jeżeli nie znajdziesz wśród nich potrzebnej Ci funkcjonalności, zawsze możesz napisać swój własny (jest to bardzo proste, acz wykracza poza ramy tego artykułu - zerknij proszę do dokumentacji Gradle).

Repozytoria i zarządzanie zależnościami

Mam dla Ciebie dobrą wiadomość - jak już przepiszesz swoje skrypty budujące na Gradle, będziesz mógł nadal używać tych samych repozytoriów artefaktów, których używasz obecnie. Gradle opiera się na Apache Ivy, i potrafi "dogadać się" z każdym możliwym do wyobrażenia typem repozytorium - od "standardowych" repozytoriów Mavena, poprzez staroświeckie foldery libs używane tradycyjnie w buildach Anta, aż po niemal dowolne repozytorium o zdefiniowanej przez programistę strukturze.

Jak widać na przykładzie pierwszego skryptu, osiągnięcie rzeczy prostych jest w Gradle nie tylko łatwe, ale i daje się elegancko wyrazić. Aby Gradle przeszukiwał centralne repozytorium Mavena w poszukiwaniu wymaganych artefaktów, wystarczy dodać takie oto linijki do skryptu budujacego:

    repositories {
        mavenCentral()
    }

Osiągnięcie rzeczy prostych
jest w Gradle nie tylko łatwe,
ale i daje się elegancko wyrazić.

Deklaracje dependencji są o wiele bardziej zwięzłe, niż te, którymi posługujesz się w Mavenie 2[2] lub Ivy. Zamieszczony poniżej kawałek kodu dodaje JAR biblioteki Commons Lang do classpatha komplikacji:

    dependencies {
        compile "commons-lang:commons-lang:2.4"
    }

Ant i Gradle

Gradle zapewnia świetną integrację z Antem. Możesz zaimportować Antowy plik build.xml bezpośrednio do skryptu budującego Gradle. Dzięki temu wszelkie targety z pliku Anta, staną się dostępne jako taski Gradle. Inny typ integracji zapewnia dostaczana przez Groovyego klasa AntBuilder. Obiekt ant jest dostępny w każdym skrypcie budującym Gradle, dzięki czemu możesz używać całego bogactwa tasków Anta - począwszy od prostych takich jak javac, copy, jar, aż po bardziej złożone - np. selenese (do uruchamiania testów Selenium) czy findbugs (do generowania raportów ze statycznej analizy kodu narzędziem Findbugs).

To wszystko czyni migrację z Anta do Gradle możliwie bezbolesną... a gdy już jej dokonasz, to nie spodziewam się byś kiedykolwiek zechciał do Anta powrócić. :)

Pisanie własnej logiki

Jak dotąd polegaliśmy wyłącznie na funkcjonalnościach oferowanych przez Gradle. Najwyższy czas, by dorzucić nieco własnej wymyślnej funkcjonalności. W ten sposób poznamy też klika nowych możliwości Gradle.

Liczenie sum kontrolnych pliku (z użyciem Anta)

Napiszemy teraz taska, który policzy sumy kontrolne plików z katalogu build/libs (domyślny katalog, do którego trafiają stworzone pliki JAR i WAR). Ponieważ wierzymy mocno w reużycie kodu, wykorzystamy w tym celu task checksum dostępny w Antcie. Dodaj poniższy kawałek kodu do pliku build.gradle i wykonaj polecenie gradle clean checksum.

 

 

 

    task checksum (dependsOn: assemble) << {
        def files = file(libsDir).listFiles()
        files.each { File file ->
            ant.checksum(file: file, property: file.name)
            println "$file.name Checksum: ${ant.properties[file.name]}"
        }
    }

Gradle zapewnia świetną integrację z Antem.

W tych kilku linijkach kodu dzieje się całkiem sporo - widać użycie skryptów Groovyego, definiowanie zależności miedzy taskami i użycie tasków Anta.

Po pierwsze, tworzony jest nowy task o nazwie checksum, który zależy od taska assemble dostarczanego przez plugin Java (ten task odpowiedzialny jest za tworzenie plików JAR i WAR). Następna linijka, napisana w Groovym, sprawia że wszystkie pliki z katalogu libsDir (wartosc tego property jest domyślnie ustawiana przez plugin Java i wskazuje na katalog build/libs) trafiają do listy. W końcu na każdym z plików z listy wywoływany jest Antowy task checksum, a wynik wypisywany jest na standardowe wyjście.

Snapshoty i wersje stabilne

W świecie Javy przyjęło się, że nazwy artefaktów odzwierciedlają fakt, czy artefakty te są stabilne (tzw. releasy) czy też nie (snapshoty). Snapshoty zwyczajowo otrzymują suffix "-SNAPSHOT", co sprawia że łatwo odróżnić je od wersji stabilnych. Zaimplementujmy teraz w naszym skrypcie budującym ten schemat nazewniczy artefaktów.

Poniższy fragment pliku build.gradle pokazuje bardzo interesującą cechę Gradla. Otóż wywołanie skryptu budującego podzielone jest na dwie fazy. W pierwszej konstruowany jest acykliczny graf zależności miedzy taskami (DAG, ang. dependency acyclic graph). W drugiej fazie następuje właściwe wywołanie tasków. Poniższy prosty przykład pokazuje, że jest możliwe "wejście" pomiedzy te dwie fazy i wykonanie pewnych operacji na grafie tasków, nim nastąpi ostateczne wykonanie tasków. W tym prostym przykładzie, graf tasków jest analizowany i na podstawie tej analizy podejmowana jest decyzja o nazwie wynikowego pliku:

    task release(dependsOn: assemble) << {
        println 'We release now'
    }

    build.taskGraph.whenReady { taskGraph ->
        if (taskGraph.hasTask(':release')) {
            version = '1.0'
        } else {
            version = '1.0-SNAPSHOT'
        }
    }

Wykonaj skrypt budujący dwukrotnie - pierwszy raz wywołując komendę gradle clean assemble, a następnie gradle clean release. Sprawdź w katalogu build/libs jakie nazwy otrzymały wynikowe pliki.

Tworzenie raportu z testów

Wyobraź sobie, że wykorzystujesz Gradle do umieszczenia bundli z testami integracyjnymi (napisanymi z użyciem TestNG) w środowisku OSGi, w którym działają moduły testowanej aplikacji. Modułów tych jest ponad 10, i ulegają one częstym zmianom (jako że wszystkie są jeszcze we wczesnym stadium developmentu). Chciałbyś wygenerować raport z testów, który zawierałby:

Dużo lepszym rozwiązaniem jest
stworzenie własnego taska i wywołanie go
z odpowiednimi parametrami z poziomu skryptu budującego.

Możliwe jest upchnięcie całej logiki tworzenia raportu bezpośrednio do skryptu budującego, ale wówczas ten urósłby nieprzyzwoicie i stałby się nieczytelny. Dużo lepszym rozwiązaniem jest stworzenie własnego taska i wywołanie go z odpowiednimi parametrami z poziomu skryptu budującego. Plik build.gradle wyglądałby w zarysie tak:

    import org.gradle.sample.report.ReportTask

    ...

    dependencies {
        compile 'commons-lang:commons-lang:2.4'
        testRuntime 'org.easymock:easymock:2.5.2'
        // much more dependencies here
    }

    ...

    task report(type: ReportTask, dependsOn: itest) {
            reportDir = 'build/report'
            testNgResultsDir = 'build/itest/test-result'
            serverLogDir= 'build/itest/server-log'
            jars = configurations.testRuntime
    }

A tak wygladałaby klasa tasku (z pominięciem nieistotnych szczegółów):

    public class ReportTask extends DefaultTask {

        def String reportDir
        def String testNgResultsDir
        def String serverLogDir
        def FileCollection jars

        @TaskAction
        def createReport() {
            def text = new StringBuilder()
            ["os.name", "os.version", "java.version", "java.vm.version",
                "java.runtime.version", "user.language", "user.name"].each {
                    text.append(it + ":\t${System.getProperty(it)}\n")
             }

            text.append("gradle -v".execute().text)

            jars.each {
                    text.append("$it.name\n")
            }

            ...

            ant.zip(destfile: zipReportFile, basedir: tmpDir)
        }

        ...
    }

Te dwa kawałki kodu demonstrują kilka godnych uwagi rzeczy. Po pierwsze, wszelkie typowe operacje na plikach (kopiowanie, tworzenie archiwum ZIP, usuwanie itd.) są bardzo łatwe do wykonania, gdy można użyć skryptów Groovyego (w tym klasy AntBuilder). Po drugie, stworzenie własnego, reużywalnego taska, a następnie skonfigurowanie go i wywołanie, jest bardzo proste. W tym przypadku task ReportTask przyjmuje cztery parametry, których dostarcza mu skrypt budujący (taki podział pozwala na wyrzucenie prawdziwej logiki biznesowej poza skrypt). Po trzecie w końcu, przykład ten pokazuje, że dependencje w Gradle można przetwarzać w najróżniejszy sposób - w powyższym przykładzie wykorzystujemy ten fakt do banalnego zadania wypisania ich do pliku raportu.

Jeden czy wiele skryptów budujących ?

Najważniejsze jest to, że można uzyskać ten sam efekt stosując oba podejścia. Dla przykładu, jeżeli chcemy dodać do projektu core dependencję w postaci biblioteki Commons Lang, to możemy albo dodać ten kawałek kodu do pliku build.gradle w głównym katalogu:

    project (':core') {
      dependencies {
        compile "commons-lang:commons-lang:2.4"
      }
    }
    

albo dodać tę linijkę do pliku build.gradle w podkatalogu core:

    dependencies {
        compile "commons-lang:commons-lang:2.4"
    }
    

Jak widzisz, jest to jedynie kwestia smaku.

Budowa projektów wielomodułowych

Nasza aplikacja webowa potrzebuje kolejnego interfejsu użytkownika - napiszemy go w Swingu. Jest to dobry moment, by podzielić projekt na trzy części - przy okazji prezentując fragment tego, co Gradle ma nam do zaoferowania w kontekście budowy projektów wielomodułowych:

Layout projektów wielomodułowych

Gradle oferuje dużą elastyczność, jeżeli chodzi o layout projektów wielomodułowych. Na potrzeby tego artykułu, zastosuję layout hierarchiczny (na poniższym schemacie pominąłem zawartość katalogów src):

    .
    |-- build.gradle
    |-- settings.gradle
    |-- core
    |   `-- src
    `-- ui
        |-- swing
        |   `-- src
        `-- web
            `-- src

W głównym katalogu znajdują się dwa podkatalogi - na projekt core, i drugi nazwany ui. W podkatalogu ui znajdują się wszystkie projekty związane z budową interfejsu użytkownika - obecnie są to dwa projektu swing i web.

Gradle oferuje dużą elastyczność,
jeżeli chodzi layout projektów wielomodułowych.

Jak widać cały projekt wielomodułowy posiada tylko jeden skrypt budujący build.gradle. Można zastanawiać się, czy dobrym pomysłem jest zawarcie całej logiki budowania w jednym miejscu. Jeżeli uznamy, że nam to nie odpowiada, Gradle spełi naszą zachciankę i pozwoli na stworzenie oddzielnych skryptów budujących dla każdego podkatalogu.[3]

settings.gradle

Po piersze przyjrzyjmy się plikowi, którego dotąd jeszcze nie napotkaliśmy: settings.gradle. W nim właśnie znajdują się informacje o layoucie projektu[4]. Jak widać poniżej, wskazuje on Gradleowi w jakich podkatalogach znajdują się poszczególne moduły (podprojekty):

    include "core", "ui:swing", "ui:web"

Zanim przyjrzymy się skryptowi budującemu
zastanówmy się jakie zadania powinien on wykonywać.

build.gradle

Zanim przyjrzymy się skryptowi budującemu, zastanówmy się jakie zadania powinien on wykonywać. Wydaje się, że są one następujace:

Plik budujący build.gradle przedstawiony jest poniżej.

    subprojects {
      usePlugin 'java'
      group = 'org.gradle.sample'
      version = '1.0'

      repositories {
        mavenCentral()
        flatDir(name: 'fileRepo', dirs: "./repo")
      }

      uploadArchives {
        repositories {
          add project.repositories.fileRepo
        }
      }

    }

    project (':core') {
      dependencies {
        compile "commons-lang:commons-lang:2.4"
      }
    }

    project (':ui') {
      subprojects {
        dependencies {
         compile project (':core')
        }
      }
    }

    project (':ui:web') {
      usePlugin 'war'
    }

    project (':ui:swing') {
      usePlugin 'groovy'
      dependencies {
        groovy "org.codehaus.groovy:groovy-all:1.6.5"
      }
    }

Nawet jeżeli pierwszy raz w życiu widzisz plik build.gradle opisujący budowę projektu wielomodułowego, nie powinieneś mieć problemów z jego zrozumieniem. Po pierwsze, korzystając z property subprojects, skrypt ustawia pewne własności wspólne dla wszystkich podprojektów (core, swing i web). W ten sposób wszystkie podprojekty będą:

Po ustawieniach wspólnych dla wszystkich podprojektów, każdy z podprojektów konfigurowany ejst osobno. Projekt core otrzymuje zależność od biblioteki Commons Lang. Oba projekty interfejsu użytkownika są zależne od projektu core. Następnie do projektu web dodany jest plugin War. W końcu, projekt swing zostaje skonfigurowany jako projekt Groovyego (co sprowadza się do dodania do niego pluginu Groovy i dopisania zależności od biblioteki Groovyego).

Budowa projektu - pełna i częściowa

W przypadku projektu wielomodułowego pojawia się pytanie "ale co właściwie chciałbyś zbudować?". A więc, chciałbyś zbudować oba projekty interfejsu użytkownika, czy może tylko jeden z nich?

Aby zbudować wszystkie projekty, wykonaj komendę gradle build z poziomu głównego katalogu projektu. Zauważysz, że w procesie budowania powstaną trzy artefakty: core-0.1.jar, swing-0.1.jar i web-0.1.war.

Gradle umożliwia wykonywanie częściowych buildów,
a nam nie pozostaje nic innego
jak z tej możliwości ochoczo korzystać.

Jeżeli chcemy wybudować wyłącznie jeden z interfejsów użytkownika, możemy użyć tasku buildNeeded[5]. Na przykład, wykonanie polecenia gradle buildNeeded w podkatalogu ui/swing, poskutkuje zbudowaniem wyłącznie projektów core i swing oraz stworzeniem dwóch artefaktów: core-0.1.jar i swing-0.1.jar.

Wniosek z tego wszystkiego taki, że Gradle umożliwia wykonywanie częściowych buildów, a nam nie pozostaje nic innego jak z tej możliwości ochoczo korzystać (w końcu funkcjonalność ta pozwala znacząco skrócić czas budowy projektu).

Podsumowanie

...ah, czyżby kolejny projekt-zbawca ? Kolejne narzędzie, które obiecuje rozwiązanie wszelkich problemów związanych z budowaniem projektów ? Nie całkiem. Gradle nie obiecuje aż tak wiele. Za to próbuje

uczynić niemożliwe możliwym, możliwe łatwym, a łatwe eleganckim

-- Moshé Feldenkrais

I nawet już teraz, przed wydaniem wersji 1.0, Gradle oferuje mnóstwo interesujących i przydatnych możliwości. W tym artykule zaprezentowałem kilka z nich, i nie ukrywam, że jest to jedynie wierzchołek (wciąż rosnącej) góry lodowej. :)

Chciałem zachęcić cię do zainwestowania odrobiny czasu by lepiej poznać Gradle. Początkowo jego elastyczność i brak sztywnych reguł może sprawić, że będziesz czuł się nieco nieswojo (szczególnie jeżeli jesteś doświadczonym użytkownikiem Mavena). W moim przypadku, nawet po kilku miesiącach pracy z Gradle, mam poczucie, że wciąż nie dokonałem jeszcze całkowitego "przeskoku myślowego". Wciąż też zadziwia mnie łatwość i elastyczność, z jaką Gradle pozwala mi tworzyć skrypty budujące projekt. Musisz dać sobie nieco czasu, a przekonasz się że w tym projekcie tkwi potęga, o jakiej nawet nie marzyłeś. Koszt przejścia (z Anta lub Mavena) jest minimalizowany przez to, że Gradle wykorzystuje wiele rozwiązań, które są Ci dobrze znane z innych projektów (np. standardowy layout projektu, taski Anta, repozytoria Mavena itd.).

Przekonasz się, że w tym projekcie tkwi potęga,
o jakiej nawet nie marzyłeś.

Na stronie Gradle znajdziesz bardzo rozbudowany podręcznik użytkownika, a w kodzie źródłowym mnóstwo przykłądów, które pomogą Ci rozpocząć pracę z Gradle (zajrzyj też do CookBook po różnorakie pomocne wskazówki). Możesz też liczyć na wsparcie członków społeczności (dostępna jest lista mailingowa i wiki), a w przypadku gdybyś potrzebował profesjonalnych szkoleń, zapoznaj się z ofertą na stronie Gradle Inc.

Links



[1] Dla ścisłości dodam, że tak naprawdę to pluginy Java i War narzucają taki układ projektu jako domyślny.

[2] Maven 3 pozwala na użycie równie zwięzłej składni, ale jak zobaczymy nieco później, w przypadku dependencji, Gradle oferuje o wiele więcej.

[3] W załączonym do artykułu kodzie źródłowym znajdziesz obie wersja - sam oceń, która wydaje Ci się bardziej odpowiednia.

[4] Plik settings.gradle może też służyć innym celom.

[5] Inne taski o zbliżonym działaniu opisane są w podręczniku użytkownika Gradle.

Źródło: http://www.javaexpress.pl/article/show/Gradle__a_powerful_build_system