Gradle mi pomohol zostaviť projekt v okamihu!

Ako začať

Keď neviete, čo je Gradle, odbehnite ku veselému motivačnému textu na blogu SoftWare Samuraja. Aby sme po ňom neopakovali, poznamenáme, že Gradle je niečo ako Maven, čiže nástroj na automatizáciu zostavovania projektov, lež miesto XML používate prehľadnejšie konštrukcie jazyka Groovy.

Ukážeme si, ako možno veľmi jednoducho naštartovať miniprojekt, kde vytvoríme požadovanú adresárovú štruktúru, zavedieme závislosti, projekt spustíme a naučíme sa, ako vytvoriť ZIP verziu s vydanou verziou.

Aby sme sa nezatatárili s HTTP servletmi a spol., na webovú časť využijeme mikroframework Spark.

Stiahnutie a inštalácia

Stiahnutie

Z webu Gradle stiahneme ZIP súbor s binárkami. Použijeme verziu 1.7-rc1, ktorá je síce release candidate, teda nefinálna verzia, ale až od tejto verzie sú k dispozícii nástroje pre rýchle naštartovanie projektu.

Rozbalenie

Súbor rozbalíme do vhodného adresára: napr. C:\java\gradle-1.7-rc-1-bin.zip.

Premenná PATH

Cestu pridáme do premennej prostredia PATH, aby sme mohli volať gradle z ľubovoľného adresára.

set PATH=%PATH%;C:\java\gradle-1.7-rc-1\bin

Overíme funkčnosť

Z ľubovoľného adresára spusťme gradle -v.

c:\Projects>gradle -v

------------------------------------------------------------
Gradle 1.7-rc-1
------------------------------------------------------------

Build time:   2013-07-02 14:56:30 UTC
Build number: none
Revision:     9a7199efaf72c620b33f9767874f0ebced135d83

Groovy:       1.8.6
Ant:          Apache Ant(TM) version 1.8.4 compiled on May 22 2012
Ivy:          2.2.0
JVM:          1.7.0_25 (Oracle Corporation 23.25-b01)
OS:           Windows 8 6.2 amd64

Založenie projektu

Od verzie 1.7-rc-1 môžeme veľmi jednoducho založiť nový projekt. (Implementovala sa dlho požadovaná vlastnosť GRADLE-1289.)

V adresári s projektami založme podadresár s projektom:

mkdir spark-hello

a

cd spark-hello

Vytvorenie kostry projektu

Kostru projektu spustíme zavolaním tasku setupBuild, ktorý nainicializuje adresárovú štruktúru a pripraví konfiguračné súbory.

Task v Gradle plní podobnú úlohu ako task v Ant-e, či goal v Mavene: realizuje nejakú komplexnú úlohu — existuje task na skompilovanie projektu, iný task na vybudovanie JARu a podobne.

Keďže chceme vytvárať bežný Java projekt, použijeme pre typ projektu hodnotu java-library.

gradle setupBuild --type java-library

V tejto verzii Gradlu je zatiaľ k dispozícii len málo typov projektov, v budúcnosti sa dodajú ďalšie.

Uvidíme výsledok:

c:\Projects\spark-hello>gradle setupBuild --type java-library
:wrapper
:setupBuild

BUILD SUCCESSFUL

Total time: 2.563 secs

Tento task vytvorí zároveň adresárovú štruktúru s obslužnými súbormi:

c:\Projects\spark-hello>tree /F
Folder PATH listing
Volume serial number is 0051ECBC 5889:C1DD
C:.
│   build.gradle
│   gradlew
│   gradlew.bat
│   settings.gradle
│
├───.gradle
│   └───1.7-rc-1
│       └───taskArtifacts
│               cache.properties
│               cache.properties.lock
│               fileHashes.bin
│               fileSnapshots.bin
│               outputFileStates.bin
│               taskArtifacts.bin
│
├───gradle
│   └───wrapper
│           gradle-wrapper.jar
│           gradle-wrapper.properties
│
└───src
    ├───main
    │   └───java
    │           Library.java
    │
    └───test
        └───java
                LibraryTest.java

Adresárová štruktúra je podobná Mavenu:

  • v src/main/java sú bežné Java zdrojáky,
  • v src/test/java sú zdrojáky unit testov.

Ako vidno, Gradle dodal ukážkový súbor Library.java a prislúchajúci unit test.

