Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Cet article est une reprise de l'article Premiers pas avec Ant que j'avais précédemment publié sur http://wiki.esicom-st-malo.fr

Ant (ou Apache Ant) est un outil qui permet d'automatiser certaines tâches liées au développement de logiciels (compilation, par exemple).

Dans le monde JEE (anciennement J2EE), Ant est devenu le standard de facto pour la compilation et le déploiement d'applications Web.

Cet article explique les principes de bases de l'utilisation d'Apache Ant, et montre certaines de ses possibilités.

Objectifs A la fin de ce tutoriel, vous saurez:
  • Modifier un fichier build.xml,
  • Automatiser la création et la suppression de fichiers avec Ant.
Prérequis
Moyens


Le fichier build.xml

Un exemple

Pour travailler, Ant nécessite qu'on lui fournisse un ensemble de tâches pour lui dire:

Dans Ant, ces tâches sont enregistrées dans un fichier XML, dont le nom par défaut doit être build.xml.

Le code suivant est un exemple de fichier build.xml:

<?xml version="1.0" encoding="utf-8" ?>
<project name="Hello" default="print">
        <target name="print">
                <echo message="Hello ant!" />
        </target>
</project>

Si vous avez correctement installé Ant sur votre système, en tapant la commande ant à l'invite du shell dans le répertoire où se trouve le fichier build.xml doit produire le résultat suivant:

 Buildfile: build.xml
 
 print:
      [echo] Hello ant!
 
 BUILD SUCCESSFUL
 Total time: 1 second

Projet, cibles et tâches

Nous allons décomposer élément par élément l'exemple de fichier build.xml ci-dessus:

<?xml version="1.0" encoding="utf-8" ?>
...

La ligne entre <? ... ?> est juste un préfixe standard pour tout ficher XML. Il n'y a rien de spécifique à Ant ici.


<project name="Hello" default="print">
        ...
</project>

L'élément project est lui spécifique à Ant. Il s'agit de l'élément racine du fichier (tous les autres éléments sont à l'intérieur de celui-ci). Il précise en attribut le nom du projet (name="..."), et la cible par défaut à construire (default="...") si rien n'est précisé au moment d'invoquer Ant.

<target name="print">
                ...
</target>

L'élément target est une cible. Une cible est identifiée par son nom (name="...") et contient toutes les tâches nécessaires pour construire cette cible.


<echo message="Hello ant!" />

Enfin, l'élément echo est une des tâches à appliquer à chaque fois que l'on construit la cible. Vous pouvez voir les tâches un peu comme des commandes à exécuter. La tâche echo se contente d'afficher le message donné en attribut (message="...").

Construire une cible

Un fichier build.xml peut contenir plusieurs cibles, et une cible plusieurs tâches. Ant permet de choisir quelle cible on souhaite constuire, et applique automatiquement les tâches contenues dans cette cible. L'exemple suivant contient deux cibles et chaque cible, deux tâches:

<?xml version="1.0" encoding="utf-8" ?>
<project name="Hello" default="cible1">
        <target name="cible1">
                <echo message="Cible 1, tâche 1" />
                <echo message="Cible 1, tâche 2" />
        </target>
        <target name="cible2">
                <echo message="Cible 2, tâche 1" />
                <echo message="Cible 2, tâche 2" />
        </target>
</project>

La commande:

 ant

Construit la cible par défaut (cible1) et produit le résultat suivant:

 Buildfile: build.xml
 
 cible1:
      [echo] Cible 1, tâche 1
      [echo] Cible 1, tâche 2
 
 BUILD SUCCESSFUL
 Total time: 1 second

Les deux tâches de la cible par défaut ont été appliquées dans l'ordre où elles sont définies dans le fichier.

La commande:

 ant cible1

Produit exactement le même résultat, puisque cible1 est la cible par défaut.

Si l'on veut exécuter les tâches de la cible2, il faut écrire:

 ant cible2

Le résultat est alors:

 Buildfile: build.xml
 
 cible2:
      [echo] Cible 2, tâche 1
      [echo] Cible 2, tâche 2
 
 BUILD SUCCESSFUL
 Total time: 1 second

Enfin, pour construire les deux cibles l'une après l'autre, il faut taper la commande:

 ant cible1 cible2

Tâches en dehors d'une cible

A partir de Ant version 1.6, il est possible d'avoir certaines tâches en dehors d'une cible. Dans ce cas, ces tâches sont exécutées avant toute cible:

<?xml version="1.0" encoding="utf-8" ?>
<project name="ttest" default="test">
        <echo message="A task *outside* a target" />
        <target name="test">
                <echo message="This task is *inside* a target" />
        </target>
        <echo message="An other task *outside* a target" />
</project>

Produit le résultat:

Buildfile: build.xml
     [echo] A task *outside* a target
     [echo] An other task *outside* a target

test:
     [echo] This task is *inside* a target

BUILD SUCCESSFUL
Total time: 1 second

Dépendances

Parfois il peut être nécessaire d'exécuter les tâches de plusieurs cibles, et dans un ordre particulier.

Considérons l'exemple suivant:

<?xml version="1.0" encoding="utf-8" ?>
<project name="greetings" default="polite">
        <target name="polite">
                <echo message="Hello" />
                <echo message="Welcome to this ant buildfile" />
        </target>
        <target name="excessive">
                <echo message="Hello" />
                <echo message="Welcome to this ant buildfile" />
                <echo message="And have a nice day!" />
        </target>
        <target name="strict">
                <echo message="Hello" />
        </target>
</project>

