xpkg

一个简单的跨平台“包”管理器。

概述

我倾向于以类似的方式设置我的环境的许多方面,无论我是在 Linux、macOS 还是其他类 Unix 系统上。

作为其中的一部分,我有一大堆脚本、配置文件等等,我需要以某种方式下载、安装,然后经常将它们符号链接到不同的位置。

以前我通过克隆一个 git 仓库,并在其中放置一堆脚本,然后将它们连接到 .bashrc 之类的文件中,来使一切正常工作。

这不是一个非常可扩展的解决方案,我想要更好的东西。

具体来说,我希望能够

简而言之,这就是 XPkg 所做的。

安装

免责声明:XPkg 纯粹是为了我自己的使用而开发的。它正处于积极(尽管是零星的)开发中,并且可能存在错误。它会修改你的 .bashrc.zshrc 等脚本,虽然它会备份它们,但它可能会破坏某些东西。如果它做了错误的事情,请告诉我,但我不能保证支持你,并且我绝对不会对它造成的任何损害负责。 使用 XPkg 的风险自负!

依赖

在启动一台新机器时,Xpkg 是我安装的第一批东西之一 - 然后我使用它来安装许多其他东西。

但是,它确实首先需要一两件事

引导

运行 curl https://raw.githubusercontent.com/elegantchaos/XPkg/master/.bin/bootstrap | bash 应该可以让你启动并运行。

这样做的是

在安装过程中,xpkg 的别名会安装到 ~/.local/bin 中,并且为 bashzshfish 安装了一些启动钩子,这些钩子将此位置包含在 $PATH 中。

你需要启动一个新的 shell / 打开一个新的终端窗口,才能使此路径更改生效。

用法

要从 Github 安装一个包:xpkg install <user/repo>

这会将包克隆到一个隐藏的位置,然后运行其安装程序。

如果它不在 github 上,你也可以指定完整的仓库 URL。

要删除一个包,xpkg remove <package>

要列出已安装的包,xpkg list

要导航到包目录(使用 pushd),输入 xg <package>

对于其他命令,请参阅 xpkg help

编写包

在其最基本的形式中,包只是 git 仓库,其中包含有效负载(你想安装或连接到你的系统的任何文件),以及安装程序(告诉 XPkg 如何安装/卸载有效负载)。

XPkg 被设计为跨平台的(这就是“X”的含义),并且是用 Swift 编写的。它应该在任何具有可用的 Swift 编译器和标准库的平台上工作。由于 Swift 是 XPkg 本身的要求,所以我决定也将其作为安装程序的要求。1

事实上,XPkg 包也是 Swift Package Manager (SPM) 包。

当你使用 XPkg 安装一个包时,它会克隆相应的仓库,然后使用 SPM 构建并运行安装程序(一个具有特殊名称的产品,目前是 <your-package-name>-xpkg-hooks),并将一组已知的参数和环境变量传递给你的包。

这个设计选择有两个好的方面

当然,在安装一个包时,你通常会想做一些事情,例如创建指向 /usr/local/bin 之类位置的符号链接,运行其他脚本等等。

为了避免每个安装程序每次都必须编写该代码,我们只是将它们放在另一个 Swift 包(当前称为 XpkgPackage)中,所有安装程序都可以导入和使用它。

示例

一个简单的包可能包含以下文件

my-package/
  Package.swift
  Sources/xpkg-my-package/
    main.swift
  Payload/
    my-command.sh

Package.swift 文件可能如下所示

// swift-tools-version:5.0

import PackageDescription

let package = Package(
    name: "my-package",
    platforms: [
        .macOS(.v10_13)
    ],
    products: [
        .executable(name: "my-package-xpkg-hooks", targets: ["my-package-xpkg-hooks"]),
    ],
    dependencies: [
        .package(url: "https://github.com/elegantchaos/XPkgPackage", from:"1.0.5"),
    ],
    targets: [
        .target(
            name: "my-package-xpkg-hooks",
            dependencies: ["XPkgPackage"]),
    ]
)

main.swift 文件可能如下所示

