Build partiel avec Maven : Construire moins pour aller plus vite.

Apache MavenApache Maven permet nativement de découper un projet en sous-modules. Chaque module est un élément autonome avec son propre cycle de vie. Maven utilise ce que l’on appel le “reactor” pour orchestrer dans un projet l’appel des différents modules en fonction de leurs dépendances.

Le concept de module, permet d’affiner la granularité des livrables et de rendre plus flexible et évolutive l’architecture de l’application. Cependant lorsque le nombre de modules d’un projet augmente cela va souvent de pair avec le nombre de lignes de code, de tests et de packages à créer. La construction du projet prend donc de plus en plus de temps à en devenir un frein pour la productivité du développeur (moi je ne trouve rien de plus énervant lorsque je développe que de devoir attendre que ma machine me rende la main).

Entendu sur Les Cast CodeursIl existe pourtant des fonctionnalités du “reactor” qui permettent à Maven de contrôler finement quels sont les modules d’un projet sur lesquels on souhaite appeler un traitement. Même si elles existent depuis près de deux ans, ces fonctionnalités sont encore peu connues et utilisées malgré leurs utilités indéniables (faute à la documentation ?). Ce billet illustre mes rapides explications de l’épisode 20 du podcast Les Cast Codeurs. Il détaille l’utilisation de 4 options de la ligne de commande pour Maven 2.1 et versions ultérieures. Vous pouvez très bien faire la même chose avec le plugin reactor et les versions 2.0.x de Maven mais il faudra taper sur plus de touches de votre clavier car la syntaxe est bien moins synthétique.

Le projet exemple

Le Projet
Pour illustrer l’article je prend volontairement un projet simple sans complexité dans les dépendances entre les modules.
Ce projet est composé de 6 sous-modules (A à F) avec les dépendances suivantes

  • Module F dépend de Module E,
  • Module E dépend de Module D,
  • Module D dépend de Module C,
  • Module C dépend de Module B,
  • Module B dépend de Module A.

Dans cet article j’utilise le verbe “construire” pour nommer une exécution Maven sur un module/projet mais il faut se rappeler que Maven fait bien plus que cela nativement : exécution des tests, génération de site web, etc. Ces options s’appliquent à n’importe quelle phase ou plugin que l’on souhaite appeler sur le projet.

A noter que les commandes Maven doivent être impérativement appelées depuis le projet principal où sont déclarés tous les modules afin qu’il connaisse le graphe complet de l’exécution des modules et n’extrait que les parties qui vous intéressent.
Dans notre exemple, compte tenu des dépendances entre modules, une exécution complète de Maven va suivre l’ordre alphabétique.

arnaud@mbp-arnaud:~$ mvn install
[INFO] ------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] Project ....................... SUCCESS [2.132s]
[INFO] ModuleA ....................... SUCCESS [5.574s]
[INFO] ModuleB ....................... SUCCESS [0.455s]
[INFO] ModuleC ....................... SUCCESS [0.396s]
[INFO] ModuleD ....................... SUCCESS [0.462s]
[INFO] ModuleE ....................... SUCCESS [0.723s]
[INFO] ModuleF ....................... SUCCESS [0.404s]
[INFO]
Reactor

Sélectionner les modules à construire. L’option -pl.

arnaud@mbp-arnaud:~$ mvn --help
usage: mvn [options] [<goal (s)>] [<phase (s)>]
Options:
...
-pl,--projects <arg> Build specified reactor projects
instead of all projects
...

Cette option permet de choisir spécifiquement les modules du projet à construire. Cela évite de naviguer de répertoire en répertoire pour lancer chaque module ou d’utiliser plusieurs lancements successifs avec l’option “-f chemin_vers_un_pom.xml”. Cela vous fait gagner aussi du temps en évitant de charger Maven et la JVM plusieurs fois. Enfin le fait que Maven utilise son “reactor”, c’est lui qui ordonne les modules en fonctions des dépendances et ça n’est pas à vous de faire ce calcule.
La liste de modules est séparée par des virgules. Pour identifier chaque module, nous pouvons soit utiliser son chemin relatif par rapport à la racine du projet soit son artifactId.

arnaud@mbp-arnaud:~$ mvn install –pl moduleE,moduleB
[INFO] -------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] ModuleB .................. SUCCESS [2.774s]
[INFO] ModuleE .................. SUCCESS [1.008s]
[INFO]

Dans note exemple nous demandons à Maven d’executer le cycle de vie jusqu’à la phase “install” pour les modules E et B. Maven calcule automatiquement l’ordre et construits le module B puis le module E.
Reactor avec liste de modules

Construire tous les modules impactant la construction d’une liste de modules. L’option -am

arnaud@mbp-arnaud:~$ mvn --help
usage: mvn [options] [<goal (s)>] [<phase (s)>]
Options:
-am,--also-make If project list is specified, also
build projects required by the
list
...

Cette option s’utilise conjointement à l’option -pl. En plus de construire les modules demandés par l’option -pl, Maven va construire tous les modules nécessaires à ceux-ci (donc ceux qui apparaissent dans leurs dépendances).