L'exemple ci-dessus contient trois cibles (polite, strict et excessive) pour saluer l'utilisateur. Pour obtenir chacune de ces salutations, on invoque respectivement;

ant strict            # ou
ant polite            # ou
ant excessive

Le problème principal avec ce fichier, est la redondance de certaines tâches. Si par exemple, on souhaite remplacer Hello par Good Morning, il y trois lignes à modifier, donc trois fois plus de travail et trois fois plus de risques de faire un oubli ou d'introduire une erreur.

On pourrait être tenté de ré-écrire le fichier ainsi:

<?xml version="1.0" encoding="utf-8" ?>
<project name="greetings" default="polite">
        <target name="polite">
                <echo message="Welcome to this ant buildfile" />
        </target>
        <target name="excessive">
                <echo message="And have a nice day!" />
        </target>
        <target name="strict">
                <echo message="Hello" />
        </target>
</project>

Maintenant, il n'y a plus de lignes redondantes dans le fichier build.xml mais pour obtenir les salutations, l'utilisateur doit maintenant utiliser les commandes:

ant strict            # ou
ant strict polite     # ou
ant strict polite excessive

C'est maintenant l'utilisateur qui subit la redondance en étant obligé de taper des lignes à rallonge. Sans compter le risque d'introduire des salutations "incorrectes":

ant excessive polite strict

Heureusement, Ant a la solution en permettant de créer des dépendances entre règles. Dans notre exemple, les salutations polies ne peuvent être affichées qu'après les salutations strictes. En termes Ant, on dit que la cible polite dépend de la cible strict. De la même manière, la cible excessive dépend de la cible polite. Les dépendances entre cibles sont exprimées par l'attribut depends="..." de l'élément target:

<?xml version="1.0" encoding="utf-8" ?>
<project name="greetings" default="polite">
        <target name="polite" depends="strict">
                <echo message="Welcome to this ant buildfile" />
        </target>
        <target name="excessive" depends="polite">
                <echo message="And have a nice day!" />
        </target>
        <target name="strict">
                <echo message="Hello" />
        </target>
</project>

Essayons maintenant la commande:

 ant excessive

L'affichage est le suivant:

Buildfile: build.xml

strict:
     [echo] Hello

polite:
     [echo] Welcome to this ant buildfile

excessive:
     [echo] And have a nice day!

BUILD SUCCESSFUL
Total time: 1 second

Nous avons demandé à Ant de construire la cible excessive. Mais comme cette cible dépend de polite Ant essaye d'abord de construire cette cible. Mais elle dépend elle-même de la cible strict. Comme cette dernière ne dépend d'aucune autre cible, elle peut être construite. Puis polite, puis excessive. nous avons bien nos trois messages et dans l'ordre.

Propriétés

Une propriété est en quelques sortes l'équivalent dans Ant d'une variable.

Certaines tâches permettent de créer des propriétés et de leur assigner une valeur. C'est par exemple le cas de la tâche property.

On peut récupérer la valeur d'une propriété à l'aide de la notation ${NomDeLaPropriete}:

<?xml version="1.0" encoding="utf-8" ?>
<project name="ptest" default="test">
        <property name="username" value="moi" />
        <target name="test">
                <echo message="Bienvenue ${username}" />
        </target>
</project>

Avec le buildfile ci-dessus, Ant produit le résultat suivant:

Buildfile: build.xml

test:
     [echo] Bienvenue moi

BUILD SUCCESSFUL
Total time: 1 second

Il est également possible de fixer la valeur d'une propriété au moment de l'appel à la commande ant. Dans ce cas, la valeur définie lors de l'appel de Ant remplace celle définie dans le fichier build.xml:

 ant -Dusername=toi

Produit le résultat suivant:

Buildfile: build.xml

test:
     [echo] Bienvenue toi

BUILD SUCCESSFUL
Total time: 1 second

Quelques tâches classiques

Ant contient de nombreuses tâches prédéfinies. Il est également possible d'ajouter à Ant de nouvelles tâches. Pour ce premier tutoriel, nous allons cependant nous contenter de jeter un oeil à quelques tâches élémentaires, celles liées à la manipulation de fichiers.

Note: Les tâches sont présentées ici succinctement et par ordre de complexité croissante. Pour une liste alphabétique complète et/ou des explications plus détaillées, reportez-vous à la documentation officielle.

echo

Nous avons déjà vu la tâche echo. Cette tâche affiche un message à l'écran. Mais elle peut également être utilisée pour ajouter du texte à un fichier, ou pour remplacer le contenu d'un fichier.

<echo message="Hello Ant!" /> <!-- affiche sur la sortie standard -->
<echo message="Hello Ant!" file="fichier" append="true" /> <!-- ajoute à un fichier -->
<echo message="Hello Ant!" file="fichier" /> <!-- écrase un fichier -->

delete

Comme son nom le laisse supposer, la tâche delete permet de supprimer un fichier. elle permet également de supprimer un répertoire, même non vide (comme rm -r en shell!):

<delete file="fichier" /> <!-- supprime un fichier -->
<delete dir="répertoire" /> <!-- supprime un répertoire et *tout* son contenu -->

move

move permet de déplacer ou renommer un fichier:

<move file="ancien" tofile="nouveau" /> <!-- renomme un fichier -->
<move file="fichier" todir="position" /> <!-- déplace un fichier -->

tstamp

Cette tâche initialise les propriétés DSTAMP, TSTAMP, et TODAY avec la date et l'heure actuelle.

<tstamp /> <!-- initialise DSTAMP, TSTAMP et TODAY -->
<echo message="${TODAY}" /> <!-- affiche la date -->

A vous de jouer

Voir aussi