问题

今天在 WSL 下安装了一个命令,该命令中某些子命令需要唤起浏览器进行操作,在这一步报错: shell exec: xdg-open: executable file not found in $PATH

具体地说,是我安装了 NAPPTIVE 的命令行工具,playground,在执行 playground login 时报的以上错误。

分析

有办法绕过这个问题吗?

我想,要么直接在 Windows 下安装 playground得了,不使用 WSL。但是你们猜猜我为什么会在 WSL 中安装这个命令呢?答案正是这个命令行工具不支持 Windows,我才使用 WSL 的。 shell No prebuilt binary for msys_nt-10.0-22543-amd64 Failed to install Playground CLI For support, go to https://docs.napptive.com/

image.png

为什么执行这个命令需要唤起浏览器

其实很多命令行工具的登录操作,都会唤起浏览器进行操作,然后返回到命令行。其实,多数这种命令行工具或者其他客户端,在登录时,都会采用 OAuth 2.0 的 Device Flow 流程,可以说是一个事实标准了。关于这个 Device Flow 的详细介绍,以及如何给自己的命令行工具加上 OAuth 2.0 的 Device Flow 流程的具体教程,详见:《https://zhuanlan.zhihu.com/p/488194876》。

为什么报 xdg-open 文件不存在

我在 k8ss 1.8.4 这个版本中直接使用了 open 来打开浏览器:
https://github.com/jeff-tian/k8ss/blob/master/src/login/loginByKeycloak.ts
image.png

如上图所示,使用了 open这个命令,只在 mac osx 中测试过可以自动打开浏览器。为了应对不同的系统可以不支持 open 集合,所以在命令行输出了一个 url 用来让用户手动打开浏览器并浏览至该页面。

而现在 playground 这个工具报 xdg-open文件不存在,显然是它或者它的依赖项使用了 xdg-open来打开浏览器,应该是只支持 linux 系统。这个命令行工具要是像 k8ss一样,将要打开的 URL 在命令行中输出该多好,这样我就不用修复这个报错了,直接手动打开 Chrome,并输入 url,就绕过了问题。但是,看不到目标 url,于是只能硬着头皮从根本上解决这个问题了。

解决步骤

安装 xdg-open

这一步很顺利,执行 sudo apt-get install -y xdg-utils就搞定了。

测试 xdg-open

输入 xdg-open https://www.baidu.com,果然事情没有那么顺利,出现了如下报错: shell [email protected]:/mnt/d/repos/uni-orders# xdg-open https://www.baidu.com /usr/bin/xdg-open: 778: /usr/bin/xdg-open: www-browser: not found /usr/bin/xdg-open: 778: /usr/bin/xdg-open: links2: not found /usr/bin/xdg-open: 778: /usr/bin/xdg-open: elinks: not found /usr/bin/xdg-open: 778: /usr/bin/xdg-open: links: not found /usr/bin/xdg-open: 778: /usr/bin/xdg-open: lynx: not found /usr/bin/xdg-open: 778: /usr/bin/xdg-open: w3m: not found xdg-open: no method available for opening https://www.baidu.com

分析

再次执行 playground login,仍然出现以上错误,说明, xdg-oepn 是安装上了,但是这个 xdg-open仍然是一个壳,它需要使用一个浏览器来打开链接,但是尝试了好几种,都没有找到相应的执行文件,于是失败。

网上搜索了一下,是要设置一个具体的可执行文件给到 BROWSER 这个环境变量。我希望 WSL 的 xdg-open能够直接打开 Windows 系统中的 Google Chrome 浏览器。

定位 Google Chrome 可执行文件

按 Windows 键,输入 Chrome,右键“打开文件位置”:

image.png

得到一个快捷方式所在的文件夹,这不是我最终想要的:
image.png

于是,再次在这个快捷方式上右键并选择“打开文件位置”:
image.png

找到了原来我的 Google Chrome 安装在“C:Program Files (x86)GoogleChromeApplication”这个文件夹下:

image.png

在 WSL 中建立一个快捷方式

其实,找到了 Google Chrome 所在的文件夹,只需要将 BROWSER 环境变量设置为 Google Chrome 的完整路径即可。但是做为一个程序员,职业病让我不直接这样做,而是引入一个中间层,让这个路径和环境变量“解耦”(为什么要带来这个额外的复杂性呢?其实没有必要,但是当时就是这么做了)。即先建立一个快捷方式,让环境变量指向这个快捷方式,而不是最终的可执行文件本身。这样以后就可以扩展了,比如切换浏览器,不需要再次修改环境变量,只需要修改这个快捷方式的指向就好了(但愿我以后真的想修改浏览器时,还记得我做了这个软链接!)。

在 WSL 中建立这个快捷方式,使用了软链接,这个软链接的名字不妨叫 browser_in_win,建立方式如下,注意将 Windows 的目录更改为了 WSL 对应的目录:

shell sudo ln -sf /mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe /usr/bin/browser_in_win

将 BROWSER 环境变量设置为 browser_in_win

shell export BROWSER=/usr/bin/browser_in_win

再次测试 xdg-open

shell xdg-open https://www.baidu.com

这一次,成功从 WSL 命令行打开了浏览器!

测试 playground login

从 WSL 中执行 playground login,完美打开了浏览器并登录成功了!
image.png

为了验证真的登录成功,使用它创建了一个应用:

shell [email protected]:/mnt/d/repos/uni-orders# playground apps create uni-orders.yaml STATUS INFO SUCCESS application [uni-orders] deployed

CREATED core.oam.dev/v1beta1, Kind=Application uni-orders created

在看到自己账号下成功创建了应用,终于放心问题是真的解决了!

总结

在确定没有办法绕过问题之后,最终在 WSL 中通过设置 BROWSER 环境变量,指向 Windows 中安装的浏览器可执行文件,解决了从 WSL 命令行中直接打开 Windows 浏览器的问题。关键在于定位到 Windows 下的 Google Chrome 可执行文件,并且转换成 WSL 的文件路径。