V adresári projektu sa nachádzajú dva konfiguračné súbory:

  • build.gradle je zostavovací skript (build skript), teda popisovač projektu, ktorý obsahuje všetko, čo je potrebné na zostavenie projektu. Je to analógia pom.xml z Mavenu alebo build.xml z Antu.
  • settings.gradle obsahuje dodatočné špecifické nastavenia pre projekt.

Ostatné súbory (napr. gradle-wrapper.jar) súvisia s tzv. Gradle Wrapperom, čo je spôsob, ako je možné spustiť Gradle bez toho, aby bolo v systéme nainštalované. Táto pokročilá vlastnosť nebude v tomto článku rozoberaná.

Zostavovací skript build.gradle

Súbor build.gradle je najdôležitejší súbor pre gradleovský projekt: obsahuje temer všetky konfiguračné nastavenia pre zostavenie projektu.

Na rozdiel od Mavenu, ktorý sa zoširoka sa vyhýbal programovaniu v XML, je Gradle akýmsi návratom naspäť k Antu a jeho explicitným programom v XML. Zostavovací skript je skript, teda program, a to v jazyku Groovy. Silne stavia na syntaktických možnostiach tohto jazyka a umožňuje zápis, ktorý je často omnoho prehľadnejší než XML.

Gradle vygeneroval ukážkový skript:

/*
 * This build file was auto generated by running the Gradle 'buildSetup' task
 * by 'novotnyr' at '18.7.2013 12:14' with Gradle 1.7-rc-1
 *
 * This generated file contains a sample Java project to get you started.
 * For more details take a look at the Java Quickstart chapter in the Gradle
 * user guide available at http://gradle.org/docs/1.7-rc-1/userguide/tutorial_java_projects.html
 */

// Apply the java plugin to add support for Java
apply plugin: 'java'

// In this section you declare where to find the dependencies of your project
repositories {
    // Use 'maven central' for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    mavenCentral()
}

// In this section you declare the dependencies for your production and test code
dependencies {
    // The production code uses the SLF4J logging API at compile time
    compile 'org.slf4j:slf4j-api:1.7.5'

    // Declare the dependency for your favourite test framework you want to use in your tests.
    // TestNG is also supported by the Gradle Test task. Just change the
    // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
    // 'test.useTestNG()' to your build script.
    testCompile "junit:junit:4.11"
} 

Polovicu skriptu zaberajú komentáre s klasickou C/Java syntaxou (buď dve lomky // alebo /* ... */. Po vyhodení komentárov sa skript zjednoduší na:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.slf4j:slf4j-api:1.7.5'
    testCompile "junit:junit:4.11"
}

Plug-iny

Prvý riadok zavedie do gradleovského projektu plug-in pre Java projekty. Plug-in obvykle sprístupní ďalšie tasky a zavedie konvencie pre umiestnenie zdrojových súborov: napr. tento plug-in pre Javu sprístupní tasky pre skompilovanie zdrojákov v src/main/java a src/test/java, pre generovanie dokumentácie JavaDoc, či pre vytvorenie JARu.

Závislosti

Preskočme na chvíľu blok repositories a venujme sa závislosťam. V bloku dependencies môže projekt uviesť závislosti, teda všetky ostatné projekty, či knižnice, na ktorých náš projekt závisí. Typický projekt funguje ako stavebnica z kociek iných projektov: napr. tento ukážkový projekt využíva na logovanie knižnicu slf4j.

Každá závislosť je jednoznačne identifikovaná trojicou: * názvom skupiny: obvykle názov spoločnosti, či názov odvodený z webovej adresy projektu. Príkladom je org.slf4j. * názvom artefaktu: teda názvom samotného knižnice, či jej modulu: v tomto prípade závisíme na module, ktorý je identifikovaný ako org.slf4j. * a jeho verziou — napr. 1.7.5

Inými príkladom je závislosť na klasickej knižnici pre unit testy: závisíme na verzii 4.11.

Závislosti majú ešte tzv. scope, teda stav projektu, kde je závislosť vyžadovaná. Naše závislosti využívajú dva scopes:

  • compile znamená, že závislosť je potrebná na to, aby sa projekt vôbec dal zostaviť.
  • testCompile znamená, že závilosť je potrebná na zostavenie unit testov, ale samotný projekt sa dá zostaviť aj bez nej, ba dokonca bez nej aj pobeží.

