RVM/rbenv 为社区添砖加瓦!rbenv for Windows!使用 PowerShell 实现,Windows 用户极致简单的安装管理多版本 Ruby

ccmywish · 2022年05月09日 · 最后由 awking 回复于 2022年05月10日 · 397 次阅读

先上代码,再讲故事。

  1. Github: https://github.com/ccmywish/rbenv-for-windows
  2. Gitee: https://gitee.com/ccmywish/rbenv-for-windows


嗨,大家好,我一直在尽自己的绵薄之力为社区搬砖,这一次我来说说我熟悉的 Windows 上的 Ruby, 以及我带给大家的 rbenv for Windows.


We're still working

我最开始学习 Ruby 的时候,就是在 Windows 上,然而很多人说在 Windows 上使用 Ruby 就是浪费时间。其实到我学的那段时间,这种情形已经不那么明显了。因为 社区在发展,用爱发电的人们在前进。人们并没有因为困难,就直接放弃对 Windows 平台的支持,而是一朝一夕的不断改进。

RubyInstaller 从 2009 年开始开发,到 2017 年左右切换到 RubyInstaller2(下文我们直接称 RubyInstaller 来指代 RubyInstaller2). 后者以 @larskanis 为主要开发人员, 成为了 Windows 上安装 Ruby 的事实标准。该项目 5 年多几乎只有他一人在做实际的维护工作,仅有少数的爱好者在一起帮忙解决问题。我对这位来自德国的工程师,Ruby 爱好者,感到敬佩。 除了琐碎的用户不清楚的内部维护细节之外,最明显的一个改进是:

曾经我们在 Windows 上安装 Rails 的时候,很容易就卡在 gem install sqlite3,然而这个还不是令人无语的网络问题,而是一个编译选项问题。当时的网上的帖子都不管用,对于刚学习 Ruby 的人更是一头雾水。我当时花了好几天才找到解决方案,心里也默默的来了句 "真是浪费时间。。。" . 然而你现在再使用 RubyInstaller,你会发现这一步已经被自动化解决了,即 SQLite3 其实会被 pacman (对,这个就是 Arch Linux 社区中最骄傲的软件 — 包管理工具) 自动安装,这在 macOS 和 Linux 上的同学都没有这样的特殊待遇。

国内现在安装 Ruby 就只有一个问题,那就是网络。不过,在 2021 年 2 月,我们在上海交通大学镜像站的帮助下创建了 https://rubyinstaller.cn/ (代码在Gitee 这),这个迟来的站点也许已经服务了不少新手老手了吧。


rbenv

作为 Ruby 爱好者,你的电脑上一定少不了 rbenvrvm,以供你在不同 Ruby 版本中做各种有趣的语言功能实验。然而 rbenv 的安装也会让人遇到烦人的网络问题,对此,我又创建了 rbenv-cn 来完全的解决它(感谢 uzxmx 对 ruby-build 的补丁,不知道您是否在社区里),而不是部分解决它(有些前辈把解决方案代码放在 Github 上,却不在意用户是否能拉下来 Github 的代码)

由于与 rbenv 的不解之缘,我了解了一部分 rbenv 的工作原理,不过也就是知道个大概,噢,用 Bash 实现的代码,真的有人在它能正常工作的时候费心思去阅读它吗?

