建立Go项目的Maven方法

首先,有一点背景。 在2010年代初期,我制作了一个小型转换器实用程序,用于将BK-0010仿真器的BIN文件转换为WAV文件。 该实用程序是用Python编写的,目的是实现最大的可移植性,它可以正常工作,并且我暂时忘记了它。 但是在2016年,用户出现了,他对Python及其安装方式一无所知。 他想要一个简单的可执行文件,它将“起作用”。 在我看来,他的要求似乎合乎逻辑,因此我决定将实用程序作为一组主要平台的二进制可执行文件进行重新设计。


图片


Python和Java并没有提供这样的机会(当然,除非有将实用程序增加数十兆字节的愿望)。 潜在地,该解决方案可以用C / C ++制成,但是针对平台的目标覆盖范围,交叉编译的困难将超出为任务分配的时间(而且我必须支持64位和32位Windows,Linux和MacOS的交叉汇编)选项)。 因此,我提请注意Go语言,该语言在当时已经非常成熟,并且已经越来越成熟,并且是唯一一个没有手鼓跳舞就可以提供所有必需的交叉编译功能的人(!)


使Go(尤其是Java开发人员)感到不便的一个不便之处是组织Go项目的结构的思想不足以及对不断调整环境的需求。 也许Go开发人员最初计划将其用于某些特定用途,或者专注于容器,但是我已经习惯了“美味”容器,并且由于我的Java主要工具是Maven ,所以我决定制作一个插件,该插件可以通过自动生成必要的工具来调用实用程序和GoSDK命令环境变量。


制作一个简单的插件来调用go实用程序并不有趣,我决定从第一步开始-在主机平台上安装GoSDK。 启动后,立即在其配置目录中检查GoSDK(我选择了默认路径~/.mvnGoLang ),并且在缺少所需版本的情况下,GoSDK存档会自动从官方站点下载并解压缩。 这使我们能够进行可移植的Go项目,而不必担心所需版本的工具是否已预先安装和配置。 当然,有了许多设置,我预见到了可能使用预安装版本并为过程中的所有步骤添加设置的可能性,因为对于许多问题(例如禁用SSL证书验证或通常向外部发出HTTP请求(例如对于Keycloak项目)来说都是至关重要的)


下一步,我将当时提供的所有go实用程序命令包装在Maven目标中。 由于新版本的GoSDK可能会出现另一个新命令,因此添加了一个custom任务,允许用户自行确定所需的命令。 默认情况下,在Maven阶段(阶段)的框架内,任务按以下顺序执行:


  • 清理default-clean ,阶段清理
  • 验证阶段修复default-fix
  • 获取 default-get 初始化阶段
  • generate-sources阶段作为default-generate 生成
  • 流程源阶段将fmt作为default-fmt
  • 测试阶段作为default-test进行测试
  • 软件包阶段以default-build
  • 作为default-install mvninstall内部任务在安装阶段执行
  • 部署阶段以default-deploy 安装

通过将任务转换为不存在的阶段,可以禁用任何基本步骤:


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

在内部实现中,在出现了对模块模式的支持之后,任务被分为“使用依赖项工作”和“不需要依赖项解决”,大部分迁移到了“使用依赖项工作”。


Go-maven项目的结构,我试图更接近Go接受的标准文件夹结构(即项目根目录中的/src/bin )。 但是由于Maven因使用Java而入狱,所以不可能直接“破坏”他组织项目结构的方法并使该步骤对用户不可见,因此即使对许多熟悉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> 

警告! 由于某些原因,HabR在格式化XML时可能会错误地显示<sourceDirectory>${basedir}/src</sourceDirectory>部分

如您所见,您必须直接确定源文件夹/src以及包含结果/bin的文件夹。 一方面,这是减少其位置的可能性,另一方面。


一个单模块项目(即Hello世界)的整个简约pom.xml如下:


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

请注意,该项目的包装指定为mvn-golang 。 此配置足以构建可执行文件,并根据src文件夹中的源文本将其放入生成的bin文件夹中。 Go构建缓存还将在/bin创建(默认情况下为/bin/.goBuildCache ),并将使用此临时文件夹清除干净。