Povedali sme, že máme dve závislosti. V reči Javy to znamená, že náš projekt potrebuje ku skompilovaniu získať ich JAR súbory. Odkiaľ ich však zoženieme?

Repozitáre

Z repozitára, ktorý si možno predstaviť ako analógiu správcu balíčkov z Linuxu alebo ako akýsi “obchod so všetkými JARkami všetkých možných projektov”, sa ťahajú projektové závislosti. Štandardný svetový repozitár pre JAR súbory je tzv. Maven Central s množstvom zrkadiel po celom svete.

Projekt môže deklarovať aj vlastné repozitáre: nejedna firma má svoj vlastný klon repozitára pre JARy vlastných projektov.

Repozitáre deklarujeme v sekcii repositories:

repositories {
    mavenCentral()
}

V našom projekte sme takto vyhlásili, že všetky závislosti budeme ťahať z webového mavenovského centrálneho úložiska.

Programovanie v Sparku

Poďme teraz urobiť skúšobný projekt v Sparku.

Dodanie závislosti

Dodajme do projektu závislosť na knižnici Spark. V dokumentácii tejto knižnice sa uvádza, že ak chceme pridať túto knižnicu do Mavenu, potrebujeme zaviesť závislosť:

<dependency>
      <groupId>com.sparkjava</groupId>
      <artifactId>spark-core</artifactId>
      <version>1.0</version>
</dependency>

Keďže sme však v Gradli, potrebujeme ju uviesť v inom tvare. Závislosť bude uvedená v klasickom scope compile a zložky oddelíme dvojbodkami.

dependencies {
    compile 'com.sparkjava:spark-core:1.0'
    compile 'org.slf4j:slf4j-api:1.7.5'
    testCompile "junit:junit:4.11"
}

Vytvorenie demo triedy

Vykradnime ukážkový príklad z dokumentácie a vytvorme triedu HelloWorld.

c:\Projects\spark-hello> notepad src/main/java/HelloWorld.java

Jej obsahom nech je:

import static spark.Spark.*;
import spark.*;

public class HelloWorld {

   public static void main(String[] args) {

      get(new Route("/hello") {
         @Override
         public Object handle(Request request, Response response) {
            return "<h1>Hello World!</h1>";
         }
      });

   }

}

Obdivovanie zoznamu taskov

Programovacia časť je za nami, poďme zostavovať. Zoznam dostupných taskov si môžeme pozrieť cez:

gradle tasks

Výsledkom bude zoznam taskov i s popisom: napr. assemble zostaví (skompiluje) projekt, build zostaví projekt a spustí unit testy a jar vytvorí JAR archív.

Zostavenie projektu

Teraz už vieme, že projekt zostavíme cez:

gradle build

Gradle bude chvíľu chrústať a najmä sťahovať závislosti (a ich závislosti) z repozitára Maven Central.

:compileJava
Download http://repo1.maven.org/maven2/com/sparkjava/spark-core/1.0/spark-core-1.0.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-server/9.0.2.v20130417/jetty-server-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-project/9.0.2.v20130417/jetty-project-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp/9.0.2.v20130417/jetty-webapp-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.0.2.v20130417/jetty-http-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-io/9.0.2.v20130417/jetty-io-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-xml/9.0.2.v20130417/jetty-xml-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-servlet/9.0.2.v20130417/jetty-servlet-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-util/9.0.2.v20130417/jetty-util-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-security/9.0.2.v20130417/jetty-security-9.0.2.v20130417.pom
Download http://repo1.maven.org/maven2/com/sparkjava/spark-core/1.0/spark-core-1.0.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-util/9.0.2.v20130417/jetty-util-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.0.2.v20130417/jetty-http-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-io/9.0.2.v20130417/jetty-io-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-server/9.0.2.v20130417/jetty-server-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-xml/9.0.2.v20130417/jetty-xml-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-security/9.0.2.v20130417/jetty-security-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-servlet/9.0.2.v20130417/jetty-servlet-9.0.2.v20130417.jar
Download http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp/9.0.2.v20130417/jetty-webapp-9.0.2.v20130417.jar
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 10.934 secs

Task build v skutočnosti zavolal viacero iných taskov. Z tých najdôležitejších: pomocou compileJava skompiloval všetky javácke zdrojáky, potom vytvoril pomocou jar výsledný JAR súbor, následne skompiloval unit testy cez compileTestJava a spustil ich cez test.

