Primero, un poco de historia. A principios de la década de 2010, hice una pequeña utilidad de conversión para archivos BIN del emulador BK-0010 a archivos WAV. La utilidad fue escrita en Python con el objetivo de máxima portabilidad, funcionó sin problemas y la olvidé por un tiempo. Pero en 2016, apareció el usuario, que no tenía idea sobre Python y cómo instalarlo. Quería un monolito ejecutable simple que "simplemente funcionara". Su solicitud me pareció lógica, y decidí reelaborar la utilidad como un conjunto de archivos binarios ejecutables para las plataformas principales.

Python y Java no dieron esa oportunidad (a menos, por supuesto, que hubiera un deseo de inflar la utilidad en muchas decenas de megabytes). Potencialmente, la solución podría hacerse en C / C ++, pero con una cobertura tan específica de las plataformas, las dificultades con la compilación cruzada irían más allá del tiempo asignado para la tarea (y tuve que soportar el ensamblaje cruzado para Windows, Linux y MacOS en 64 y 32 bits opciones). Así que llamé la atención sobre el lenguaje Go, que está ganando popularidad, que en ese momento ya había madurado bastante y era el único que, sin "bailar con una pandereta", proporciona toda la compilación cruzada requerida de inmediato (!) .
Un inconveniente que me molestó mucho sobre Go (especialmente como desarrollador de Java) fue la poca consideración de organizar la estructura de los proyectos de Go y la necesidad de ajustar constantemente el entorno. Tal vez los desarrolladores de Go inicialmente planearon un uso específico o hubo un enfoque en los contenedores, pero me acostumbré al "sabroso" y como mi herramienta principal en Java es Maven , decidí hacer un complemento que haga llamadas a las utilidades y comandos GoSDK con la generación automática de los necesarios. Variables de entorno.
No fue interesante hacer un complemento simple que llamara a la utilidad go, y decidí ir desde el paso: instalar GoSDK en la plataforma host. Inmediatamente después del inicio, se verifica la presencia de GoSDK en su directorio de configuración (elegí la ruta predeterminada ~/.mvnGoLang
) y, en ausencia de la versión requerida, el archivo GoSDK se descarga y desempaqueta automáticamente del sitio oficial . Esto nos permitió hacer proyectos portátiles de Go sin preocuparnos de si la herramienta de la versión requerida está preinstalada y configurada. Por supuesto, con muchas configuraciones, preví la posibilidad de usar una versión preinstalada y configuraciones adicionales para todos los pasos en el proceso, ya que para muchos de estos problemas son críticos, como deshabilitar la verificación del certificado SSL o generalmente hacer solicitudes HTTP fuera (como para el proyecto Keycloak ).
El siguiente paso, envolví en los objetivos de Maven (objetivos) todos los comandos de utilidad go provistos en ese momento. Como existía la posibilidad de que apareciera otro nuevo comando con la nueva versión de GoSDK, se agregó una tarea custom
permite al usuario determinar el comando deseado por su cuenta. Por defecto, en el marco de las fases de maven (fases), las tareas se ejecutan en el siguiente orden:
- limpiar como
default-clean
en fase limpia - arreglar como arreglo
default-fix
en la fase de validación - obtener como
default-get
en la fase de inicialización - generar como
default-generate
en la fase de generar fuentes - fmt como
default-fmt
en la fase de fuentes de proceso - prueba como prueba
default-test
en la fase de prueba - compilar como compilación
default-build
en la fase de paquete - como instalación
default-install
tarea interna mvninstall se ejecuta en la fase de instalación - instalar como
default-deploy
en la fase de despliegue
Cualquiera de los pasos básicos se puede deshabilitar traduciendo la tarea a una fase inexistente:
<execution> <id>default-fix</id> <phase>none</phase> </execution>
En la implementación interna, las tareas se dividieron en "trabajar con dependencias" y "no requerir resolución de dependencia", después de la aparición de soporte para el modo módulo, la mayoría migró a "trabajar con dependencias".
La estructura del proyecto Go-maven, traté de acercarme a la estructura de carpetas estándar aceptada para Go (es decir, /src
y /bin
en la raíz del proyecto). Pero dado que Maven está encarcelado por Java, no fue directamente posible "romper" su enfoque para organizar la estructura del proyecto y hacer que este paso sea invisible para el usuario, por lo que la configuración básica del complemento parece un poco inusual incluso para muchos familiarizados con 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>
ADVERTENCIA Por alguna razón, el HabR puede mostrar incorrectamente la <sourceDirectory>${basedir}/src</sourceDirectory>
al formatear XML
Como puede ver, debe determinar directamente la carpeta de origen /src
y la carpeta con el resultado /bin
. Por un lado, esta es una desventaja, por otro lado, la posibilidad de cambiar su ubicación.
El pom.xml minimalista completo para un proyecto de un solo módulo, a la Hello world, es el siguiente:
<?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>
Tenga en cuenta que el paquete del proyecto se designa como mvn-golang . Esta configuración es suficiente para compilar el archivo ejecutable y colocarlo en la carpeta bin resultante sobre la base de los textos fuente en la carpeta src. Go build cache también se creará en la /bin
(como /bin/.goBuildCache
por defecto) y se borrará con clean con esta carpeta temporal.
En la fase de instalación , se mvninstall
tarea interna mvninstall
, que simplemente empaqueta todo el proyecto en un archivo zip y lo coloca en el repositorio maven como un artefacto generado. Inicialmente, solo almacené estos artefactos, pero a partir de la versión 2.3.2 se agregó un mecanismo para admitirlos como dependencias estándar de Maven y se hizo posible desarrollar proyectos con código común "compartido" a través del repositorio de Maven. Está claro que poner los resultados binarios generados en el repositorio como artefactos es una mala idea debido a los requisitos multiplataforma y, por lo tanto, el contenido de la carpeta /bin
no está empaquetado en el artefacto.
Conectar otro proyecto con el empaquetado mvn-golang
como una dependencia de mvn-golang
parece a esto:
<dependency> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-go-test-mix-terminal</artifactId> <version>1.0.0-SNAPSHOT</version> <type>mvn-golang</type> </dependency>
Con la versión 2.3.3, se agregó soporte para trabajar con el mecanismo Go de los módulos , pero por defecto no está activado (por compatibilidad con versiones anteriores) y se habilita utilizando el parámetro de configuración:
<moduleMode>true</moduleMode>
Cuando el mecanismo de los módulos Go todavía estaba en la etapa experimental, agregué soporte para trabajar con versiones de dependencia a través de llamadas directas a las utilidades CVS, se hizo un ejemplo de prueba . Pero ahora creo que dicho mecanismo ya no es de gran interés y es más rentable utilizar dependencias estándar a través de módulos. Además, el complemento puede preprocesar los archivos go.mod
en el momento de construir el proyecto, reemplazando las rutas a las carpetas locales si el trabajo continúa en el marco de un proyecto de varios módulos.
Como Maven ofrece la posibilidad de estandarizar el uso de arquetipos, hice dos arquetipos:
- com.igormaznitsa: mvn-golang-hello: 2.3.3 para un arquetipo simple de módulo único
- com.igormaznitsa: mvn-golang-hello-multi: 2.3.3 para un proyecto de varios módulos con código fuente compartido
Un ejemplo de cómo trabajar con el arquetipo de un proyecto de un solo módulo se puede ver en la animación a continuación.
.
También puede simplemente clonar el proyecto "Hello World" y jugar:
git clone https://github.com/raydac/mvn-golang-example.git