import XPkgPackage

let links = [
    ["Payload/my-command.sh"]
]

let arguments = CommandLine.arguments
let package = InstalledPackage(fromCommandLine: arguments)
try! package.performAction(fromCommandLine: CommandLine.arguments, links: links, commands: [])

这使用 XPkgPackage 提供的功能将链接 my-command 安装到 /usr/local/bin 中,该链接指向磁盘上包的缓存版本中的文件 Payload/my-command.sh

关于术语的说明

XPkg 已经经历了一次重大的重新设计,并且术语还没有赶上来。

以前我们有包和清单。现在我们有了包和安装程序。

我计划重命名很多东西以反映新的现实

连接到 Shell 启动

许多包需要做的一件事是连接到 shell 启动过程(无论是 .bashrc、.zshrc 或其他),以便设置环境变量、别名等等。

与其让每个包都修改这些初始化文件,这可能会变得混乱,我决定让一个包将自己安装到这个启动过程中,并让这个包提供一种灵活的方式来安装其他钩子。

这个包叫做 shell-hooks (https://github.com/elegantchaos/shell-hooks),并且在你安装 XPkg 本身时默认安装。

它将自身连接到 Bash、Zsh 和 Fish 的启动过程中。 在启动时,它会扫描 ~/.config/shell-hooks/ 并运行它在那里找到的任何文件。 实际上,它使用子目录和模式匹配来精确地选择要运行的文件,具体取决于你所在的平台,以及这是交互式会话还是非交互式会话。

标准安装程序支持包 XpkgPackage 了解 shell-hooks,并提供支持将符号链接安装到其目录中。 这使得 Xpkg 包可以非常简单地将自身插入到 shell 启动过程中。

现有包

我正在慢慢地将我的一堆旧脚本和链接转换为包,并且我已经制作了一堆包,支持诸如

其中许多都在私有仓库中,因为它们基本上是 *我* 的设置,但你会在 github 上找到一些公开的。 我会尝试随着时间的推移开放更多,我只需要确保它们不会意外地包含私有令牌或其他非通用消费的东西。

它是如何工作的

XPkg 基本上在隐藏目录中创建一个本地 swift 包,并在其中维护一个 Package.swift 文件。

当你安装一个包时,XPkg 会将其添加到 Package.swift 文件中,并使用 swift update 来解析它并获取依赖项。

然后,它会发现由于此操作而添加的任何包,并尝试为它们构建并运行安装程序。

包删除以类似的方式工作,但方向相反。

还有更多内容,但这是基本思想。

使用 SPM 来完成所有依赖项解析和获取似乎是一种以少量工作获得大量功能的好方法!

我认为这个想法可能非常可靠,如果不是因为使用 SPM 作为提供安装程序的一种方式而暴露出来,那将纯粹是一个实现细节。 理论上,可以提供其他安装程序机制来代替/或者提供。

在开发过程中,我发现偶尔 XPkg 本身中的错误可能会导致自动生成的 Package.swift 损坏并需要手动编辑。 对于其他人会使用的东西来说,这显然不是理想的情况,但是当 XPkg 本身稳定下来时,应该可以防止这种损坏发生。

未来计划

除了支持安装之外,XPkg 最初还旨在帮助解决其他一些事情

所有这些都旨在帮助支持一种同时在多台机器上工作/经常在机器之间移动的存在。

其中一些功能正在开发中,或者可能会在以后添加。

XPkg 以前还将自己安装到 /usr/local/share 中,并将链接等安装到 /usr/local/bin 中。 在某个时候,我改为使用 ~/.local/。 在某个时候,我打算使其支持两者,具体取决于配置标志。 在某个时候。 也许...

脚注

  1. XPkg 的第一个迭代没有安装程序,而是有清单。 该清单是一个隐藏的 json 文件,名为 .xpkg.json,它位于包的根目录,并描述了如何安装/卸载该包。 这很轻量级,但有点不灵活,因为这取决于 XPkg 来解释清单。 你可以通过调用 shell 脚本来运行代码,但你不能指定对其他包作为依赖项的要求。