Scoop 安装 Volta 后手动设置 VOLTA_HOME,pnpm/yarn 会无限递归

新 Windows 机器装好环境后,打开 opencode 过一会儿整机开始卡,任务管理器都打不开

用 btop 和 Process Explorer 看进程树,后台在不停生成 cmd.exe,夹着一串 yarn / pnpm

cmd.exe /C pnpm
  -> ...\volta\bin\pnpm(.cmd/.exe)
    -> volta run pnpm
      -> cmd.exe /C pnpm
        -> ...\volta\bin\pnpm(.cmd/.exe)
          -> volta run pnpm
            -> ...

opencode 只是触发点

opencode 启动时会依次执行几种包管理器的命令来判断自己是通过什么方式安装的,见 packages/opencode/src/installation/index.ts

const checks = [
  { name: "npm", command: () => $`npm list -g --depth=0`.throws(false).quiet().text() },
  { name: "yarn", command: () => $`yarn global list`.throws(false).quiet().text() },
  { name: "pnpm", command: () => $`pnpm list -g --depth=0`.throws(false).quiet().text() },
  { name: "bun", command: () => $`bun pm ls -g`.throws(false).quiet().text() },
  { name: "brew", command: () => $`brew list --formula opencode`.throws(false).quiet().text() },
]

这解释了为什么没主动敲过 yarn 它也会冒出来。在终端里直接运行 pnpmyarn,同样的递归立刻复现,和 opencode 无关

复现条件

在沙盒环境里单独安装一套 Volta,用正常流程 volta install Node 和包管理器,一切正常。没有安装的工具会老老实实提示:

pnpm is not available.

Use `volta install pnpm` to select a default version.

按我装机时的步骤重放:先手动设置 VOLTA_HOME,再用 Scoop 安装 Volta,问题复现

此时 VOLTA_HOME 指向的目录基本是空的。Volta 运行时参考的是一套路径,PATH 实际命中的命令入口是另一套

Volta 的递归保护为什么没起作用

Volta 不是没考虑递归。run/executor.rs 执行工具前会打一个 _VOLTA_TOOL_RECURSION 环境变量:

self.command.env(RECURSION_ENV_VAR, "1");
self.command.env("PATH", path);

run/pnpm.rsrun/yarn.rs 看到这个变量就不再解析 Volta 环境,直接退回系统 PATH:

let platform = match env::var_os(RECURSION_ENV_VAR) {
    Some(_) => None,
    None => Platform::current(session)?,
};

问题出在 Windows 的 shim。shim.rs 生成的 shim 脚本只有一行:

@echo off
volta run %~n0 %*

volta runrun/mod.rs 里执行工具前会先把递归标记清掉:

env::remove_var(RECURSION_ENV_VAR);

于是流程变成:命中 shim,进入 volta run pnpm,递归标记被清掉,执行 pnpm,PATH 又解析回 shim,再来一轮。递归保护每一轮都被重置

Volta 从 PATH 里移除的只有它自己认定的两条路径,见 layout/windows.rs

Ok(vec![home.shim_dir().to_owned(), install.root().to_owned()])

VOLTA_HOME 下的 shim 目录,和 Volta 自己的安装根目录。PATH 里实际命中的 shim 如果不在这两条路径里,清理就没有清到真正的目标

结论

手动设置 VOLTA_HOME 之后,出现了两套对不上的路径:

VOLTA_HOME=C:\Path\To\VoltaData

Volta 认为的 shim 目录:
C:\Path\To\VoltaData\bin

PATH 实际优先命中的:
C:\Path\To\Scoop\apps\volta\current\appdata\bin\pnpm.cmd

递归保护删的是前者,反复命中的是后者

用 Scoop 安装 Volta 就不要再额外设置 VOLTA_HOME

自检

  1. 进程树里有没有大量重复的 cmd.exe
  2. 命令链里是否反复出现 volta run pnpmvolta run yarn
  3. Volta 是否通过 Scoop 安装
  4. 环境变量里是否手动设置过 VOLTA_HOME
  5. VOLTA_HOME 指向的位置,和 PATH 里实际命中的 volta / pnpm / yarn 是不是同一套

评论

评论加载中…

输入关键词开始搜索。

选择Enter 打开Esc 关闭CtrlK 唤起