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

ccmywish · 2022年05月09日 · 最后由 ccmywish 回复于 2022年05月24日 · 932 次阅读

先上代码,再讲故事。

  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 能够使用正确的版本。所以,这只是个显示问题,但是的确不太好解决。

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

缺陷是比较严重的,所以我还是建议主要使用 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

支持支持🔥

ruby 能够在 win 上工作,终于 rb 可以和 python 一样也出 Excel 教程了!!!哈哈哈,与之一战

amonlei 回复

有意义。要不然 Ruby 的领域面就一直很狭隘,处在服务器侧的 web 领域(这只是个一个小小的地盘)。

拒绝 windows 等于拒绝了 —— GUI 程序、办公自动化、一大批新手玩家、外挂领域、等于拒绝市场上最大占比的操作系统。

支持。个人常在 Windows 上写点小工具,然后用 ocra 或者 neri 打包成 exe 分发。

wsl 只在写 Rails 的时候使用(主要是一些 C 扩展不支持 Windows)。

安装完之后启动遇到了错误,机器上有一个 Ruby 3.1。

rbenv: Only one system Ruby is support, but you've installed 3
Seems you have just installed rbenv, auto install MSYS2 for you
MSYS2 is must-have if you want to install gems with C extensions
所在位置 C:\Ruby-on-Windows\rbenv\lib\commands.ps1:13 字符: 9
+         | Where-Object { $_.name -match 'rbenv-.*?\.ps1$' }
+         ~
不允许使用空管道元素。
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : EmptyPipeElement

所在位置 C:\Ruby-on-Windows\rbenv\lib\version.ps1:84 字符: 17
+                 | Where-Object {
+                 ~
不允许使用空管道元素。
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : EmptyPipeElement

get_commands : 无法将“get_commands”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径
,请确保路径正确,然后再试一次。
所在位置 C:\Ruby-on-Windows\rbenv\bin\rbenv.ps1:126 字符: 23
+ $available_commands = get_commands
+                       ~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (get_commands:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

rbenv: 'install' isn't a rbenv command. See 'rbenv help'.
加载个人及系统配置文件用了 553 毫秒。

PS C:\Ruby-on-Windows> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      25120  1000

如果有人跟我一样卸载 Ruby 时只是直接删除 C:\Ruby26-x64 文件夹和变量而不是运行卸载程序的话,注册表还会残留 RubyInstaller 的信息,导致 rbenv for Windows 读取出来一个不存在的 system,安装 gem 的时候会出现

Set-Content: C:\Ruby-on-Windows\rbenv\libexec\rbenv-rehash.ps1:30
Line |
  30 |          Set-Content "$where\$name.ps1" $REHASH_TEMPLATE
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Could not find a part of the path 'C:\Ruby26-x64\bin\kramdown.ps1'.

解决方法是删除注册表:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall RubyInstaller 的残留项。

koell 回复

已合并你的 fix,感谢 👍

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