在 Linux 上待久了,回到 Windows 上工作,觉得最缺的就是它了,于是我想尝试在 Windows 上使用它。我尝试直接在 MSYS2 中使用 rbenv,经过一番小小的修改,很可惜还是工作不了。然后我突然发现,RubyInstaller 自带的工具 ridk 其实已经实现了 ridk use 来管理多版本。嗯,不错,不过它是以 Ruby 实现的,因此有非常多的缺点,比如,你对 Ruby 版本的切换只能在本次生效。另外,你得自己手动安装很多个版本,对于不了解 RubyInstaller 内部工作的人来说,将会很头疼,比如要不要安装 MSYS2? 需不需要更新?安装在哪个目录?为什么它的官网给了那么多可下载的链接?(这就是为什么我在 https://rubyinstaller.cn/ 中的下载区域只提供了几个链接的原因,其他那些让高级用户自己去存档里找吧)好吧,那个头疼的人就是我。


将 rbenv 带到 Windows 上来

我决定实现一个 rbenv ,然而我还是太自信了,我之前的了解 rbenv 原理其实就是读了几篇已有的文章,再加上写 rbenv-cn 的时候与之打交道了一部分而已,其实你随便问一个问题,我就支支吾吾了,比如 rehash 到底是啥?生成 Bash 脚本?生成 Bash 脚本用来干嘛?不知道。

于是我决定耐下心来,研究清楚 rbenv 在 Windows 上的可能性。我搞清楚了大部分 RubyInstaller 的工作原理(这次是真的绝大部分了,毕竟也没有人写它的文章,无从参考)。这个时候我自己就有一套实现 rbenv 的方案了。而且,我一上来想到的就和 rbenv 的实现不同,是利用 Windows 文件系统的 junction 来处理(然而,最后我还是另外实现了 shims)。至于语言 ,当然是用 Windows 上的原生语言 PowerShell 写, 使用 PowerShell 开发的舒适度远远远超过于令人发指,令人气愤的 Zsh, Bash. 刚才我们提到的 rbenv 网络问题,我记得在看它的 issues 时,有人就提到了用 Bash 实现太混乱,不好修改代码的问题。

尽管 PowerShell 也有非常多脚本语言存在的弊端,不过代码的清晰度,可维护性,都非常地高了,运行速度也非常快,所以你最终会发现我实现的 shims 仅有 8ms ~ 20ms 的延迟,这个已经可以达到 rbenv 的效果了。


使用截图

实现效果如何? 使用 rbenv install head 来直接体验正在开发的 Ruby-dev 吧!


安装

哈哈,国内用户优先考虑,我直接将镜像内置了。也就是说,大家以后几乎不需要再去 https://rubyinstalelr.org 或者 https://rubyinstaller.cn 了。完全用命令行来下来安装管理多 Ruby 吧。

mkdir "C:\Ruby-on-Windows"
git -C "C:\Ruby-on-Windows" clone "https://github.com/ccmywish/rbenv-for-windows" rbenv

# 如果 Github pull 不下来,直接换成 Gitee ,即
git -C "C:\Ruby-on-Windows" clone "https://gitee.com/ccmywish/rbenv-for-windows" rbenv

然后在你的 $profile 里添加

# rbenv for Windows
$env:RBENV_ROOT = "C:\Ruby-on-Windows"
# 这个变量一定要放在 init 之前
$env:RBENV_USE_MIRROR = "CN"  # For Chinese users

& "$env:RBENV_ROOT\rbenv\bin\rbenv.ps1" init


优势

  1. 我们比 rbenv 更快,更稳。因为我们直接使用 RubyInstaller2 经过测试打包好的二进制,意味着所有人使用经过测试的统一版本,也不需要编译,非常节省你的时间。
  2. 基于对 RubyInstaller 的较深入理解,我已经设计好了最佳的下载安装方式,多个 Ruby 复用一套 MSYS2 环境,极其节省空间,最终你会发现,每次安装新 Ruby 只需要 15MB,太舒服了。
  3. 充分使用 RubyInstaller 的功能,使得他们的工作得到重视,让他们的开发成果得到最大化利用。
  4. 下载安装的过程很流畅,至少不会让你再吭呲吭呲先解决网络问题等等
  5. PowerShell 可读性非常高,维护性强,并且我直接改了一部分很有用的 scoop 的代码,整个框架非常清晰。想了解 rbenv 原理,不如直接来看我是怎么实现的。所以,我也鼓励任何对此有兴趣的人来参与维护,开发(我可能将会在未来较长一段时间不从事开发工作)。


缺陷

展示了半天好的,当然也有缺陷。缺陷在 README 中详细说了,我在这里简单说下

  • rbenv local 无力与 prompt工具 比如 starship 交互

没办法,starship 应该直接读了 ruby.exe 文件,所以你如果用 rbenv local 的话,你的 prompt工具 并不会显示正确的版本,虽然你的确通过 rbenv 能够使用正确的版本。所以,这只是个显示问题,这也是个让人头疼的显示问题。

  • rbenv global 的切换问题。由于我们的实现,如果有进程正在使用这个 global version,你没办法切换它。

  • bundle install 的问题,hook 在 Windows 上触发不了,不知道是什么问题。可能是 Bundler 的缺陷,好吧,我不知道,但是我已经怀疑解决它不是易事。

可以看到,缺陷是比较严重的,所以我还是建议主要使用 rbenv globalrbenv shell 工作。很多人会问, rbenv local 是一个核心功能啊,对此,我想说,我目前能想到的最好办法就是这样。你完全可以在有 .ruby-version 的目录直接 rbenv global 切换到对应的版本上去。正如我上文所说,我可能未来较长一段时间不再参与开发工作,尽管我本人作为用户当然会不断改进它,只不过可能不那么及时。我希望有友善的人,热情的人,聪明的人能够帮助此项目做的更好,解决遇到的这些问题。


工作原理

具体的工作原理,大部分,核心的放在了 README 中,剩下的放在代码注释里。 有兴趣的人可以去查看(不过我再次反问我自己,如果能够正常工作,谁会有兴趣看?)


手动点赞,非专业开发人员,自学 ruby 和 rails,主要是辅助日常工作。如果想把完成的开发成果分享给非局域网的人,在他人电脑上安装 ruby 和 rails 环境安装就是一个非常费劲的问题(什么 docker、linux 根本不现实,也不想去注册域名、空间什么的,太费事),现场一蹲一个小时也不一定搞定,远程指导安装更是不可能,所以做出来的东西只能自嗨。希望这个能有用,解决在 windows 上的快速安装问题,感谢作者!

其实吧,没太大必要折腾 win,因为项目中很多 gem 在 win 下面有问题,win 下面最好的开发环境还是 wsl1,楼主辛苦了,但是意义真的不大

y9info 回复

用 docker 可以把所有系统依赖包括 ruby, postgres, redis 都写成配置文件(docker compose),难度大大低于单独处理每个依赖,最难的地方就在于第一步:开始学习。

我曾经通过微信指导让一个朋友在 windows 主机上通过 docker compose 运行单独给他写的应用。

amonlei 回复

哈哈,感谢,just for fun

支持支持🔥

需要 登录 后方可回复, 如果你还没有账号请 注册新账号