Skip to content

Commit

Permalink
fix shell inference in powershell when installed through scoop (#1164)
Browse files Browse the repository at this point in the history
* be more verbose on shell inference issues in Windows

* add changeset

* fix shell inference with scoop

* change changeset text

* test scoop shims

* don't concat paths

* skip instead of not emitting tests

* setup scoop in windows

* use test.skip
  • Loading branch information
Schniz committed Jun 13, 2024
1 parent 04a81f7 commit 318f86d
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/warm-garlics-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fnm": patch
---

windows: fix shell inference in powershell when using scoop's shims
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ jobs:
with:
name: fnm-windows
path: target/release
- uses: MinoruSekine/setup-scoop@v4
- uses: pnpm/action-setup@v2.4.0
with:
run_install: false
Expand Down
11 changes: 9 additions & 2 deletions e2e/shellcode/shells/cmdEnv.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ScriptLine, define } from "./types.js"

type EnvConfig = {
executableName: string
useOnCd: boolean
logLevel: string
corepackEnabled: boolean
Expand All @@ -9,9 +10,15 @@ type EnvConfig = {
export type HasEnv = { env(cfg: Partial<EnvConfig>): ScriptLine }

function stringify(envConfig: Partial<EnvConfig> = {}) {
const { useOnCd, logLevel, corepackEnabled, resolveEngines } = envConfig
const {
useOnCd,
logLevel,
corepackEnabled,
resolveEngines,
executableName = "fnm",
} = envConfig
return [
`fnm env`,
`${executableName} env`,
useOnCd && "--use-on-cd",
logLevel && `--log-level=${logLevel}`,
corepackEnabled && "--corepack-enabled",
Expand Down
33 changes: 33 additions & 0 deletions e2e/windows-scoop.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { script } from "./shellcode/script.js"
import { Bash, Fish, PowerShell, WinCmd, Zsh } from "./shellcode/shells.js"
import testNodeVersion from "./shellcode/test-node-version.js"
import describe from "./describe.js"
import os from "node:os"
import { execa } from "execa"

if (os.platform() !== "win32") {
test.skip("scoop shims only work on Windows", () => {})
} else {
beforeAll(async () => {
// Create a scoop shim for tests
await execa(`scoop`, [
"shim",
"add",
"fnm_release",
"target/release/fnm.exe",
])
})

for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) {
describe(shell, () => {
test(`scoop shims infer the shell`, async () => {
await script(shell)
.then(shell.env({ executableName: "fnm_release" }))
.then(shell.call("fnm_release", ["install", "v20.14.0"]))
.then(shell.call("fnm_release", ["use", "v20.14.0"]))
.then(testNodeVersion(shell, "v20.14.0"))
.execute(shell)
})
})
}
}
33 changes: 29 additions & 4 deletions src/shell/infer/windows.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
#![cfg(not(unix))]

use crate::shell::Shell;
use sysinfo::System;
use log::{debug, warn};
use sysinfo::{ProcessRefreshKind, System, UpdateKind};

pub fn infer_shell() -> Option<Box<dyn Shell>> {
let mut system = System::new();
let mut current_pid = sysinfo::get_current_pid().ok();

system
.refresh_processes_specifics(ProcessRefreshKind::new().with_exe(UpdateKind::OnlyIfNotSet));

while let Some(pid) = current_pid {
system.refresh_process(pid);
if let Some(process) = system.process(pid) {
current_pid = process.parent();
debug!("pid {pid} parent process is {current_pid:?}");
let process_name = process
.exe()
.and_then(|x| x.file_stem())
.and_then(|x| x.to_str())
.and_then(|x| {
tap_none(x.file_stem(), || {
warn!("failed to get file stem from {:?}", x);
})
})
.and_then(|x| {
tap_none(x.to_str(), || {
warn!("failed to convert file stem to string: {:?}", x);
})
})
.map(str::to_lowercase);
if let Some(shell) = process_name
.as_ref()
Expand All @@ -24,9 +36,22 @@ pub fn infer_shell() -> Option<Box<dyn Shell>> {
return Some(shell);
}
} else {
warn!("process not found for {pid}");
current_pid = None;
}
}

None
}

fn tap_none<T, F>(opt: Option<T>, f: F) -> Option<T>
where
F: FnOnce(),
{
match &opt {
Some(_) => (),
None => f(),
};

opt
}

0 comments on commit 318f86d

Please sign in to comment.