使用 0install 进行二进制分发

0install 提供了一种向用户分发二进制文件的方式,作为 OPAM 对源代码分发支持的补充。

传统的二进制文件分发方式是为流行的 Linux 发行版的最新版本创建单独的软件包(RPM、Deb、PKGBUILD 等),为 OS X 创建 .pkg 文件,为 Windows 创建 setup.exe 文件,以及为其他系统或没有 root 权限的用户提供一些通用二进制文件。这需要大量的工作,并且需要对许多不同的软件包格式有专业知识。0install 提供了一种支持所有平台的单一格式,这意味着您只需要执行一次打包工作(尽管您仍然应该在多个平台上测试)。

示例:OPAM 二进制文件

您可以在大多数系统上安装 OPAM 的二进制版本,方法是首先从您的发行版中安装“0install”软件包(在较旧的发行版中为“zeroinstall-injector”,然后添加 OPAM。

  1. 获取 0install。适用于主要的 Linux 发行版

     $ yaourt -S zeroinstall-injector             # Arch Linux
     $ sudo apt-get install zeroinstall-injector  # Debian, Ubuntu, etc
     $ sudo yum install 0install                  # Fedora
     $ sudo yum install zeroinstall-injector      # Red Hat
     $ sudo zypper install zeroinstall-injector   # OpenSUSE
    

    对于 OS X:ZeroInstall.pkg

    0install 也支持 Windows,但目前还没有 OPAM 的 Windows 二进制文件,因此我也没有使用 0install 发布。

  2. 安装 opam

     $ 0install add opam https://tools.ocaml.org/opam.xml
     $ opam --version
     1.1.1
    

    如果您已经拥有 opam 命令,但仍然想尝试 0install 版本,只需为其指定一个不同的名称(例如,0install add 0opam https://tools.ocaml.org/opam.xml 创建 0opam 命令)。

如果显示可用,0install add 将打开一个窗口;如果显示不可用,则在控制台上显示进度。

如果您希望在所有情况下都使用控制台,请使用 --console

0install 使用完整的 URI 而不是短名称来标识每个软件包。在这里,我们告诉 0install 创建一个名为 opam 的本地命令,该命令运行程序https://tools.ocaml.org/opam.xml

0install 将其安装的每个软件包都保存在一个单独的目录中,这样就不会与任何东西发生冲突。您可以使用“show”命令查看它将 OPAM 放置在何处。

$ 0install show opam
- URI: https://tools.ocaml.org/opam.xml
  Version: 1.1.1
  Path: /home/test/.cache/0install.net/implementations/sha256new_RUOX6PWGDCHH5TDNEDRHQJ54YZZ4TSAGBB5AEBRNOKSHM3N7XORA
  
  - URI: http://repo.roscidus.com/utils/aspcud
    Version: 1.9.0
    Path: /home/test/.cache/0install.net/implementations/sha1new=5f838f78e489dabc2e2965ba100f14ae8350cbce
  
  - URI: http://repo.roscidus.com/utils/curl
    Version: 7.32.0-10.20
    Path: (package:rpm:curl:7.32.0-10.20:x86_64)

OPAM 依赖于另外两个程序:aspcud 提供了一个比内部程序更好的求解器,curl 用于下载 OPAM 软件包(它通常还需要 gccm4patch,但我只从人们可能缺少的程序开始)。在这种情况下,0install 使用官方的 Fedora 软件包满足了 curl 依赖关系,但需要使用 0install 安装 aspcud。在 Arch Linux 上,它可以使用两个发行版的软件包。0install 将使用 PackageKit 安装任何必需的发行版软件包,这将根据其策略提示用户许可。

您可以通过添加版本约束来升级(或降级)软件包。默认情况下,0install 优先选择程序的“稳定”版本。

$ 0install update opam
A later version (https://tools.ocaml.org/opam.xml 1.2.0-pre4) exists but was not selected.
Using 1.1.1 instead.
To select "testing" versions, use:
0install config help_with_testing True

您可以按照建议的操作,告诉它全局优先选择测试版本,或者如果您只想影响此程序,则可以添加版本约束。

$ 0install update opam --not-before=1.2.0-pre4
https://tools.ocaml.org/opam.xml: 1.1.1 -> 1.2.0-pre4

如果您愿意,还可以指定上限(--before)或固定版本(--version)。您可以使用 --version-for 控制依赖项的版本。顺便说一句,0install 在任何地方都支持制表符补全:它可以在子命令(update)、应用程序名称(opam)、选项(--not-before)甚至可用版本的列表上进行补全!

最后,如果升级导致程序无法工作,则可以使用 whatchanged 查看最新的更改。

$ 0install whatchanged opam
Last checked    : 2014-08-26 11:00
Last update     : 2014-08-26
Previous update : 2014-07-03

https://tools.ocaml.org/opam.xml: 1.1.1 -> 1.2.0-pre4

To run using the previous selections, use:
0install run /home/tal/.config/0install.net/apps/opam/selections-2014-07-03.xml

注意:这具有每天的粒度,因此如果您正在关注,您将看不到任何更改,因为您昨天没有安装它。

软件包元数据

如果您访问https://tools.ocaml.org/opam.xml,您应该会看到一个描述软件包的普通网页。如果您在浏览器中查看源代码,您会发现它实际上是一个 XML 文档,其中包含一个样式表提供格式。这是一个摘录。

<group license="OSI Approved :: GNU Lesser General Public License (LGPL)">
  <group>
    <requires interface="http://repo.roscidus.com/utils/aspcud"
              importance="recommended">
      <executable-in-var name="OPAMEXTERNALSOLVER"/>
    </requires>

    <requires interface="http://repo.roscidus.com/utils/curl"
              importance="recommended">
      <executable-in-var name="OPAMCURL"/>
    </requires>

    <command name="run" path="opam"/>

    <implementation arch="Linux-x86_64"
                    id="sha1new=6e16ff6ee58e39c9ebbed2fb6c6b6cc437b624a4"
                    released="2014-04-17"
                    stability="stable"
                    version="1.1.1">
      <manifest-digest sha256new="RUOX6PWGDCHH5TDNEDRHQJ54YZZ4TSAGBB5AEBRNOKSHM3N7XORA"/>
      <archive href="http://test.roscidus.com/archives/opam-Linux-x86_64-1.1.1.tgz"
               size="1476315"/>
    </implementation>

这表示 OPAM 1.1.1 的 64 位 Linux 二进制文件可在给定的 URL 上获得,并且解压缩后具有给定的 SHA256 校验和。可以通过执行存档中的 opam 二进制文件来运行它。它依赖于 aspcudcurl,它们位于其他存储库中(理想情况下,这些应该是这些程序的官方项目站点,但目前它们由第三方提供)。在这两种情况下,我们都通过设置环境变量来告诉 OPAM 选择的版本。<group> 元素避免为多个版本重复相同的信息。curl 被标记为 recommended,因为虽然0install 支持大多数发行版软件包管理器,但如果它找不到 curl 软件包,则更有可能找不到 curl 软件包,而不是平台没有 curl。

下面有一个更复杂的条目,说明如何从源代码构建,这提供了一种生成更多二进制文件的方法,并且 XML 后面跟着一个 GPG 签名块(格式化为 XML 注释,以便该文档仍然是有效的 XML)。

安全性

当您第一次使用程序时,0install 会下载签名的 GPG 密钥并使用密钥信息服务进行检查。如果此服务知道密钥,则将其保存为该站点的受信任密钥。否则,它会提示您确认。将来,它将检查来自该站点的所有更新是否都使用相同的密钥签名,如果没有则提示您(类似于 ssh 的操作)。

如果您希望查看密钥信息提示而不是自动批准它们,请使用 0install config auto_approve_keys false 或在 GUI 中关闭“自动批准新提要”,并取消信任密钥(右键单击它以显示菜单)。

首次使用新站点时,您将看到如下提示。

创建软件包

理想情况下,OPAM 自己的 Git 存储库将包含一个 XML 文件,描述其构建和运行时依赖项(在这种情况下为 curlaspcud)以及如何从中构建二进制文件。然后,我们将使用诸如0release之类的工具自动生成其发布的 XML。但是,在尝试使用 0install 时,您可能更喜欢打包现有的二进制版本,这就是我为 OPAM 所做的。

最简单的情况是二进制文件位于当前目录中。在这种情况下,XML 只描述其依赖项以及如何运行它,但不描述如何下载程序。您可以使用0template创建模板 XML 文件(或自己编写)。

$ 0install add 0template http://0install.net/tools/0template.xml
$ 0template opam.xml
'opam.xml' does not exist; creating new template.

As it ends with .xml, not .xml.template, I assume you want a feed for
a local project (e.g. a Git checkout). If you want a template for
publishing existing releases, use opam.xml.template instead.

Does your program need to be compiled before it can be used?

1) Generate a source template (e.g. for compiling C source code)
2) Generate a binary template (e.g. for a pre-compiled binary or script)
> 2

Writing opam.xml

填写空白,我们得到

<?xml version="1.0"?>
<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
  <name>OPAM</name>
  <summary>OCaml package manager</summary>

  <description>
    OPAM is an open-source package manager edited by OCamlPro.
    It supports multiple simultaneous compiler installations, flexible
    package constraints, and a Git-friendly development workflow.
  </description>

  <homepage>https://opam.ocaml.org/</homepage>

  <feed-for interface="https://tools.ocaml.org/opam.xml"/>

  <group license="OSI Approved :: GNU Lesser General Public License (LGPL)">
    <requires importance="recommended" interface="http://repo.roscidus.com/utils/aspcud">
      <executable-in-var name="OPAMEXTERNALSOLVER"/>
    </requires>

    <requires importance="recommended" interface="http://repo.roscidus.com/utils/curl">
      <executable-in-var name="OPAMCURL"/>
    </requires>

    <command name="run" path="opam"/>

    <implementation arch="Linux-x86_64" id="." local-path="." version="1.1.1"/>
  </group>
</interface>

这与上面的 XML 几乎相同,只是我们指定了 local-path="." 而不是提供 URL 和摘要(有关详细信息,请参阅提要文件格式规范)。<feed-for> 指明了我们最终将在哪里托管所有版本的公共列表。

您可以像这样在本地测试您的 XML

$ 0install run opam.xml --version
1.1.1

$ 0install select opam.xml          
- URI: /tmp/opam/opam.xml
  Version: 1.1.1
  Path: /tmp/opam
  
  - URI: http://repo.roscidus.com/utils/aspcud
    Version: 1.9.0-1
    Path: (package:arch:aspcud:1.9.0-1:x86_64)
  
  - URI: http://repo.roscidus.com/utils/curl
    Version: 7.37.1-1
    Path: (package:arch:curl:7.37.1-1:x86_64)

现在我们需要一种方法为 Web 上发布的存档生成类似的 XML。将 opam.xml 重命名为 opam.xml.template 并将 <implementation> 更改为

<implementation arch="{arch}" version="{version}">
  <manifest-digest/>
  <archive href="http://example.com/archives/opam-{arch}-{version}.tgz"/>
</implementation>

如果存档已在某个地方发布,则可以在 <archive> 中使用完整 URL。如果您在本地进行新的发布,只需将存档放在与 XML 相同的目录中并提供叶节点(href="opam-{arch}-{version}.tgz")。

您现在可以对模板 XML 运行 0template 以生成填充了哈希、大小等的 XML。

$ 0template opam.xml.template version=1.1.1 arch=Linux-x86_64
Writing opam-1.1.1.xml

这将生成

<group license="OSI Approved :: GNU Lesser General Public License (LGPL)">
  <requires importance="recommended" interface="http://repo.roscidus.com/utils/aspcud">
    <executable-in-var name="OPAMEXTERNALSOLVER"/>
  </requires>

  <requires importance="recommended" interface="http://repo.roscidus.com/utils/curl">
    <executable-in-var name="OPAMCURL"/>
  </requires>

  <command name="run" path="opam"/>

  <implementation arch="Linux-x86_64"
                  id="sha1new=6e16ff6ee58e39c9ebbed2fb6c6b6cc437b624a4"
                  released="2014-08-26"
                  version="1.1.1">
    <manifest-digest sha256new="RUOX6PWGDCHH5TDNEDRHQJ54YZZ4TSAGBB5AEBRNOKSHM3N7XORA"/>
    <archive href="http://example.com/archives/opam-Linux-x86_64-1.1.1.tgz" size="1476315"/>
  </implementation>
</group>

您可以像以前一样测试它。

$ 0install run opam-1.1.1.xml --version
1.1.1

最后,您可以使用0repo工具将 XML 提交到存储库(很容易自己托管)。

$ 0install add 0repo http://0install.net/tools/0repo.xml
[ ... configure your repository ... ]
$ 0repo add opam-1.1.1.xml

0repo 将 XML 合并到存储库的主版本列表中,上传存档(或测试 URL,如果已上传),将最终 XML 提交到 Git,并将 XML 推送到您的 Web 服务器。有更简单的方法来获取签名的 XML,例如使用0publish-gui获取图形 UI,但是如果您要发布一个程序的多个版本,那么您从 0repo 获得的自动化(和健全性检查)通常是值得的。在我的例子中,我将 0repo 配置为将签名的 XML 推送到 GitHub Pages 存储库。

有很多方法可以扩展它。对于 OPAM 1.2 版本,我没有一个接一个地添加官方二进制文件,而是使用了 0template 创建了一个源代码模板,添加了 1.2 源代码版本,并用它生成了二进制文件(主要是因为我想在一个旧的 Docker 容器中构建,以便二进制文件可以在更多系统上工作)。对于我自己的软件,我会将一个 XML 文件提交到我的 Git 仓库,说明如何构建它,并让 0release 处理整个发布过程(从标记 Git 仓库,到在各种虚拟机中构建二进制文件,再到发布归档文件和最终签名的 XML 文件)。将来,我们希望将此与 OPAM 集成,以便源代码和二进制文件的发布可以同时进行。

扩展 0install

0install 很容易使用脚本编写。它有一个稳定的命令行界面(以及一个新的 JSON API)。它还有一个 OCaml API,但这个 API 还不稳定(它仍然有点 Python 风格,因为该软件最近从 Python 移植到 OCaml)。

例如,我使用 0install 来管理 Mirage 微内核 的 Xen 镜像。以下命令显示了 Xen 的 mir-hello 微内核的最新二进制文件(如果需要,会先下载它)

$ 0install download --os=Xen http://test.roscidus.com/mir-console.xml --show
- URI: http://test.roscidus.com/mir-console.xml
  Version: 0.2
  Path: /home/tal/.cache/0install.net/implementations/sha256new_EY2FDE4ECMNCXSRUZ3BSGTJQMFXE2U6C634PBDJKOBUU3SWD5GDA

总结

0install 是一个成熟的跨平台软件管理系统,包含在大多数 Linux 发行版的软件仓库中,也适用于 Windows、OS X 和 Unix。在用户不需要从源代码编译的情况下,它非常适合分发二进制可执行文件。它支持 GPG 签名检查、自动更新、固定版本和多个版本的并行安装。所有平台都使用单一的软件包格式(当然,您仍然需要为例如 OS X 和 Linux 创建单独的二进制归档文件)。

0install 是一个去中心化的系统,这意味着没有中央仓库。软件包由 URI 命名,元数据直接从指定的仓库下载。有一些额外的服务(例如 默认镜像服务、搜索服务和密钥信息服务),但这些都是可选的。

使用 0install 获取 OPAM 意味着所有平台都无需单独打包即可获得支持,并且即使是不希望以 root 身份安装的用户仍然可以获得签名检查、依赖项处理和自动更新。我们希望 0install 能让您更轻松地分发您自己的应用程序的二进制文件。

我在 OCaml 2014 上的演讲(视频幻灯片)提供了更多关于 0install 及其转换为 OCaml 的信息。