A menudo surge una pregunta razonable: ¿por qué todo esto es necesario y qué bonificaciones otorga el uso de Maven en el proceso de construcción de un proyecto Go? Intentaré responderlo punto por punto:
- Maven es un entorno de desarrollo de proyectos multiplataforma muy maduro, compatible con casi todas las plataformas de CI, por ejemplo Jenkins, con Go2XUnit puede convertir los resultados de las pruebas al formato que se muestra mediante los complementos de informes.
- Maven es multiplataforma y es compatible con todos los sistemas operativos, y se incluye en todos los repositorios. La presencia de perfiles activados de forma flexible facilita la personalización del proceso para varias plataformas.
- Maven tiene una ENORME cantidad de complementos , lo que facilita obtener un efecto sinérgico, por ejemplo, combinando Go y GWT , conectando ANTLR al proyecto , generando Go basado en descriptores de Protobuf e incluso agregando preprocesamiento . Todo esto se puede organizar manualmente a través de archivos por lotes, pero si hay complementos compatibles oficiales, entonces es más rentable usarlos.
- El proyecto se vuelve fácilmente portátil entre máquinas y plataformas, y el cambio de la versión GoSDK se realiza cambiando una línea.
- Facilidad para organizar proyectos de módulos múltiples, con la separación del código fuente a través del repositorio de Maven.
- La herramienta es familiar y familiar para los desarrolladores de Java, lo que facilita su adaptación al cambiar al desarrollo en Golang o al desarrollar soluciones multilingües de Go + Java.
- Existe la posibilidad de un pseudodesarrollo en Go en entornos compatibles con Maven, incluso si no tienen ningún soporte para esta plataforma, por ejemplo, en NetBeans IDE .
El mayor inconveniente de la solución, en mi opinión, es uno aquí: un número limitado de desarrolladores familiarizados con Maven entre la comunidad de Golang. Para aquellos que se cambiaron a Golang con C / C ++, está claro que es difícil encontrar algo más cercano y más caro, y nadie ha cancelado los sistemas "nativos" de Go-build. Noté que, por alguna razón, a muchos desarrolladores no les gusta mezclar plataformas.
Entonces, mostré brevemente una de las formas de usar Maven al desarrollar proyectos Go usando el complemento mvn-golang-wrapper. El proyecto de complemento está diseñado como un proyecto OSS y publicado en GitHub . Si alguien está interesado y lo usará en sus proyectos, no dude en hacer preguntas y "informar errores". Intenté hacer un conjunto de ejemplos para diferentes ocasiones (en las que se prueba el complemento), pero no puedo cubrir todo.
Los casos de prueba en el proyecto de complemento usan la versión de desarrollo, por lo que si desea construirlos localmente después de clonar el proyecto, primero debe construir la versión de desarrollo del complemento utilizando el comando en el directorio raíz del proyecto:
mvn install
después de lo cual, puede mvn-golang-examples
cualquier mvn-golang-examples
y construirlo con
mvn clean install
También puede comenzar a construir todos los ejemplos desde la raíz del proyecto, utilizando
mvn clean install -Pexamples
El complemento admite el ensamblaje de proyectos de subprocesos múltiples y puede acelerarse utilizando el argumento correspondiente, dividiéndose, por ejemplo, en 6 hilos
mvn clean install -Pexamples -T6
Durante el desarrollo, el proyecto ha acumulado una cantidad decente de "campanas y silbatos", que decidí no cubrir en este breve artículo. Puede encontrar información sobre los parámetros con pequeños ejemplos de configuración en el mapa mental de este complemento (el archivo fuente en formato SciaReto está aquí ):
