[Awosome Software] asdf: 统一管理多版本的软件工具/编程语言/运行环境

asdf: 统一管理多版本的软件工具/编程语言/运行环境

asdf 是软件工具/编程语言/运行环境版本管理器。比 nvm(Node.js)、rvm(Ruby)等版本管理器功能更强大,支持范围更广,完全可以替换它们。

本文介绍在 macOS 上安装 asdf,并通过 asdf Node.js 插件安装 Node.js 多版本。

推荐理由

CloudoLife 推荐使用 asdf 统一管理不同工具/编程语言/运行环境多版本。推荐理由:

  • 简单性,只需要安装 asdf 和对应工具/编程语言/运行环境的插件,无需为不同的工具/编程语言/运行环境安装其他多版本管理工具。

  • 一致性,使用相同的 asdf 基本命令和配置,可以统一管理不同工具/编程语言/运行环境多版本,按您所需,灵活熟练切换不同版本。

  • 多样性,官方和社区插件已经支持多达数百种工具/编程语言/运行环境,几乎涵盖到所有工具/编程语言/运行环境。

  • 及时性,插件支持的工具/编程语言/运行环境与上游保持同步,版本更新非常及时,非常容易尝试新版本。

项目简介

asdf 是一个工具/运行环境(如 Dart, Elixir, Flutter, Golang (Go), Java, Node.js, Python, Ruby 等)版本管理器。所有的工具版本定义都包含在一个文件(.tool-versions)中,你可以将配置文件 .tool-versions 放在项目的 Git 存储库中以便于和团队其他成员共享,从而确保每个人都使用完全相同的工具版本。

传统工作方式需要多个命令行版本管理器(如 nvm, rvm 等等),而且每个管理器都有其不同的 API、配置文件和实现方式(比如,$PATH 操作、shim、环境变量等等)。asdf 提供单个交互方式和配置文件来简化开发工作流程,并可通过简单的插件接口扩展到所有工具和运行环境

它是如何工作的

一旦 asdf 核心在 Shell 配置中设置好之后,你可以安装插件来管理特定的工具。当通过插件安装工具时,安装的可执行程序会为每个可执行程序创建 shimopen in new window。当你尝试运行其中一个可执行程序时,将运行 shim,从而允许 asdf 识别 .tool-versions 文件中设置的工具版本并执行该版本。

为什么使用 asdf?

asdf 确保团队可以使用完全相同的工具版本,通过插件系统支持很多工具,以及作为 Shell 配置中包含的单个 Shell 脚本的 简单性和熟悉性。

插件列表

除 Dart, Flutter, Golang, Java, Node.js, Python, Ruby, Rust 等常见插件外,asdf 官方和社区已经为不同的软件工具/编程语言/运行环境提供 100+ 插件。而且新的插件还在陆续开发中…

查看 Plugin List | asdf-vm/asdf-plugins: Central plugin repository for asdf - https://github.com/asdf-vm/asdf-plugins#plugin-list 了解 asdf 支持的插件。

快速入门

asdf 安装过程包括:

  • 安装依赖

  • 下载 asdf 核心

  • 安装 asdf

  • 为每一个你想要管理的工具/运行环境安装插件

  • 安装工具/运行环境的一个版本

  • 通过 .tool-versions 配置文件设置全局和项目版本

接下来以 macOS 操作系统、Homebrew 包管理器、Oh My Zsh Shell 命令行配置工具为例,介绍:

  • 如何安装 asdf 以及所需要的依赖

  • 如何安装 Node.js 最新运行环境

  • 如何安装 Node.js 其他版本运行环境

Hombrew 安装 asdf 以及所需要的依赖

Homebrew 是一款 macOS 操作系统平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能。简单的一条指令 brew <subcommand>,就可以实现包管理,而不用你关心各种依赖和文件路径的情况,十分方便快捷。

访问The Missing Package Manager for macOS (or Linux) — Homebrew - https://brew.sh/了解更多信息。

得益于功能强大的 Homebrew 包管理器,Homebrew 安装 asdf 时将会自动安装所需要的依赖。

1
brew install asdf

包管理器 和 Oh My Zsh Shell 命令行配置

Oh My Zsh 是基于 zsh 命令行的一个扩展工具集,提供了丰富的扩展功能。它是一种全新的工作方式。它基于 zsh 命令行,提供了主题配置,插件机制,已经内置的便捷操作。给我们一种全新的方式使用命令行。

访问Oh My Zsh - a delightful & open source framework for Zsh - https://ohmyz.sh/了解更多信息。

使用以下命令将 asdf.sh 加入到 ~/.zshrc 文件中:

