refactor(core): replace bash tool with shell tool
This commit is contained in:
parent
595c6bd4a7
commit
5ae93092aa
37 changed files with 2260 additions and 901 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import path from "path"
|
||||
import { Shell } from "@opencode-ai/core/shell"
|
||||
import { ShellSelect } from "@opencode-ai/core/shell/select"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { which } from "@opencode-ai/core/util/which"
|
||||
|
||||
|
|
@ -8,56 +8,56 @@ const withShell = async (shell: string | undefined, fn: () => void | Promise<voi
|
|||
const prev = process.env.SHELL
|
||||
if (shell === undefined) delete process.env.SHELL
|
||||
else process.env.SHELL = shell
|
||||
Shell.acceptable.reset()
|
||||
Shell.preferred.reset()
|
||||
ShellSelect.acceptable.reset()
|
||||
ShellSelect.preferred.reset()
|
||||
try {
|
||||
await fn()
|
||||
} finally {
|
||||
if (prev === undefined) delete process.env.SHELL
|
||||
else process.env.SHELL = prev
|
||||
Shell.acceptable.reset()
|
||||
Shell.preferred.reset()
|
||||
ShellSelect.acceptable.reset()
|
||||
ShellSelect.preferred.reset()
|
||||
}
|
||||
}
|
||||
|
||||
describe("shell", () => {
|
||||
test("normalizes shell names", () => {
|
||||
expect(Shell.name("/bin/bash")).toBe("bash")
|
||||
expect(ShellSelect.name("/bin/bash")).toBe("bash")
|
||||
if (process.platform === "win32") {
|
||||
expect(Shell.name("C:/tools/NU.EXE")).toBe("nu")
|
||||
expect(Shell.name("C:/tools/PWSH.EXE")).toBe("pwsh")
|
||||
expect(ShellSelect.name("C:/tools/NU.EXE")).toBe("nu")
|
||||
expect(ShellSelect.name("C:/tools/PWSH.EXE")).toBe("pwsh")
|
||||
}
|
||||
})
|
||||
|
||||
test("detects login shells", () => {
|
||||
expect(Shell.login("/bin/bash")).toBe(true)
|
||||
expect(Shell.login("C:/tools/pwsh.exe")).toBe(false)
|
||||
expect(ShellSelect.login("/bin/bash")).toBe(true)
|
||||
expect(ShellSelect.login("C:/tools/pwsh.exe")).toBe(false)
|
||||
})
|
||||
|
||||
test("detects posix shells", () => {
|
||||
expect(Shell.posix("/bin/bash")).toBe(true)
|
||||
expect(Shell.posix("/bin/fish")).toBe(false)
|
||||
expect(Shell.posix("C:/tools/pwsh.exe")).toBe(false)
|
||||
expect(ShellSelect.posix("/bin/bash")).toBe(true)
|
||||
expect(ShellSelect.posix("/bin/fish")).toBe(false)
|
||||
expect(ShellSelect.posix("C:/tools/pwsh.exe")).toBe(false)
|
||||
})
|
||||
|
||||
test("falls back when configured shell cannot be resolved", async () => {
|
||||
await withShell(undefined, async () => {
|
||||
const preferred = Shell.preferred()
|
||||
const acceptable = Shell.acceptable()
|
||||
expect(Shell.preferred("opencode-missing-shell")).toBe(preferred)
|
||||
expect(Shell.acceptable("opencode-missing-shell")).toBe(acceptable)
|
||||
const preferred = ShellSelect.preferred()
|
||||
const acceptable = ShellSelect.acceptable()
|
||||
expect(ShellSelect.preferred("opencode-missing-shell")).toBe(preferred)
|
||||
expect(ShellSelect.acceptable("opencode-missing-shell")).toBe(acceptable)
|
||||
})
|
||||
})
|
||||
|
||||
test("falls back for terminal-only acceptable shells", () => {
|
||||
expect(Shell.name(Shell.acceptable("fish"))).not.toBe("fish")
|
||||
expect(Shell.name(Shell.acceptable("nu"))).not.toBe("nu")
|
||||
expect(ShellSelect.name(ShellSelect.acceptable("fish"))).not.toBe("fish")
|
||||
expect(ShellSelect.name(ShellSelect.acceptable("nu"))).not.toBe("nu")
|
||||
})
|
||||
|
||||
test("builds command args per shell family", () => {
|
||||
expect(Shell.args("/bin/sh", "echo hi", "/tmp")).toEqual(["-c", "echo hi"])
|
||||
expect(Shell.args("/usr/bin/fish", "echo hi", "/tmp")).toEqual(["-c", "echo hi"])
|
||||
const zsh = Shell.args("/bin/zsh", "echo hi", "/tmp")
|
||||
expect(ShellSelect.args("/bin/sh", "echo hi", "/tmp")).toEqual(["-c", "echo hi"])
|
||||
expect(ShellSelect.args("/usr/bin/fish", "echo hi", "/tmp")).toEqual(["-c", "echo hi"])
|
||||
const zsh = ShellSelect.args("/bin/zsh", "echo hi", "/tmp")
|
||||
expect(zsh[0]).toBe("-l")
|
||||
expect(zsh[1]).toBe("-c")
|
||||
expect(zsh.at(-1)).toBe("/tmp")
|
||||
|
|
@ -66,34 +66,34 @@ describe("shell", () => {
|
|||
if (process.platform === "win32") {
|
||||
test("rejects blacklisted shells case-insensitively", async () => {
|
||||
await withShell("NU.EXE", async () => {
|
||||
expect(Shell.name(Shell.acceptable())).not.toBe("nu")
|
||||
expect(ShellSelect.name(ShellSelect.acceptable())).not.toBe("nu")
|
||||
})
|
||||
})
|
||||
|
||||
test("normalizes Git Bash shell paths from env", async () => {
|
||||
const shell = "/cygdrive/c/Program Files/Git/bin/bash.exe"
|
||||
await withShell(shell, async () => {
|
||||
expect(Shell.preferred()).toBe(FSUtil.windowsPath(shell))
|
||||
expect(ShellSelect.preferred()).toBe(FSUtil.windowsPath(shell))
|
||||
})
|
||||
})
|
||||
|
||||
test("resolves /usr/bin/bash from env to Git Bash", async () => {
|
||||
const bash = Shell.gitbash()
|
||||
const bash = ShellSelect.gitbash()
|
||||
if (!bash) return
|
||||
await withShell("/usr/bin/bash", async () => {
|
||||
expect(Shell.acceptable()).toBe(bash)
|
||||
expect(Shell.preferred()).toBe(bash)
|
||||
expect(ShellSelect.acceptable()).toBe(bash)
|
||||
expect(ShellSelect.preferred()).toBe(bash)
|
||||
})
|
||||
})
|
||||
|
||||
test("resolves bare bash to Git Bash before PATH", async () => {
|
||||
const bash = Shell.gitbash()
|
||||
const bash = ShellSelect.gitbash()
|
||||
if (!bash) return
|
||||
expect(Shell.acceptable("bash")).toBe(bash)
|
||||
expect(Shell.preferred("bash")).toBe(bash)
|
||||
expect(ShellSelect.acceptable("bash")).toBe(bash)
|
||||
expect(ShellSelect.preferred("bash")).toBe(bash)
|
||||
await withShell("bash", async () => {
|
||||
expect(Shell.acceptable()).toBe(bash)
|
||||
expect(Shell.preferred()).toBe(bash)
|
||||
expect(ShellSelect.acceptable()).toBe(bash)
|
||||
expect(ShellSelect.preferred()).toBe(bash)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ describe("shell", () => {
|
|||
const shell = which("pwsh") || which("powershell")
|
||||
if (!shell) return
|
||||
await withShell(path.win32.basename(shell), async () => {
|
||||
expect(Shell.preferred()).toBe(shell)
|
||||
expect(ShellSelect.preferred()).toBe(shell)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue