79 lines · 2.2 KB · TypeScript
RawDownload
import { Flag } from "@/flag/flag"import { lazy } from "@/util/lazy"import path from "path"import fs from "fs"import { spawn, type ChildProcess } from "child_process" const SIGKILL_TIMEOUT_MS = 200 export namespace Shell {  export async function killTree(proc: ChildProcess, opts?: { exited?: () => boolean }): Promise<void> {    const pid = proc.pid    if (!pid || opts?.exited?.()) return     if (process.platform === "win32") {      await new Promise<void>((resolve) => {        const killer = spawn("taskkill", ["/pid", String(pid), "/f", "/t"], { stdio: "ignore" })        killer.once("exit", () => resolve())        killer.once("error", () => resolve())      })      return    }     try {      process.kill(-pid, "SIGTERM")      await Bun.sleep(SIGKILL_TIMEOUT_MS)      if (!opts?.exited?.()) {        process.kill(-pid, "SIGKILL")      }    } catch (_e) {      proc.kill("SIGTERM")      await Bun.sleep(SIGKILL_TIMEOUT_MS)      if (!opts?.exited?.()) {        proc.kill("SIGKILL")      }    }  }  const BLACKLIST = new Set(["fish", "nu"])   function exists(p: string) {    try {      return fs.existsSync(p)    } catch {      return false    }  }   function fallback() {    if (process.platform === "win32") {      if (Flag.OPENSCIENCE_GIT_BASH_PATH) return Flag.OPENSCIENCE_GIT_BASH_PATH      const git = Bun.which("git")      if (git) {        // git.exe is typically at: C:\Program Files\Git\cmd\git.exe        // bash.exe is at: C:\Program Files\Git\bin\bash.exe        const bash = path.join(git, "..", "..", "bin", "bash.exe")        if (Bun.file(bash).size) return bash      }      return process.env.COMSPEC || "cmd.exe"    }    if (process.platform === "darwin") {      if (exists("/bin/zsh")) return "/bin/zsh"    }    const bash = Bun.which("bash")    if (bash) return bash    if (exists("/bin/bash")) return "/bin/bash"    return "/bin/sh"  }   export const preferred = lazy(() => {    const s = process.env.SHELL    if (s) return s    return fallback()  })   export const acceptable = lazy(() => {    const s = process.env.SHELL    if (s && !BLACKLIST.has(process.platform === "win32" ? path.win32.basename(s) : path.basename(s))) return s    return fallback()  })}