1
echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc

或者 使用 ZSH 框架插件,比如 asdf for oh-my-zsh - https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/asdf 将会使脚本生效并安装补全功能。

补全功能可以被 ZSH 框架 asdf 或者 按照 Homebrew 的指引 - https://docs.brew.sh/Shell-Completion#configuring-completions-in-zsh 完成配置。如果你正在使用 ZSH 框架,有关的 asdf 插件或许需要更新才能通过 fpath 正确地使用最新的 ZSH 补全功能。Oh-My-ZSH asdf 插件还在更新中,请查看 ohmyzsh/ohmyzsh#8837 - https://asdf-vm.com/zh-hans/guide/getting-started.html#_3-%E5%AE%89%E8%A3%85-asdf:~:text=%E4%B8%AD%EF%BC%8C%E8%AF%B7%E6%9F%A5%E7%9C%8B-,ohmyzsh/ohmyzsh%238837,open%20in%20new%20window,-%E4%BA%86%E8%A7%A3%E6%9B%B4%E5%A4%9A%E3%80%82了解更多。

asdf 脚本需要在设置好的 $PATH 之后和已经生效的框架(比如 oh-my-zsh 等等)之后的位置生效。

通常打开一个新的终端标签页来重启你的 shellPATH 更改即时生效。

或者在当前窗口运行 source ~/.zshrcPATH 更改即时生效。

1
$ source ~/.zshrc

核心安装完成!

这样就完成了 asdf 核心的安装 🎉

asdf 仅在你安装插件、工具和管理它们的版本时才开始真正发挥作用。请继续阅读下面的指南来了解这些是如何做到的。

安装插件

出于演示目的,我们将通过 asdf-nodejs 插件来安装和设置 Node.js。

插件依赖

每个插件都有依赖,所以我们需要确认应该列举了这些依赖的插件源码。对于 asdf-nodejs 来说,它们是:

1
brew install gpg gawk

我们应该提前安装这些依赖,因为有些插件有 post-install 钩子。

安装插件

1
asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git

访问asdf-vm/asdf-nodejs: Node.js plugin for asdf version manager - https://github.com/asdf-vm/asdf-nodejs了解更多信息。

安装指定版本

现在我们已经有了 Node.js 插件,所以我们可以开始安装某个版本了。

我们通过 asdf list all nodejs 可以看到所有可用的版本或者通过 asdf list all nodejs 14 查看版本子集。

我们将只安装最新可用的 latest 版本:

1
asdf install nodejs latest

注意
asdf 强制使用准确的版本。latest 是一个通过 asdf 来解析到执行时刻的实际版本号的辅助工具。

可以安装可用的 15.10.0 版本:

1
asdf install nodejs 15.10.0

设置默认版本

asdf 在从当前工作目录一直往上到 $HOME 目录的所有 .tool-versions 文件中进行工具的版本查找。查找在执行 asdf 管理的工具时实时发生。

警告
如果没有为工具找到指定的版本,则会出现错误。asdf current 将显示当前目录中的工具和版本解析结果,或者不存在,以便你可以观察哪些工具将无法执行。

全局

全局默认配置在 ~/.tool-versions 文件中进行管理。使用以下命令可以设置一个全局版本:

1
asdf global nodejs latest

~/.tool-versions 文件内容将会如下所示:

1
2
$ cat ~/.tool-versions
nodejs 16.5.0

某些操作系统已经有一些由系统而非 asdf 安装和管理的工具了,python 就是一个常见的例子。你需要告诉 asdf 将管理权还给系统。版本参考部分 将会引导你。

本地

本地版本被定义在 ./.tool-versions 文件中(当前工作目录)。通常,这将会是一个项目的 Git 存储库。当在你想要的目录执行:

如果当前工作目录没有 .tool-versions,您可以手动创建:

1
$ touch .tool-versions
1
asdf local nodejs latest

./.tool-versions 文件内容将会如下所示:

1
2
$ cat ./.tool-versions
nodejs 16.5.0

使用现有工具版本文件

asdf 支持从其他版本管理器的现有版本文件中迁移过来,比如 rbenv.ruby-version 文件。这在每个插件中都原生支持。

asdf-nodejs 支持从 .nvmrc.node-version 文件进行迁移。为了启用此功能,请在 asdf 配置文件 $HOME/.asdfrc 中加入以下内容:

1
legacy_version_file = yes

请查看 配置 - https://asdf-vm.com/zh-hans/manage/configuration.html 参考页面可以了解更多配置选项。

完成指南!