arnaud@mbp-arnaud:~$ mvn install –pl moduleD -am
[INFO] ------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] ModuleA ................. SUCCESS [4.075s]
[INFO] ModuleB ................. SUCCESS [0.468s]
[INFO] ModuleC ................. SUCCESS [0.354s]
[INFO] ModuleD ................. SUCCESS [0.384s]
[INFO]

Cas d’usage : Imaginons que vous développiez une application JEE avec de nombreux JARs, quelques WARs et EARs. Si vous travaillez sur un war en particulier et que vous êtes capable de ne déployer que ce dernier pour tester vos développements, vous n’avez pas besoin de reconstruire tout votre projet. Demandez à Maven de reconstruire que les modules nécessaires à la construction du WAR en passant ce dernier en paramètre de l’option -pl et en ajoutant l’option -am.
mvn install –pl monWAR -am
Reactor avec dépendances des modules

Construire tous les modules impactés par la construction d’une liste de module. L’option -amd

arnaud@mbp-arnaud:~$ mvn --help
usage: mvn [options] [<goal (s)>] [<phase (s)>]
Options:
...
-amd,--also-make-dependents If project list is specified, also
build projects that depend on
projects on the list
...

Cette option s’utilise conjointement à l’option -pl. En plus de construire les modules demandés par l’option -pl, Maven va construire tous les modules qui dépendent de ces derniers.

arnaud@mbp-arnaud:~$ mvn install –pl moduleD -amd
[INFO] ------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] ModuleD ................. SUCCESS [4.881s]
[INFO] ModuleE ................. SUCCESS [0.478s]
[INFO] ModuleF ................. SUCCESS [0.427s]
[INFO]

Cas d’usage : Vous travaillez sur un module et vous voulez vérifier que vos modifications n’impactent pas les autres modules qui l’utilisent. Vous demandez donc à Maven de reconstruire ce module (-pl monModule) et tous ceux qui l’utilisent (-amd). Ainsi la compilation et les tests des autres modules valideront vos changements.
mvn install –pl monModule -amd
Reactor avec modules dépendants

Reprennez où vous voulez. L’option -rf

arnaud@mbp-arnaud:~$ mvn --help
usage: mvn [options] [@lt;goal (s)>] [<phase (s)>]
Options:
...
-rf,--resume-from <arg> Resume reactor from specified
project
...

Cette option permet de reprendre à un point donné (un module) l’ensemble de la construction du projet. Tout comme l’option -pl, le module passé en paramètre de l’option -rf est identifié à partir de son chemin relatif ou de son artifactId.

arnaud@mbp-arnaud:~$ mvn install –rf moduleD
[INFO] ------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] ModuleD ................. SUCCESS [9.707s]
[INFO] ModuleE ................. SUCCESS [0.625s]
[INFO] ModuleF ................. SUCCESS [0.679s]
[INFO] Project ................. SUCCESS [2.467s]
[INFO]

Cas d’usage : Vous travaillez sur votre projet et vous voulez le reconstruire entièrement pour valider vos changements. Vous lancez la construction et elle échoue dans le module D. Vous trouvez le problème et corrigez le module D erroné. A quoi bon relancer la construction complète alors que vous savez que les modules construits avant le module D n’ont pas été modifiés et ne peuvent pas être affecté par votre modification. Vous demandez donc à Maven de relancer toute la construction à partir du module D.
mvn install –rf moduleD
Reactor avec démarage depuis un module

8 thoughts on “Build partiel avec Maven : Construire moins pour aller plus vite.”

    1. J’avoue que je ne connaissais pas ce problème et qu’il est vrai que je suis formaté pour faire le clean quand je le sens nécessaire. Le problème exposé est tout à fait correct et la solution me semble bonne même si elle est une sorte de hack par rapport à la philosophie de Maven (au moins elle fonctionne même si elle apporte une nouvelle dose de magie). Ce sujet devrais à mon goût ressortir des tiroirs (le thread mentionné date de 2007) pour voir si Maven 3 pourrait améliorer cela. Avec le build // cela pourrait grandement améliorer la qualité et la rapidité des builds.

  1. Comment Imprimer la page?
    il manque tout le coté droit…
    Et je ne trouve pas le bouton “print format”…

  2. J’ai réussi à imprimer avec Firefox, mais sous IE, windows XP, il manque le coté droit (voir le PDF: http://dl.free.fr/rm.pl?h=mXxT7IfOF&i=26163107&s=XxT7IfOFGw1d4l4bGtR8ElaKW3NkEK5K)
    J’utilise IE pour lire ce type d’article car il est le seul à proposer le format .mht pour sauver les pages dans un format incluant les images dans un fichier unique , avec en bonus l’URL du document original dans l’entète (il faut l’ouvrir avec un éditeur de texte)

  3. Salut,
    est ce qu’on peut utiliser le reactor avec pom parent qui ne sert qu’a de l’héritage mais qui ne définit pas de modules ?
    En sachant que j’ai un projet qui définit des dépendances que je voudrais “construire en chaine”
    Merci 🙂

    1. Je ne pense pas. Le reacteur est construit à partir du projet en cours et de tous les modules déclarés. Ensuite les options -pl,-amd etc permettent de restreindre l’execution du réacteur à une sous partie des modules.

Comments are closed.