Tout d'abord, un peu d'histoire. Au début des années 2010, j'ai créé un petit utilitaire de conversion pour les fichiers BIN de l'émulateur BK-0010 en fichiers WAV. L'utilitaire a été écrit en Python dans le but d'une portabilité maximale, il a fonctionné sans problème et je l'ai oublié pendant un moment. Mais en 2016, l'utilisateur est apparu, qui n'avait aucune idée de Python et comment l'installer. Il voulait un simple monolithe exécutable qui "fonctionnerait tout simplement". Sa demande m'a semblé logique et j'ai décidé de retravailler l'utilitaire comme un ensemble de fichiers exécutables binaires pour les principales plates-formes.

Python et Java n'ont pas donné une telle opportunité (à moins bien sûr que l'on veuille gonfler l'utilitaire de plusieurs dizaines de mégaoctets). Potentiellement, la solution pourrait être faite en C / C ++, mais avec une telle couverture ciblée des plates-formes, les difficultés de compilation croisée dépasseraient le temps alloué pour la tâche (et j'ai dû prendre en charge le montage croisé pour Windows, Linux et MacOS en 64 et 32 bits options). J'ai donc attiré l'attention sur le langage Go, qui gagne en popularité, qui à cette époque était déjà devenu assez mature et le seul qui, sans toutes les danses avec un tambourin, fournit toute la compilation croisée requise dès la sortie de la boîte (!) .
Un inconvénient qui m'a beaucoup ennuyé à propos de Go (en particulier en tant que développeur Java) était la médiocrité de l'organisation de la structure des projets Go et la nécessité d'ajuster constamment l'environnement. Peut-être que les développeurs de Go avaient initialement prévu une utilisation spécifique ou l'accent était mis sur les conteneurs, mais je me suis habitué à celui «savoureux» et comme mon principal outil en Java est Maven , j'ai décidé de faire un plug-in qui appelle les utilitaires et les commandes GoSDK avec la génération automatique des nécessaires. variables d'environnement.
Ce n'était pas intéressant de créer un simple plugin qui appellerait l'utilitaire go, et j'ai décidé de passer à l'étape - installer GoSDK sur la plateforme hôte. Immédiatement après le démarrage, le GoSDK est vérifié dans son répertoire de configuration (j'ai choisi le chemin par défaut ~/.mvnGoLang
) et, en l'absence de la version requise, l'archive GoSDK est automatiquement téléchargée et décompressée depuis le site officiel . Cela nous a permis de créer des projets Go portables sans se soucier de savoir si l'outil de la version requise est préinstallé et configuré. Bien sûr, avec de nombreux paramètres, j'ai prévu la possibilité d'utiliser une version préinstallée et des paramètres ajoutés pour toutes les étapes du processus, car pour de nombreux problèmes de ce type, ils sont critiques, tels que la désactivation de la vérification des certificats SSL ou généralement les requêtes HTTP à l'extérieur (comme pour le projet Keycloak ).
L'étape suivante, j'ai enveloppé dans les objectifs Maven (objectifs) toutes les commandes de l'utilitaire go fournies à ce moment-là. Puisqu'il y avait une chance qu'une autre nouvelle commande apparaisse avec la nouvelle version de GoSDK, une tâche custom
été ajoutée permettant à l'utilisateur de déterminer la commande souhaitée par lui-même. Par défaut, dans le cadre de maven-phases (phases), les tâches sont exécutées dans l'ordre suivant:
- nettoyer comme nettoyage par
default-clean
en phase propre - correction comme correction par
default-fix
dans la phase de validation - obtenir par
default-get
en phase d' initialisation - générer comme génération par
default-generate
dans la phase de génération de sources - fmt comme
default-fmt
dans la phase des sources de processus - test comme test par
default-test
dans la phase de test - construire en tant que build par
default-build
dans la phase de package - comme
default-install
par default-install
tâche interne mvninstall est exécutée dans la phase d' installation - installer en tant que
default-deploy
par default-deploy
dans la phase de déploiement
N'importe laquelle des étapes de base peut être désactivée en traduisant la tâche en une phase inexistante:
<execution> <id>default-fix</id> <phase>none</phase> </execution>
Dans l'implémentation interne, les tâches étaient divisées en «travailler avec les dépendances» et «ne nécessitant pas de résolution de dépendance», après l'apparition de la prise en charge du mode module, la plupart ont migré vers «travailler avec les dépendances».
La structure du projet Go-maven, j'ai essayé de me rapprocher de la structure de dossier standard acceptée pour Go (c'est /src
dire /src
et /bin
à la racine du projet). Mais comme Maven est emprisonné pour Java, il n'a pas été directement possible de «casser» son approche de l'organisation de la structure du projet et de rendre cette étape invisible pour l'utilisateur, de sorte que la configuration de base du plugin semble un peu inhabituelle même pour beaucoup familiers avec maven:
<build> ```${basedir}/src</sourceDirectory> <directory>${basedir}/bin</directory> <plugins> <plugin> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-golang-wrapper</artifactId> <version>2.3.3</version> <extensions>true</extensions> <configuration> <goVersion>1.12.9</goVersion> </configuration> </plugin> </plugins> </build>
ATTENTION! Pour une raison quelconque, le HabR peut afficher de manière incorrecte la section <sourceDirectory>${basedir}/src</sourceDirectory>
lors du formatage XML
Comme vous pouvez le voir, vous devez déterminer directement le dossier source /src
et le dossier avec le résultat /bin
. D'une part, c'est un inconvénient, d'autre part, la possibilité de changer leur emplacement.
L'ensemble pom.xml minimaliste pour un projet à module unique, un monde la Hello, est le suivant:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-golang-helloworld</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>mvn-golang</packaging> <build> ```${basedir}/src</sourceDirectory> <directory>${basedir}/bin</directory> <plugins> <plugin> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-golang-wrapper</artifactId> <version>2.3.3</version> <extensions>true</extensions> <configuration> <goVersion>1.12.9</goVersion> </configuration> </plugin> </plugins> </build> </project>
Veuillez noter que l'emballage du projet est désigné comme mvn-golang . Cette configuration est suffisante pour construire le fichier exécutable et le placer dans le dossier bin résultant sur la base des textes sources dans le dossier src. Le cache de génération Go sera également créé dans le /bin
(comme /bin/.goBuildCache
par défaut) et sera effacé avec clean avec ce dossier temporaire.
Dans la phase d' installation , la tâche mvninstall
interne est mvninstall
, qui emballe simplement l'ensemble du projet dans une archive zip et le place dans le référentiel maven en tant qu'artefact généré. Au départ, je venais de stocker ces artefacts, mais à partir de la version 2.3.2 un mécanisme a été ajouté pour les prendre en charge en tant que dépendances maven standard et il est devenu possible de développer des projets avec "partage" de code commun via le référentiel maven. Il est clair que placer les résultats binaires générés dans le référentiel en tant qu'artefacts est une mauvaise idée en raison des exigences multiplates-formes et donc le contenu du dossier /bin
n'est pas empaqueté dans l'artefact.
Connecter un autre projet avec l' empaquetage mvn-golang
tant que dépendance mvn-golang
ressemble à ceci:
<dependency> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-go-test-mix-terminal</artifactId> <version>1.0.0-SNAPSHOT</version> <type>mvn-golang</type> </dependency>
Avec la version 2.3.3, un support a été ajouté pour travailler avec le mécanisme Go des modules , mais par défaut, il n'est pas activé (pour la compatibilité descendante) et est activé à l'aide du paramètre de configuration:
<moduleMode>true</moduleMode>
Lorsque le mécanisme des modules Go était encore au stade expérimental, j'ai ajouté la prise en charge du travail avec les versions de dépendance via des appels directs aux utilitaires CVS, un exemple de test a été réalisé . Mais maintenant, je pense qu'un tel mécanisme n'est plus d'un grand intérêt et qu'il est plus rentable d'utiliser des dépendances standard via des modules. De plus, le plugin est capable de prétraiter les fichiers go.mod
au moment de la construction du projet, en remplaçant les chemins vers les dossiers locaux si le travail est en cours dans le cadre d'un projet multi-module.
Étant donné que Maven prévoit la possibilité de normalisation à l'aide d'archétypes, j'ai créé deux archétypes:
- com.igormaznitsa: mvn-golang-hello: 2.3.3 pour un archétype simple à module unique
- com.igormaznitsa: mvn-golang-hello-multi: 2.3.3 pour un projet multi-module avec code source partagé
Un exemple de travail avec l'archétype d'un projet à module unique peut être vu dans l'animation ci-dessous
.
Vous pouvez également simplement cloner le projet "Hello World" et jouer:
git clone https://github.com/raydac/mvn-golang-example.git

