Maven-way para criar projetos Go

Primeiro, um pouco de fundo. No início de 2010, criei um pequeno utilitário de conversão de arquivos BIN do emulador BK-0010 para arquivos WAV. O utilitário foi escrito em Python com o objetivo de máxima portabilidade, funcionou sem problemas e eu me esqueci dele por um tempo. Mas em 2016, o usuário apareceu, que não tinha idéia do Python e como instalá-lo. Ele queria um monólito executável simples que "funcionasse". Seu pedido me pareceu lógico e decidi refazer o utilitário como um conjunto de arquivos executáveis ​​binários para as principais plataformas.


imagem


Python e Java não deram essa oportunidade (a não ser, é claro, que houvesse um desejo de aumentar o utilitário em muitas dezenas de megabytes). Potencialmente, a solução poderia ser feita em C / C ++, mas com uma cobertura tão direcionada das plataformas, as dificuldades com a compilação cruzada iriam além do tempo alocado para a tarefa (e eu tive que oferecer suporte à montagem cruzada para Windows, Linux e MacOS em 64 e 32 bits opções). Então, chamei a atenção para o idioma Go, que está ganhando popularidade, que já havia se tornado bastante maduro e o único que, sem "dançar com um pandeiro", fornece toda a compilação cruzada necessária logo de cara (!) .


Um inconveniente que me incomodou muito com o Go (especialmente como desenvolvedor Java) foi a falta de consideração da organização da estrutura dos projetos Go e a necessidade de ajustar constantemente o ambiente. Talvez os desenvolvedores do Go tenham planejado inicialmente algum uso específico ou houvesse um foco em contêineres, mas eu me acostumei com o "saboroso" e, como minha principal ferramenta em Java é o Maven , decidi criar um plug-in que faz chamadas para utilitários e comandos GoSDK com a geração automática dos necessários variáveis ​​de ambiente.


Não era interessante criar um plug-in simples que chamasse o utilitário go, e eu decidi ir da etapa - instalar o GoSDK na plataforma host. Imediatamente após o início, a presença do GoSDK é verificada em seu diretório de configuração (eu escolhi o caminho padrão ~/.mvnGoLang ) e, na ausência da versão necessária, o arquivo do GoSDK é automaticamente baixado e descompactado do site oficial . Isso nos permitiu criar projetos portáteis Go sem se preocupar se a ferramenta da versão necessária está pré-instalada e configurada. Obviamente, com muitas configurações, previ a possibilidade de usar uma versão pré-instalada e adicionei configurações para todas as etapas do processo, pois para muitos problemas, como desativar a verificação do certificado SSL ou geralmente fazer solicitações HTTP fora (como no projeto Keycloak ), são essenciais .


O próximo passo, envolvi nos objetivos do Maven (objetivos) todos os comandos do utilitário go fornecidos naquele momento. Como havia a chance de outro novo comando aparecer com a nova versão do GoSDK, uma tarefa custom foi adicionada, permitindo que o usuário determinasse o comando desejado por conta própria. Por padrão, dentro da estrutura de maven-phase (phase), as tarefas são executadas na seguinte ordem:


  • limpo como default-clean na fase limpa
  • corrigir como correção default-fix na fase de validação
  • obter como default-get na fase de inicialização
  • gerar como default-generate na fase gerar-fontes
  • fmt como default-fmt na fase de fontes de processo
  • teste como teste default-test na fase de teste
  • construir como construção default-build na fase do pacote
  • como default-install tarefa interna mvninstall é executada na fase de instalação
  • instalar como default-deploy na fase de implantação

Qualquer uma das etapas básicas pode ser desabilitada convertendo a tarefa em uma fase inexistente:


 <execution> <id>default-fix</id> <phase>none</phase> </execution> 

Na implementação interna, as tarefas foram divididas em “trabalhando com dependências” e “não exigindo resolução de dependência”, após o surgimento do suporte ao modo de módulo, mais migrado para “trabalhando com dependências”.


A estrutura do projeto Go-maven, tentei me aproximar da estrutura de pastas padrão aceita para Go (ou seja, /src e /bin na raiz do projeto). Mas como o Maven está preso no Java, não foi possível "quebrar" diretamente sua abordagem para organizar a estrutura do projeto e tornar essa etapa invisível para o usuário; portanto, a configuração básica do plug-in parece um pouco incomum, mesmo para muitos familiarizados com o 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> 

ATENÇÃO! Por alguma razão, o HabR pode exibir incorretamente a <sourceDirectory>${basedir}/src</sourceDirectory> ao formatar XML

Como você pode ver, você precisa determinar diretamente a pasta de origem /src e a pasta com o resultado /bin . Por um lado, isso é um sinal de menos, por outro lado, a possibilidade de alterar sua localização.


Todo o pom.xml minimalista de um projeto de módulo único, no mundo Hello, é o seguinte:


 <?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> 

Observe que a embalagem do projeto é designada como mvn-golang . Essa configuração é suficiente para criar o arquivo executável e colocá-lo na pasta bin resultante com base nos textos de origem na pasta src. O cache de compilação Go também será criado na /bin (como /bin/.goBuildCache por padrão) e será apagado com a limpeza desta pasta temporária.


Na fase de instalação , a tarefa interna mvninstall é mvninstall , que simplesmente empacota o projeto inteiro em um arquivo zip e o coloca no repositório maven como um artefato gerado. Inicialmente, eu apenas armazenei esses artefatos, mas a partir da versão 2.3.2, um mecanismo foi adicionado para suportá-los como dependências padrão do maven e tornou-se possível desenvolver projetos com "compartilhamento" de código comum por meio do repositório do maven. Está claro que colocar os resultados binários gerados no repositório como artefatos é uma má idéia devido a requisitos de plataforma cruzada e, portanto, o conteúdo da pasta /bin não é empacotado no artefato.