安装阶段,内部mvninstall任务mvninstall ,它简单地将整个项目打包在一个zip归档文件中,并将其作为生成的工件放置在maven存储库中。 最初,我只是存储了这些工件,但是从2.3.2版本开始,添加了一种机制来支持它们作为标准的maven依赖关系,并且可以通过maven存储库“共享”公共代码来开发项目。 显然,由于跨平台的要求,将生成的二进制结果作为工件放入存储库是一个坏主意,因此/bin文件夹的内容未打包在工件中。


将另一个打包为 mvn-golang项目连接为maven依赖项,看起来像这样:


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

在版本2.3.3中,添加了使用模块Go机制的支持,但默认情况下未激活(出于向后兼容性),并且使用配置参数启用了该支持:


 <moduleMode>true</moduleMode> 

当Go模块的机制仍处于试验阶段时,我通过直接调用CVS实用程序添加了对使用依赖版本的支持,并制作了一个测试示例 。 但是现在我认为,这种机制已不再引起人们的广泛兴趣,通过模块使用标准依赖项会更加有利可图。 此外,该插件能够在构建项目时对go.mod文件进行预处理,如果在多模块项目的框架内正在进行工作,则可以替换本地文件夹的路径。


由于Maven提供了使用原型进行标准化的可能性,因此我提出了两种原型:


  • com.igormaznitsa:mvn-golang-hello:2.3.3用于简单的单模块原型
  • com.igormaznitsa:mvn-golang-hello-multi:具有共享源代码的多模块项目的2.3.3

在下面的动画中可以看到使用单模块项目原型的示例。
图片


您还可以仅克隆“ Hello World”项目并进行以下操作:


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

图片


通常会出现一个合理的问题-为什么所有这些都是必要的,并且在构建Go项目的过程中使用Maven有何好处? 我将尝试一点一点地回答它:


  1. Maven是一个非常成熟的跨平台项目构建环境,几乎所有CI平台(例如Jenkins)都支持Maven, 使用Go2XUnit您可以将测试结果转换为报告插件显示的格式。
  2. Maven是跨平台的,并且受所有存储库中所有操作系统的支持。 灵活激活的配置文件的存在使您可以轻松地针对各种平台自定义流程。
  3. Maven拥有大量的插件 ,例如通过组合Go和GWT ,将ANTLR连接到项目基于Protobuf描述符生成Go甚至添加预处理 ,可以很容易地获得协同效果。 所有这些都可以通过批处理文件手动组织,但是如果有官方支持的插件,那么使用它们会更有利可图。
  4. 该项目变得易于在机器和平台之间移植,并且通过更改一行来切换GoSDK版本。
  5. 易于组织多模块项目,并通过Maven存储库分离源代码。
  6. 该工具对于Java开发人员来说是熟悉的,在切换到Golang上的开发或开发多语言的Go + Java解决方案时,它可以促进他们的适应。
  7. 即使在不支持该平台的环境中,例如在NetBeans IDE中 ,也可以在支持Maven的环境中在Go上进行伪开发。

我认为,该解决方案的最大缺点就是一个-有限的Golang社区中熟悉Maven的开发人员。 对于那些使用C / C ++切换到Golang的人来说,很显然,很难找到更接近,更昂贵的东西,而且没有人取消“原生” Go-build系统。 我注意到,由于某些原因,许多开发人员不喜欢混合使用平台。


因此,我简要介绍了使用mvn-golang-wrapper插件开发Go项目时使用Maven的方法之一。 该插件项目被设计为OSS项目,并发布在GitHub上 。 如果有人感兴趣并且愿意在他们的项目中使用,那么不要犹豫,提出问题并“报告错误”。 我尝试为不同的场合提供组示例 (正在测试插件),但是我无法涵盖所有​​内容。


插件项目中的测试示例使用dev版本,因此,如果要在克隆项目后在本地构建它们,则首先需要使用项目根目录中的命令来构建插件的dev版本:


 mvn install 

之后,您可以进入任何mvn-golang-examples子项目并使用


 mvn clean install 

您还可以使用以下命令从项目的根目录开始构建所有示例


 mvn clean install -Pexamples 

该插件支持项目的多线程组装,可以使用相应的参数进行加速,例如分为6个线程


 mvn clean install -Pexamples -T6 

在开发过程中,该项目积累了相当数量的“钟声和口哨声”,我决定在这篇简短的文章中不作介绍。 有关带有小型配置示例的参数的信息,可以在此插件的思维导图中找到( SciaReto格式的源文件在此处 ):


图片

Source: https://habr.com/ru/post/zh-CN465803/


All Articles