Souvent, une question raisonnable se pose - pourquoi tout cela est nécessaire et quels bonus l'utilisation de Maven donne-t-elle dans le processus de construction d'un projet Go? J'essaierai d'y répondre point par point:
- Maven est un environnement de construction de projet multiplateforme très mature, pris en charge par presque toutes les plates-formes CI, par exemple Jenkins, en utilisant Go2XUnit, vous pouvez convertir les résultats des tests au format affiché par les plugins de rapport.
- Maven est multiplateforme et pris en charge par tous les systèmes d'exploitation, étant inclus dans tous les référentiels. La présence de profils activés de manière flexible facilite la personnalisation du processus pour différentes plates-formes.
- Maven a une énorme quantité de plugins , ce qui facilite l'obtention d'un effet synergique, par exemple en combinant Go et GWT , en connectant ANTLR au projet , en générant Go en fonction des descripteurs Protobuf et même en ajoutant du prétraitement . Tout cela peut être organisé manuellement via des fichiers batch, mais s'il existe des plugins officiellement pris en charge, il est plus rentable de les utiliser.
- Le projet devient facilement portable entre les machines et les plates-formes, et la commutation de la version GoSDK se fait en changeant une ligne.
- Facilité d'organisation des projets multi-modules, avec séparation du code source via le référentiel Maven.
- L'outil est familier aux développeurs Java, ce qui facilite leur adaptation lors du passage au développement sur Golang ou lors du développement de solutions Java Go + multilingues.
- Il existe la possibilité de pseudo-développement sur Go dans des environnements qui prennent en charge Maven, même s'ils ne prennent pas en charge cette plate-forme, par exemple, dans l' IDE NetBeans .
Le plus gros inconvénient de la solution, à mon avis, en est un ici - un nombre limité de développeurs familiers avec Maven au sein de la communauté Golang. Pour ceux qui sont passés à Golang avec C / C ++, il est clair qu'il est difficile de trouver quelque chose de plus proche et plus cher à faire, et personne n'a annulé les systèmes de construction Go «natifs». J'ai remarqué que pour une raison quelconque, de nombreux développeurs n'aiment pas mélanger les plates-formes.
J'ai donc brièvement montré l'une des façons d'utiliser Maven lors du développement de projets Go à l'aide du plugin mvn-golang-wrapper. Le projet de plugin est conçu comme un projet OSS et publié sur GitHub . Si quelqu'un est intéressé et utilisera dans ses projets, alors n'hésitez pas à poser des questions et à "signaler des bugs". J'ai essayé de faire un ensemble d'exemples pour différentes occasions (sur lesquelles le plugin est testé), mais je ne peux pas tout couvrir.
Les cas de test dans le projet de plugin utilisent la version de développement, donc si vous voulez les construire localement après le clonage du projet, vous devez d'abord construire la version de développement du plugin en utilisant la commande dans le répertoire racine du projet:
mvn install
après quoi, vous pouvez aller dans n'importe quel mvn-golang-examples
et le construire avec
mvn clean install
vous pouvez également commencer à construire tous les exemples à partir de la racine du projet, en utilisant
mvn clean install -Pexamples
Le plugin prend en charge l'assemblage multi-thread de projets et il peut être accéléré en utilisant l'argument correspondant, se divisant par exemple en 6 threads
mvn clean install -Pexamples -T6
Pendant le développement, le projet a accumulé une quantité décente de «cloches et sifflets», que j'ai décidé de ne pas couvrir dans ce court article. Des informations sur les paramètres avec de petits exemples de configuration peuvent être trouvées dans la carte mentale de ce plugin (le fichier source au format SciaReto est ici ):
