Skip to content

Commit 0f99bfb

Browse files
committed
fix(env): isolate direct shims from package manager selection
1 parent 40b9cb6 commit 0f99bfb

7 files changed

Lines changed: 78 additions & 2 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const assert = require('node:assert/strict');
2+
const { execFileSync } = require('node:child_process');
3+
const { delimiter } = require('node:path');
4+
5+
// Start each child at the shim even though the parent Node process has injected tool paths.
6+
const env = {
7+
...process.env,
8+
PATH: [process.env.VP_HOME + '/bin', '/usr/bin', '/bin'].join(delimiter),
9+
VP_PATH_INJECTED_TOOLS: '',
10+
};
11+
const [tool, expected] = process.argv.slice(2);
12+
const args = tool === 'vp' ? ['install', '--', '--version'] : ['--version'];
13+
const actual = execFileSync(tool, args, { env, encoding: 'utf8' }).trim();
14+
assert.equal(actual, expected);
15+
console.log(`${tool} uses the expected version`);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "shim-package-manager-version-overrides",
3+
"private": true,
4+
"packageManager": "pnpm@10.18.0"
5+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[[case]]
2+
name = "selection_override_does_not_change_shims"
3+
vp = "global"
4+
skip-platforms = ["windows"]
5+
env = { VP_PACKAGE_MANAGER = "pnpm@10.19.0", npm_config_manage_package_manager_versions = "false" }
6+
steps = [
7+
{ argv = ["node", "check.cjs", "pnpm", "10.18.0"], comment = "The matching shim still uses the project pin" },
8+
{ argv = ["node", "check.cjs", "vp", "10.19.0"], comment = "vp install still uses VP_PACKAGE_MANAGER" },
9+
{ argv = ["node", "check.cjs", "pnpm", "10.18.0"], envs = [["VP_PACKAGE_MANAGER", "invalid"]], comment = "An invalid selection does not affect direct shims" },
10+
]
11+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# selection_override_does_not_change_shims
2+
3+
## `node check.cjs pnpm 10.18.0`
4+
5+
The matching shim still uses the project pin
6+
7+
```
8+
pnpm uses the expected version
9+
```
10+
11+
## `node check.cjs vp 10.19.0`
12+
13+
vp install still uses VP_PACKAGE_MANAGER
14+
15+
```
16+
vp uses the expected version
17+
```
18+
19+
## `VP_PACKAGE_MANAGER=invalid node check.cjs pnpm 10.18.0`
20+
21+
An invalid selection does not affect direct shims
22+
23+
```
24+
pnpm uses the expected version
25+
```

crates/vp_global_cli/src/commands/env/package_manager.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ pub(crate) async fn resolve_current(
1313
resolve_current_for(cwd, None).await
1414
}
1515

16+
/// Selecting a manager for vp commands must not change direct shim versions.
17+
pub(crate) async fn resolve_shim_for(
18+
cwd: &AbsolutePath,
19+
expected: PackageManagerType,
20+
) -> Result<Option<EnvironmentPackageManagerResolution>, Error> {
21+
let session = config::read_session_package_manager().await;
22+
let session = session.as_deref().map(parse_package_manager_spec_with_hash).transpose()?;
23+
let default = configured_default_for(&config::load_config().await?, expected)?;
24+
resolve_environment_package_manager(
25+
cwd,
26+
session.as_ref().map(|(kind, version, hash)| (*kind, version.as_str(), hash.as_deref())),
27+
default.as_ref().map(|(kind, version, hash)| (*kind, version.as_str(), hash.as_deref())),
28+
Some(expected),
29+
)
30+
.await
31+
.map_err(Error::from)
32+
}
33+
1634
pub(crate) async fn resolve_current_for(
1735
cwd: &AbsolutePath,
1836
expected: Option<PackageManagerType>,

crates/vp_global_cli/src/shim/dispatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ async fn resolve_package_manager_tool(
661661
return Ok(None);
662662
};
663663

664-
let resolution = package_manager::resolve_current_for(cwd, Some(expected_type)).await?;
664+
let resolution = package_manager::resolve_shim_for(cwd, expected_type).await?;
665665
let (version, hash) = match resolution {
666666
Some(resolution) => (resolution.version, resolution.hash),
667667
None if expected_type == PackageManagerType::Npm => return Ok(None),

docs/guide/env.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ Package-manager selection uses this priority:
5454
6. The named package manager's global default version
5555
7. The named shim's latest release
5656

57-
A selected manager controls only its named shims. For example, pnpm controls `pnpm` and `pnpx`; invoking `npm` still resolves npm independently. Alias pairs are `npm`/`npx`, `pnpm`/`pnpx`, `yarn`/`yarnpkg`, and `bun`/`bunx`. Without a matching project selection, a named shim uses its configured default version and otherwise uses the latest release without prompting. The resolved version is cached for one hour and an expired cache remains available when the registry cannot be reached. The directly invoked npm shim keeps its Node-bundled fallback, while an explicit `vp env ... npm` family scope uses standalone npm's latest release.
57+
`VP_PACKAGE_MANAGER` selects the manager and version for commands such as `vp install`. Direct package-manager shims ignore this variable and continue to resolve their versions from the session file, project configuration, and family default.
58+
59+
A project selection controls only its named shims. For example, pnpm controls `pnpm` and `pnpx`; invoking `npm` still resolves npm independently. Alias pairs are `npm`/`npx`, `pnpm`/`pnpx`, `yarn`/`yarnpkg`, and `bun`/`bunx`. Without a matching project selection, a named shim uses its configured default version and otherwise uses the latest release without prompting. The resolved version is cached for one hour and an expired cache remains available when the registry cannot be reached. The directly invoked npm shim keeps its Node-bundled fallback, while an explicit `vp env ... npm` family scope uses standalone npm's latest release.
5860

5961
A fresh install uses the split platform layout by default. On Unix, Vite+
6062
stores managed runtimes and related files in `~/.local/share/vite-plus`. It

0 commit comments

Comments
 (0)