mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-20 07:34:38 +00:00
fix(opencode): serialize config bun installs (#17342)
This commit is contained in:
@@ -37,6 +37,7 @@ import { Account } from "@/account"
|
|||||||
import { ConfigPaths } from "./paths"
|
import { ConfigPaths } from "./paths"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import { Process } from "@/util/process"
|
import { Process } from "@/util/process"
|
||||||
|
import { Lock } from "@/util/lock"
|
||||||
|
|
||||||
export namespace Config {
|
export namespace Config {
|
||||||
const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
|
const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
|
||||||
@@ -289,6 +290,7 @@ export namespace Config {
|
|||||||
|
|
||||||
// Install any additional dependencies defined in the package.json
|
// Install any additional dependencies defined in the package.json
|
||||||
// This allows local plugins and custom tools to use external packages
|
// This allows local plugins and custom tools to use external packages
|
||||||
|
using _ = await Lock.write("bun-install")
|
||||||
await BunProc.run(
|
await BunProc.run(
|
||||||
[
|
[
|
||||||
"install",
|
"install",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test, expect, describe, mock, afterEach } from "bun:test"
|
import { test, expect, describe, mock, afterEach, spyOn } from "bun:test"
|
||||||
import { Config } from "../../src/config/config"
|
import { Config } from "../../src/config/config"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Auth } from "../../src/auth"
|
import { Auth } from "../../src/auth"
|
||||||
@@ -10,6 +10,7 @@ import { pathToFileURL } from "url"
|
|||||||
import { Global } from "../../src/global"
|
import { Global } from "../../src/global"
|
||||||
import { ProjectID } from "../../src/project/schema"
|
import { ProjectID } from "../../src/project/schema"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
|
import { BunProc } from "../../src/bun"
|
||||||
|
|
||||||
// Get managed config directory from environment (set in preload.ts)
|
// Get managed config directory from environment (set in preload.ts)
|
||||||
const managedConfigDir = process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR!
|
const managedConfigDir = process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR!
|
||||||
@@ -763,6 +764,39 @@ test("installs dependencies in writable OPENCODE_CONFIG_DIR", async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("serializes concurrent config dependency installs", async () => {
|
||||||
|
await using tmp = await tmpdir()
|
||||||
|
const dirs = [path.join(tmp.path, "a"), path.join(tmp.path, "b")]
|
||||||
|
await Promise.all(dirs.map((dir) => fs.mkdir(dir, { recursive: true })))
|
||||||
|
|
||||||
|
const seen: string[] = []
|
||||||
|
let active = 0
|
||||||
|
let max = 0
|
||||||
|
const run = spyOn(BunProc, "run").mockImplementation(async (_cmd, opts) => {
|
||||||
|
active++
|
||||||
|
max = Math.max(max, active)
|
||||||
|
seen.push(opts?.cwd ?? "")
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 25))
|
||||||
|
active--
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
stdout: Buffer.alloc(0),
|
||||||
|
stderr: Buffer.alloc(0),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(dirs.map((dir) => Config.installDependencies(dir)))
|
||||||
|
} finally {
|
||||||
|
run.mockRestore()
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(max).toBe(1)
|
||||||
|
expect(seen.toSorted()).toEqual(dirs.toSorted())
|
||||||
|
expect(await Filesystem.exists(path.join(dirs[0], "package.json"))).toBe(true)
|
||||||
|
expect(await Filesystem.exists(path.join(dirs[1], "package.json"))).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
test("resolves scoped npm plugins in config", async () => {
|
test("resolves scoped npm plugins in config", async () => {
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
init: async (dir) => {
|
init: async (dir) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user