Documente Academic
Documente Profesional
Documente Cultură
Procesul de obtinere a unui executabil pornind de la surse necesitã în general mai multe
operatii (comenzi) manuale, operatii care trebuie repetate dupã fiecare modificare în surse.
Acest proces se numeste contruire de aplicatii iar instrumentele care automatizeazã acest
proces se numesc “build tools”.
Aplicatiile au devenit tot mai complexe si nu mai este vorba de un singur fisier executabil
care trebuie produs, ci de o serie de “artefacte” (fisiere de configurare, fisiere cu teste, s.a).
Dintre operatiile care fac parte de obicei din construirea unei aplicatii mentionãm: stergerea,
crearea de directoare, stergerea, crearea si copierea de fisiere, compilare, linkeditare, testare,
împachetare si instalare (“deployment”). Operatiile sunt mai complexe pentru aplicatii si servicii
Web care includ si baze de date.
Primul instrument pentru construirea de aplicatii a fost “make” folosit pentru programe în
limbajul C si care folosea fisiere text ca “script” pentru descrierea operatiilor necesare.
Pentru construirea de aplicatii scrise în Java a fost scris “Ant” care este folosit si în prezent
pentru automatizarea operatiilor de obtinere a multor aplicatii. Ant foloseste fisiere XML pentru
descrierea operatiilor necesare construirii unei aplicatii.
Programul “Ivy” se foloseste împreunã cu Ant pentru descrierea dependentelor dintre fazele
construirii unei aplicatii si foloseste tot fisiere XML.
“Maven” este considerat ca fiind un instrument pentru gestionarea proiectelor software
(“project management tool”) si include facilitãti necesare dezvoltãrii de aplicatii mari, la care
contribuie mai multe persoane, care refolosesc pãrti din alte proiecte software, care pot genera
rapoarte si site-uri Web. Versiunile Maven folosite în prezent sunt 2.2 si 3.0 si folosesc tot fisiere
XML pentru descrierea operatiilor si dependentelor.
Utilizarea de fisiere XML tot mai complexe si mai mari ( de la “Ant” la “Maven”) s-a dovedit un
neajuns al acestor instrumente si de aceea s-a trecut mai recent la utilizarea unor limbaje
dinamice ca Ruby si Groovy în locul limbajului XML pentru fisierele de “build”. “Gant” este o
“fatadã” pentru utilizarea de sarcini “Ant”, iar “Gradle” este o alternativã la “Maven”; ambele
folosesc limbajul Groovy.
Mai exact, fisierele de “build” pentru Gant si Gradle sunt scrise într-un DSL intern Groovy, în
timp ce Ant si Maven foloseau fisiere scrise într-un DSL extern (bazat pe XML). Fisierele de
build pot fi imperative (pentru Ant), declarative (pentru Maven) sau mixte (Maven cu Ant).
Pe lângã cele patru instrumente considerate ca cele mai importante (Ant,Ivy,Maven,Gradle)
se mai folosesc si alte instrumente pentru construirea de proiecte (Buildr, IBM Rational Build
Forge, MSBuild s.a.).
Construirea de aplicatii este tot mai des parte dintr-un proces de integrare continuã
(“Continuous Integration”), care înseamnã actualizarea regulatã de cãtre participantii la un
proiect software a unui depozit de surse si executabile (“code repository”, “code base”).
Construirea unei aplicatii este un “proiect” Ant; un proiect este descris într-un fisier numit
“build.xml”. Un proiect contine una sau mai multe actiuni (“target”), iar o actiune contine una sau
mai multe operatii (“task”), majoritatea fiind predefinite. In plus, un proiect poate folosi mai multe
proprietãti, incluse în “build.xml” sau citite dintr-un fisier separat “build.properties”.
Un proiect Ant are trei atribute:
- un nume ;
- actiunea cu care începe proiectul (“default”);
- directorul de bazã pentru alte “cãi” folosite în proiect (“basedir”).
Exemplu de proiect Ant:
1
<project name="MyProject" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="source" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
<target name="myTarget.check">
<condition property="myTarget.run">
2
<and>
<available file="foo.txt"/>
<available file="bar.txt"/>
</and>
</condition>
</target>
Operatiile au de obicei mai multe argumente (atribute de marcaje XML) în formatul urmãtor:
<name attribute1="value1" attribute2="value2" ... />
Datoritã numãrului mare de operatii predefinite în Ant este putin probabil sã fie necesarã
definirea de noi operatii (“tasks”) ca extinderi de tip “plugin” pentru Ant.
Fiecare proprietate are un nume si o valoare; de exemplu proprietatea cu numele “source”
are valoarea “src” si este folositã în comanda de compilare:
<javac srcdir="${source}" destdir="${build}"/>
Inainte de executia comenzii se înlocuieste numele cu valoarea proprietãtii în optiuni (în
parametri comenzii); exemplu:
javac –sourcepath src –d build *.*
Ant poate folosi, pe lângã operatiile sale proprii, operatii Ivy si Maven.
In general un fisier “build.xml” contine urmãtoarele actiuni “top-level” (nesubordonate altora):
- build (etapele construirii unei aplicatii)
- test (testare cu JUnit)
- clean (stergere fisiere si directoare create de actiunea “build”
- deploy (transfer arhivã aplicatie pe sistemul unde se exploateazã)
- publish (publicare surse si binare pe un site Web de distributie)
- fetch (obtinerea ultimei versiuni dintr-un arbore cvs)
- docs/javadocs (creare documentatie pentru aplicatie)
- all : clean, fetch,build,test,docs,deploy
Exemple de actiuni interne:
- init (initializare proprietãti, citire fisiere de proprietãti, s.a.)
- compile (compilare surse)
- link/jar (creare executabile)
Acest exemplu este extras din documentatia Ant (Apache Ant User Manual : Tutorials : Hello
World with Ant) unde este extins treptat de la simpla construire a unei aplicatii cu o singurã
clasã Java, la utilizarea log4j pentru jurnalizare si apoi la utilizare JUnit pentru testare si creare
de rapoarte în urma testelor.
Sursa clasei se aflã în subdirectorul “src” al directorului de lucru si aratã astfel:
package oata;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
3
}
public void testWillAlwaysFail() {
fail("An error message");
}
}
Subdirectorul “lib” contine arhiva cu clasele “junit” iar subdirectorul “build” este creat de Ant
ca urmare a interpretãrii actiunilor din “build.xml”. Folderul “build” are 3 subdirectoare :
“classes”, “jar” si “junitreport”.
<target name="clean">
<delete dir="build"/>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="src" destdir="${classes.dir}" classpathref="classpath"/>
</target>
<junit printsummary="yes">
<classpath>
<path refid="classpath"/>
4
</classpath>
<formatter type="xml"/>
<target name="junitreport">
<junitreport todir="${report.dir}">
<fileset dir="${report.dir}" includes="TEST-*.xml"/>
<report todir="${report.dir}"/>
</junitreport>
</target>
</project>
Fisierele “build.xml” folosite de Ant sunt de tip imperativ si solicitã executarea unor actiuni;
ele sunt interpretate de cãtre programul Ant. Caracteristica de limbaj procedural interpretat este
proprie oricãrui limbaj de scripting, deci fisierele XML de “build” ar putea fi înlocuite cu un limbaj
de scripting dacã acesta contine deja sau poate fi extins cu posibilitatea de a descrie operatii
Ant (“task”), dependente dintre operatii si de a folosi operatiile predefinite din Ant.
Groovy este un limbaj de scripting extensibil si deci poate îndeplini acest rol, cu câteva
avantaje fatã de fisierele XML folosite de Ant:
- Scripturile necesare construirii de aplicatii sunt mai usor de scris si de citit ;
- Scripturile pot include orice secvente de cod Groovy, pe lângã taskuri Ant;
- Eventualele erori din script sunt detectate încã din faza de compilare Groovy (parte din
procesul de interpretare).
Gant este un program cu acelasi rol ca si Ant dar care foloseste fisiere de build scrise în
Groovy cu anumite extensii (deci un DSL intern lui Groovy). Gant se poate utiliza direct sau
indirect din Grails, prin comenzi specifice Grails.
Un script Gant este un script Groovy care contine definitii de actiuni, apeluri de operatii Ant
predefinite si operatii asupra altor obiecte predefinite. Douã obiecte predefinite sunt mai des
folosite:
- includeTargets : includere de actiuni din alte scripturi sau clase definite corespunzãtor;
- includeTool : includere clase care oferã diferite servicii folosite în scriptil Gant. Exemplu:
Un “target” Ant este aici un functor, având ca parametri un nume de target si o descriere (un
sir). Metoda “depends” poate avea ca argument un nume de target si este folositã, ca si în Ant,
pentru a specifica secventa de executie a unor actiuni “target”, care poate fi alta decât ordinea
definirii lor în fisierul “build”; executia începe cu actiunea implicitã, care apare ca parametru în
metoda “setDefaultTarget”.
Un fisier “build.gant” poate refolosi actiuni din alte fisiere în douã moduri:
- prin includerea unor surse Groovy (sub-scripturi). Exemplu:
includeTargets << new File('source/org/codehaus/groovy/gant/targets/clean.gant' )
- prin “evaluarea” unor surse Groovy:
evaluate (new File(‘clean.gant’))
- prin includerea de fisiere Groovy compilate (de clase Groovy). Exemplu:
includeTargets << gant.targets.Clean
Definitia “target-closure” poate contine orice cod Groovy. Se pot folosi operatii predefinite Ant
prin apeluri de metode de forma “ant.echo”, “ant.mkdir”,.. sau direct ca “echo”,”mkdir”,...
target (first: ‘First target’) { echo (‘prima actiune’) }
Numele de actiuni sunt chei într-un dictionar folosit ca argument de functorul “target” si sunt
de tip “String” (chiar dacã nu este necesarã utilizarea de ghilimele pentru aceste nume); totusi
observatia este importantã atunci când aceste nume (si chiar actiunile) sunt create dinamic
(ceea ce cu Ant si XML nici nu este posibil). Exemplu:
6
aTargetName = 'something'
target ( ( aTargetName ) : 'A target called' + aTargetName + '.' ) {
println ( 'Executing ' + aTargetName )
}
Obiectul predefinit “ant” poate fi dat factor comun la apelarea unei secvente de operatii,
folosind metoda “sequential” astfel:
sourceDirectory = 'source'
buildDirectory = 'build'
includeTargets << gant.targets.Clean
cleanPattern << '**/*~'
cleanDirectory << buildDirectory
ant.taskdef ( name : 'groovyc' , classname : 'org.codehaus.groovy.ant.Groovyc' )
target ( compile : 'Compile source to build directory.' ) {
javac ( srcdir : sourceDirectory , destdir : buildDirectory , debug : 'on' )
groovyc ( srcdir : sourceDirectory , destdir : buildDirectory )
}
Pentru a executa un script Gant trebuie folosit programul Gant, care este un fisier “bat” ce
contine o comandã de forma:
java – jar gant-1.9.3_groovy-1.7.3.jar
7
Gant nu face parte din distributia Groovy dar face parte din distributia Grails. Gant se poate
descãrca în douã variante:
- Self-contained: contine si bibliotecile Groovy necesare
- Necesitã o instalare Groovy separatã
Fisierul care contine un script Gant trebuie sã aibã numele “gant.bat”, dar comanda “gant”
poate avea ca argumente numele unor actiuni din fisierul “gant.bat”. Exemplu:
gant clean
Grails este un framework complet (“full-stack”) pentru aplicatii Web, bazat pe limbajul Groovy
si care înlocuieste configurarea prin respectarea unor conventii, la fel ca si Ruby on Rails. Grails
nu aduce noi tehnologii Web, dar simplificã considerabil utilizarea unor tehnologii existente si se
bazeazã pe câteva produse de succes cum sunt Spring si Hibernate (pentru ORM).
Dezvoltarea unei aplicatii Web cu ajutorul lui Grails se poate face:
- Intr-un IDE (NetBeans si IDEA-JetBrains);
- In mod linie de comandã, folosind comenzi specifice Grails.
Fiecare comandã Grails lanseazã un script Gant sau Groovy predefinit si poate avea
argumente. Exemple de comenzi Grails uzuale:
myapp
grails-app // sursele aplicatiei
lib // biblioteci folosite de aplicatie
scripts // scripturi groovy pentru comenzi consola
src // alte surse (auxiliare)
target // clase rezultate din compilari
test // surse teste
web-app // resurse statice (css, imagini,..)
application.properties
Sursele aplicatiei se aflã în subdirectorul “grails-app”, care are o structurã ce reflectã schema
MVC (Model-View-Controller):
conf // configurãri
controllers // servleti controler
domain // clase domeniu (model)
services // clase cu servicii ptr controlere
views // pagini afisate (gsp,jsp,html)
Scripturile Grails se pot afla si în alte subdirectoare (unde sunt cãutate la executia unei
comenzi); în afara scripturilor predefinite orice programator îsi poate defini alte scripturi Gant.
Scripturile pentru comenzile predefinite (create-app, run-app, s.a.) se aflã în subdirectorul
“scripts” din distributia Grails (de ex. C:\grails-1.3\scripts) si au un nume putin modificat fatã de
numele folosite în comenzi. Exemple de comenzi si numele scripturilor executate:
grails create-script CreateScript.groovy
grails run-app RunApp.groovy
grails generate-all GenerateAll.groovy
8
Pentru a crea un script ce poate fi apelat printr-o nouã comandã Grails se va folosi comanda:
grails create-script MyScript
Pentru a include un script predefinit într-un nou script trebuie specificat directorul unde se
aflã distributia Grails (valoarea variabilei de sistem GRAILS_HOME). Exemplu:
grailsHome = ant.project.properties."environment.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Package.groovy" )
task('default':"My Script") {
depends( package )
}
O altã operatie Gant utilã este “classpath”, care stabileste cãile din interiorul directorului unei
aplicatii Grails (grails-app,lib,classes) astfel ca eventualele stergeri de fisiere sã nu genereze
exceptii:
grailsHome = ant.project.properties."environment.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Init.groovy" )
task('default':"My Funky Script") {
depends( classpath )
// reference a Grails class here
}
Fragment dintr-un script pentru comanda “grails create-app” (creare director si subdirectoare
aplicatie):
import grails.util.GrailsNameUtils
import grails.util.Metadata
grailsAppName = ""
projectType = "app"
9
metadataFile = new File("$basedir/${Metadata.FILE}")
metadata = Metadata.getInstance(metadataFile)
// Reset the plugin stuff.
pluginSettings.clearCache()
pluginsHome = grailsSettings.projectPluginsDir.path
}
ant.move(
file: "${basedir}/GrailsPlugin.groovy",
tofile: "${basedir}/${pluginName}GrailsPlugin.groovy", overwrite: true)
// Insert the name of the plugin into whatever files need it.
ant.replace(dir:"${basedir}") {
include(name: "*GrailsPlugin.groovy")
include(name: "scripts/*")
replacefilter(token: "@plugin.name@", value: pluginName)
replacefilter(token: "@plugin.short.name@", value: GrailsNameUtils.getScriptName(pluginName))
replacefilter(token: "@plugin.version@", value: grailsAppVersion ?: "0.1")
replacefilter(token: "@grails.version@", value: grailsVersion)
}
// install default plugins into plugin project
installDefaultPluginSet()
event("StatusFinal", [ "Created plugin ${pluginName}" ])
}
Resurse:
http://ant.apache.org/
http://ant.apache.org/ivy/
http://gant.codehaus.org/
10