Conectar outro projeto com o empacotamento mvn-golang como uma dependência mvn-golang é algo como isto:


 <dependency> <groupId>com.igormaznitsa</groupId> <artifactId>mvn-go-test-mix-terminal</artifactId> <version>1.0.0-SNAPSHOT</version> <type>mvn-golang</type> </dependency> 

Com a versão 2.3.3, foi adicionado suporte para trabalhar com o mecanismo Go dos módulos , mas, por padrão, ele não é ativado (para compatibilidade com versões anteriores) e é ativado usando o parâmetro de configuração:


 <moduleMode>true</moduleMode> 

Quando o mecanismo dos módulos Go ainda estava em fase experimental, adicionei suporte para trabalhar com versões de dependência por meio de chamadas diretas aos utilitários do CVS, um exemplo de teste foi feito . Mas agora acho que esse mecanismo não é mais de grande interesse e é mais lucrativo usar dependências padrão por meio de módulos. Além disso, o plug-in é capaz de pré-processar os arquivos go.mod no momento da criação do projeto, substituindo os caminhos para as pastas locais, se o trabalho estiver em andamento na estrutura de um projeto com vários módulos.


Como o Maven prevê a possibilidade de padronização usando arquétipos, criei dois arquétipos:


  • com.igormaznitsa: mvn-golang-hello: 2.3.3 para um arquétipo de módulo único simples
  • com.igormaznitsa: mvn-golang-hello-multi: 2.3.3 para um projeto de vários módulos com código-fonte compartilhado

Um exemplo de trabalho com o arquétipo de um projeto de módulo único pode ser visto na animação abaixo
imagem .


Você também pode clonar o projeto "Hello World" e brincar:


 git clone https://github.com/raydac/mvn-golang-example.git 

imagem


Muitas vezes, surge uma pergunta razoável - por que tudo isso é necessário e quais bônus o uso do Maven dá no processo de construção de um projeto Go? Vou tentar responder ponto por ponto:


  1. O Maven é um ambiente de criação de projetos de plataforma cruzada muito maduro, suportado por quase todas as plataformas de CI, por exemplo, Jenkins. Usando o Go2XUnit, você pode converter os resultados dos testes no formato exibido pelos plug-ins de relatórios.
  2. O Maven é multiplataforma e é suportado por todos os sistemas operacionais, sendo incluído em todos os repositórios. A presença de perfis ativados de forma flexível facilita a personalização do processo para várias plataformas.
  3. O Maven possui uma enorme quantidade de plugins , o que facilita a obtenção de um efeito sinérgico, por exemplo, combinando o Go e o GWT , conectando o ANTLR ao projeto , gerando o Go com base nos descritores do Protobuf e até adicionando pré-processamento . Tudo isso pode ser organizado manualmente por meio de arquivos em lote, mas se houver plug-ins oficiais suportados, é mais rentável usá-los.
  4. O projeto se torna facilmente portátil entre máquinas e plataformas, e a troca da versão do GoSDK é feita alterando uma linha.
  5. Facilidade de organização de projetos com vários módulos, com a separação do código-fonte através do repositório Maven.
  6. A ferramenta é familiar e familiar aos desenvolvedores Java, o que facilita sua adaptação ao mudar para o desenvolvimento no Golang ou ao desenvolver soluções multilíngues Go + Java.
  7. Existe a possibilidade de pseudo-desenvolvimento on Go em ambientes que suportam o Maven, mesmo se eles não tiverem suporte para esta plataforma, por exemplo, no NetBeans IDE .

A maior desvantagem da solução, na minha opinião, é uma aqui - um número limitado de desenvolvedores familiarizados com o Maven na comunidade Golang. Para aqueles que mudaram para Golang com C / C ++, é claro que é difícil encontrar algo mais próximo e mais caro de fazer, assim como ninguém cancelou os sistemas Go-build "nativos". Percebi que, por algum motivo, muitos desenvolvedores não gostam de misturar plataformas.


Então, mostrei brevemente uma das maneiras de usar o Maven ao desenvolver projetos Go usando o plug-in mvn-golang-wrapper. O projeto do plug-in foi criado como um projeto OSS e publicado no GitHub . Se alguém estiver interessado e usar em seus projetos, não hesite em fazer perguntas e "reportar bugs". Tentei fazer um conjunto de exemplos para diferentes ocasiões (nas quais o plug-in está sendo testado), mas não posso cobrir tudo.


Os exemplos de teste no projeto de plug-in usam a versão dev, portanto, se você deseja criá-los localmente após a clonagem do projeto, primeiro você precisa criar a versão dev do plug-in usando o comando no diretório raiz do projeto:


 mvn install 

após o qual, você pode acessar qualquer subprojeto mvn-golang-examples e construí-lo com


 mvn clean install 

você também pode começar a criar todos os exemplos a partir da raiz do projeto, usando


 mvn clean install -Pexamples 

O plug-in suporta montagem de projetos com vários threads e pode ser acelerado usando o argumento correspondente, dividindo, por exemplo, em 6 threads


 mvn clean install -Pexamples -T6 

Durante o desenvolvimento, o projeto acumulou uma quantidade razoável de "sinos e assobios", que decidi não abordar neste pequeno artigo. Informações sobre os parâmetros com pequenos exemplos de configuração podem ser encontradas no mapa mental deste plug-in (o arquivo de origem no formato SciaReto está aqui ):


imagem

Source: https://habr.com/ru/post/pt465803/


All Articles