index.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import { z } from "zod"
  2. import { Global } from "../global"
  3. import { Log } from "../util/log"
  4. import path from "path"
  5. import { NamedError } from "../util/error"
  6. export namespace BunProc {
  7. const log = Log.create({ service: "bun" })
  8. export async function run(
  9. cmd: string[],
  10. options?: Bun.SpawnOptions.OptionsObject<any, any, any>,
  11. ) {
  12. log.info("running", {
  13. cmd: [which(), ...cmd],
  14. ...options,
  15. })
  16. const result = Bun.spawn([which(), ...cmd], {
  17. ...options,
  18. stdout: "pipe",
  19. stderr: "pipe",
  20. env: {
  21. ...process.env,
  22. ...options?.env,
  23. BUN_BE_BUN: "1",
  24. },
  25. })
  26. const code = await result.exited
  27. // @ts-ignore
  28. const stdout = await result.stdout.text()
  29. // @ts-ignore
  30. const stderr = await result.stderr.text()
  31. log.info("done", {
  32. code,
  33. stdout,
  34. stderr,
  35. })
  36. if (code !== 0) {
  37. throw new Error(`Command failed with exit code ${result.exitCode}`)
  38. }
  39. return result
  40. }
  41. export function which() {
  42. return process.execPath
  43. }
  44. export const InstallFailedError = NamedError.create(
  45. "BunInstallFailedError",
  46. z.object({
  47. pkg: z.string(),
  48. version: z.string(),
  49. }),
  50. )
  51. export async function install(pkg: string, version = "latest") {
  52. const mod = path.join(Global.Path.cache, "node_modules", pkg)
  53. const pkgjson = Bun.file(path.join(Global.Path.cache, "package.json"))
  54. const parsed = await pkgjson.json().catch(() => ({
  55. dependencies: {},
  56. }))
  57. if (parsed.dependencies[pkg] === version) return mod
  58. parsed.dependencies[pkg] = version
  59. await Bun.write(pkgjson, JSON.stringify(parsed, null, 2))
  60. await BunProc.run(["install", "--registry=https://registry.npmjs.org"], {
  61. cwd: Global.Path.cache,
  62. }).catch((e) => {
  63. new InstallFailedError(
  64. { pkg, version },
  65. {
  66. cause: e,
  67. },
  68. )
  69. })
  70. return mod
  71. }
  72. }