恭喜你完成了 asdf 的快速上手 🎉 你现在可以管理你的项目的 nodejs 版本了。对于项目中的其他工具/运行环境可以执行类似步骤即可!

更多命令

asdf 还有更多命令需要熟悉,你可以通过运行 asdf --help 或者 asdf 来查看它们。命令主要分为三类:

  • asdf 核心

  • 插件

  • (工具的)版本

asdf 中所有可用命令的列表。这个列表就是 asdf help 命令的打印内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$ asdf
MANAGE PLUGINS
asdf plugin add <name> [<git-url>] 从插件仓库添加插件或者,添加一个 Git repo 作为插件
asdf plugin list [--urls] [--refs] 列出已安装的插件。可选择显示 git url 和 git-ref
asdf plugin list all 列出所有在 asdf-plugins 上注册的 List 插件带有 URL 的存储库
asdf plugin remove <name> 删除插件和软件包版本
asdf plugin update <name> [<git-ref>] 更新插件到最新提交默认分支或特定的 git-ref
asdf plugin update --all 更新所有插件到最新提交默认分支


MANAGE PACKAGES
asdf install 安装所有在 .tool-versions 文件中列出的软件包版本
asdf install <name> 安装一个在 .tool-versions 文件中列出的特定软件包版本
asdf install <name> <version> 安装特定版本的包
asdf install <name> latest[:<version>] 安装最新的稳定版本包,或可选版本,安装最新的稳定版本,或以给定的字符串开头
asdf uninstall <name> <version> 删除特定版本的包
asdf current 显示当前版本集或正在用于所有包
asdf current <name> 显示当前版本集或正在用于包装
asdf where <name> [<version>] 示已安装的安装路径或当前版本
asdf which <command> 显示可执行文件的路径
asdf local <name> <version> 设置包本地版本
asdf local <name> latest[:<version>] 将包本地版本设置为提供的最新版本
asdf global <name> <version> 设置包全局版本
asdf global <name> latest[:<version>] 将包全局版本设置为提供的最新版本
asdf shell <name> <version> 将包版本设置为当前 shell 中的 `ASDF_${LANG}_VERSION`
asdf latest <name> [<version>] 显示包的最新稳定版本
asdf latest --all 显示所有最新的稳定版本软件包以及是否已安装
asdf list <name> [version] 列出软件包的已安装版本和可选择过滤版本
asdf list all <name> [<version>] 列出包的所有版本和可选择过滤返回的版本
asdf help <name> [<version>] 插件和工具的输出文档


UTILS
asdf exec <command> [args...] 为当前版本执行命令 shim
asdf env <command> [util] 在用于命令 shim 执行的环境
asdf info 打印操作系统、Shell 和 ASDF 调试信息
asdf reshim <name> <version> 为特定包的版本重新创建 shims
asdf shim-versions <command> 列出插件和版本提供命令
provide a command
asdf update 更新到最新的稳定版本
asdf update --head 将 asdf 更新到 master 分支上的最新版本

RESOURCES
GitHub: https://github.com/asdf-vm/asdf
Docs: https://asdf-vm.com

常见问题 FAQs

brew upgrade asdf 升级新版本后 No such file or directory 没有这样的文件或目录

1
2
3
4
5
6
7
$ brew upgrade asdf

$ node -v
~/.asdf/shims/node: line 8: /usr/local/Cellar/asdf/0.9.0/libexec/bin/asdf: No such file or directory

$ cat ~/.asdf/shims/rails
exec /usr/local/Cellar/asdf/0.9.0/libexec/bin/asdf exec "node" "$@"

先将 ~/.asdf/shims 备份,然后运行 asdf reshim 重新生成最新的 ~/.asdf/shims

1
2
3
4
$ mv ~/.asdf/shims ~./asdf/shims.bak

$ asdf reshim
# $ asdf reshim node

command not found: pnpm 命令未找到:pnpm

1
2
3
4
$ npm i pnpm

$ pnpm -v
zsh: command not found: pnpm

原因可能是安装 pnpm 时没有使用 -g 选项安装。

记得使用 -g 选项将 pnpm 命令安装到 $HOME/.asdf/shims 目录

1
2
3
4
$ npm install -g pnpm

$ pnpm -v
7.3.0

参考链接

[1] Home | asdf - https://asdf-vm.com/

[2] The Missing Package Manager for macOS (or Linux) — Homebrew - https://brew.sh/

[3] Oh My Zsh - a delightful & open source framework for Zsh - https://ohmyz.sh/

[4] asdf-vm/asdf-nodejs: Node.js plugin for asdf version manager - https://github.com/asdf-vm/asdf-nodejs

[5] Node.js - https://nodejs.org/en/