Mkdir700's Note

Mkdir700's Note

使用 GoReleaser 发布 Rust 二进制文件

2024-10-10

作为消费者,我们喜欢通过以下方式之一获取二进制发布:

  • 操作系统原生包格式,例如 deb、rpm 等。
  • 语言原生包格式,例如 pip、npm 等。通过这种方式提供纯二进制文件并不常见,但有些项目会这样做,例如 puppeteer,它会下载最新的无头 Chrome 二进制文件。
  • 使用 curl shell 组合,例如 curl http://acme.org/bin | sh,这种方式快速且无依赖,但受到批评,因为这实际上是让用户执行远程代码。因此,我通常避免这种方式,但如果必须使用,我会先手动验证 shell 脚本。
  • 现代二进制打包工具,例如 Homebrew。

虽然每种技术的过程可能有所不同,但它们都需要一种方式来托管二进制文件或包,语言原生包格式可能是个例外,因为你可以将大型二进制文件推送到注册表中(但这可能不被赞同)。

原则上,打包和发布需要以下步骤:

  1. 跨平台编译你的二进制文件(例如 Linux、Windows、macOS),因为我们要分发二进制文件,所以必须为每个平台和架构准备好版本。
  2. 打包(例如 tar、zip),某些平台需要特定的打包格式。
  3. 对你的包进行摘要(例如 sha 256)——虽然我们都享受着可靠的互联网连接和文件托管解决方案,但我们不能假设所有用户都如此。通过摘要验证下载是明智的。
  4. 使用某种路径格式方案上传到 <provider>(例如上传到 S 3,路径为 v0.0.1/project-name/tarball)。
  5. 设置分发工件(例如,使用给定的格式方案从 S 3 生成下载和验证的 shell 文件)。

对于开源项目,有很多工具可以使用,因为 Github Releases 和 Git 标签使得构建一个优秀的发布过程变得轻而易举。对于其他项目,Amazon S 3 是存储的完美选择,而有意见的发布格式化规则则有助于此。这就是 GoReleaser 发挥作用的地方。

使用 GoReleaser 与 Rust

虽然 GoReleaser 仅支持构建 Go 项目,但在打包和分发方面它做得非常出色,难以忽视。

它可以打包、生成 sha 256 校验和、上传到 Github releases 或 Amazon S 3 或自定义 HTTP 端点,还可以生成变更日志、语义版本等。网站上并没有展示所有功能,所以我建议查看仓库中的文档以了解更多支持的功能。

所以它拥有我们想要的一切,但它不能构建 Go 以外的任何东西。

从 Linux 主机使用 cross 进行 Rust 跨平台编译很容易,使用 TravisCI 和 trust 更加简单,但从 OSX 主机上就不容易了,更不用说如果你的项目不是开源的。

要在 OSX 系统上方便地进行跨平台构建,我是这样做 OSX 和 Linux 的:

docker run --rm -v`pwd`:/app liuchong/rustup:nightly sh -c 'cd /app && cargo build --release --target=x86_64-unknown-linux-gnu'
cargo build --release --target=x86_64-apple-darwin

完成构建后,你的 target/ 文件夹中会有 Linux 和 OSX(darwin)构建。

对于 Windows 构建,你可能需要回到 trust 并使用 CI 系统。

已经有努力使 GoReleaser 通用化,例如支持 Rust 的多语言支持,以及一些更通用化的讨论,最终形成一个通用基础设施。

目前仍然缺乏支持自定义构建器的插件架构的基础设施,这些构建器可以与 GoReleaser 一起工作,所以目前 Rust 仍然不受支持。

破解 GoReleaser 构建过程

这个破解方法围绕通过放置一个 dummy. go 文件来满足 GoReleaser,并在构建的后阶段进行钩入。

以下是一个工作的 .goreleaser.yaml 设置:

project_name: cep
builds:
  -
    main: dummy.go
    goarch:
      - amd64
    binary: cep
    hooks:
      post: sh build-cross-release.sh
archive:
  replacements:
    darwin: Darwin
    linux: Linux
    windows: Windows
    386: i386
    amd64: x86_64
checksum:
  name_template: 'checksums.txt'
s3:
  -
    bucket: cep-dev
    acl: public-read
release:
  disable: true

Go 的虚拟程序非常简单:

package main

func main() {
}

使用后阶段,我们实际上执行了必要的 Rust 构建,并将工件复制到 GoReleaser 期望的位置,覆盖 Go 工件(对于名为 cep 的项目):

# jondot: https://github.com/goreleaser/goreleaser/issues/962

docker run --rm -v`pwd`:/app liuchong/rustup:nightly sh -c 'cd /app && cargo build --release --target=x86_64-unknown-linux-gnu'
cargo build --release --target=x86_64-apple-darwin

mkdir -p dist/darwin_amd64 && cp target/x86_64-apple-darwin/release/cep dist/darwin_amd64
mkdir -p dist/linux_amd64 && cp target/x86_64-unknown-linux-gnu/release/cep dist/linux_amd64

GoReleaser 会愉快地继续构建的其余阶段,这意味着我们可以免费获得一切!

加分项:GoDownloader

可能不太为人所知,godownloader 是 GoReleaser 的姊妹项目。它会读取 .goreleaser.yaml 并为你生成一个 curl-shell 组合。

如果通过 curl http://your-binary.com/binary | sh 分发二进制文件是你的菜,你可以使用 godownloader 并免费获得一个聪明的 shell 脚本来安装你的二进制文件。

探索其他 Rust 发布工具

已经有现有的 Rust 工作旨在构建类似于 GoReleaser 的东西,但坦率地说,它还不够完整。你可以看看以下项目:

  • cargo-release
  • cargo-deliver
  • cargo-hublish

最后,如果你想从 OSX 进行 Rust 跨平台构建,可以看看 docker-rustup。