Výsledkom behu je, že v adresári build/libs sa ocitne JAR s našim projektom:

c:\Projects\spark-hello\build\libs\spark-hello.jar 

Bokom poznamenajme, že všetky závislosti stiahnuté z webu sa sťahujú do adresára .gradle v domovskom adresári používateľa (napr. do C:/Users/novotnyr/.gradle).

Prvý beh síce trval cca 10 sekúnd, ale väčšinu času zabralo sťahovanie závislosti, ktoré sa deje len raz. Druhý beh na ukážkovom stroji trval už len cca 3 sekundy.

Spustenie projektu

Ako spustíme projekt, ktorý má triedu s metódou main()? Jedna možnosť je zhromaždiť všetky závislosti v jednom adresári, tiahlo nakonfigurovať CLASSPATH, najlepšie v nejakom .bat/.sh súbore a následne ho spustiť.

V Gradli však môžeme použiť plug-in application, ktorý nám prácu značne uľahčí.

Plug-in pre aplikácie

Dodajme na začiatok buildovacieho skriptu:

apply plugin:'application'

Na koniec skriptu dodajme deklaráciu, ktorou určíme hlavnú triedu s metódou main() v projekte. Musíme uviesť celý názov triedy, vrátane balíčkov. Keďže naša trieda nie je v žiadnom balíčku, bude to jednoduché:

mainClassName = "HelloWorld"

Celý buildovací skript bude vyzerať:

apply plugin: 'java'
apply plugin: 'application'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.sparkjava:spark-core:1.0'  
    compile 'org.slf4j:slf4j-api:1.7.5'
    testCompile "junit:junit:4.11"
}

Projekt spustíme cez:

gradle run

Uvidíme:

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details
== Spark has ignited ...
>> Listening on 0.0.0.0:4567
> Building > :run

Gradle ostal bežať, pretože sme spustili sparkovský HTTP server, ktorý čaká na naše požiadavky. Stačí navštíviť adresu vo webovom prehliadači a uvidime výsledok:

http://localhost:4567/hello

Server môžeme zastaviť bežným spôsobom: napr. stlačením Ctrl-C v konzole.

Vypustenie verzie

Upratanie nepotrebných súborov

Teraz, keď sme už skoro na konci, upraceme (teda vymažeme) demonštračné triedy Library.java a LibraryTest.java:

c:\Projects\spark-hello>del src\main\java\Library.java
c:\Projects\spark-hello>del src\test\java\LibraryTest.java

Nebudeme potrebovať ani závislosti pre *slf4j. Upravme teda blok dependencies:

dependencies {
    compile 'com.sparkjava:spark-core:1.0'  
    testCompile "junit:junit:4.11"
}

V skutočnosti sa môžeme zbaviť aj závislosti na JUnite, keďže nemáme žiadne unit testy.

Vytvorenie distribučného archívu

Gradle obsahuje v rámci plug-inu application aj tasky, ktorými môžeme jednoducho vytvoriť ZIP súbor s aplikáciou a všetkými jej závislosťami. Táto funkcionalita je síce len v inkubačnej fáze (teda môže obsahovať viac chýb než je zvyklosťou, resp. spôsob použitia sa ešte môže neskôr meniť), ale pre jednoduché prípady funguje.

Spusťme teda:

gradle distZip

a výsledkom bude kompletný ZIP:

c:\Projects\spark-hello\build\distributions\spark-hello.zip

Ten obsahuje dokonca skripty pre Windows a Linux, ktorými aplikáciu môžeme ihneď po rozbalení spustiť.

Alternatívna možnosť je spustenie gradle distTar, ktorou vznikne .tar.gz podoba nášho projektu

Sumár

Ukázali sme si, ako možno jednoducho naštartovať projekt (gradle setupBuild), ako ho zostaviť (gradle build), ako ho spustiť pomocou plug-inu application (gradle run) a ako z neho vytvoriť distribučnú verziu (gradle distZip).

Samozrejme, toto je len ľahké škrabnutie po povrchu mocného nástroja. Podrobnejšie info nájdete v hore zmienenom vychádzajúcom seriáli SoftWare Samuraja alebo priamo v dokumentácii.

2 thoughts on “Gradle mi pomohol zostaviť projekt v okamihu!

Napísať odpoveď pre Guido Zrušiť odpoveď

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *