Compare commits

...
1 Commits
Author SHA1 Message Date
rekram1-node f4f781da7b fix(util): isolate temporary scratch files 2026-08-24 14:53:18 +00:00
4 changed files with 22 additions and 7 deletions
+1 -1
View File
@@ -14,6 +14,6 @@ export function roots(app: string) {
cache: path.join(cache!, app),
config: path.join(config!, app),
state: path.join(state!, app),
tmp: path.join(os.tmpdir(), app),
tmp: path.join(process.env.XDG_RUNTIME_DIR || os.tmpdir(), app),
}
}
+12 -3
View File
@@ -65,12 +65,21 @@ const acquire = (input: Partial<Interface>) =>
const service = Service.of(make(input))
yield* Effect.promise(() =>
Promise.all(
[service.data, service.config, service.state, service.log, service.bin, service.repos, service.tmp].map(
(directory) => fs.promises.mkdir(directory, { recursive: true }),
[service.data, service.config, service.state, service.log, service.bin, service.repos].map((directory) =>
fs.promises.mkdir(directory, { recursive: true }),
),
),
)
const canonicalTmp = yield* Effect.promise(() => fs.promises.realpath(service.tmp))
const temporary = yield* Effect.promise(async () => {
if (input.tmp !== undefined || process.env.XDG_RUNTIME_DIR) {
await fs.promises.mkdir(service.tmp, { recursive: true })
return service.tmp
}
await fs.promises.mkdir(path.dirname(service.tmp), { recursive: true })
return fs.promises.mkdtemp(`${service.tmp}-`)
})
yield* Effect.promise(() => fs.promises.access(temporary, fs.constants.W_OK | fs.constants.X_OK))
const canonicalTmp = yield* Effect.promise(() => fs.promises.realpath(temporary))
return Service.of({ ...service, tmp: input.tmp ?? canonicalTmp })
})
+3 -1
View File
@@ -13,6 +13,7 @@ describe("global roots", () => {
XDG_CACHE_HOME: path.join(root, "cache"),
XDG_CONFIG_HOME: path.join(root, "config"),
XDG_STATE_HOME: path.join(root, "state"),
XDG_RUNTIME_DIR: path.join(root, "runtime"),
}
expect(run(env)).toEqual({
@@ -20,7 +21,7 @@ describe("global roots", () => {
cache: path.join(env.XDG_CACHE_HOME, "opencode"),
config: path.join(env.XDG_CONFIG_HOME, "opencode"),
state: path.join(env.XDG_STATE_HOME, "opencode"),
tmp: path.join(os.tmpdir(), "opencode"),
tmp: path.join(env.XDG_RUNTIME_DIR, "opencode"),
})
})
@@ -33,6 +34,7 @@ describe("global roots", () => {
XDG_CACHE_HOME: "",
XDG_CONFIG_HOME: "",
XDG_STATE_HOME: "",
XDG_RUNTIME_DIR: "",
...(process.platform === "win32" ? { USERPROFILE: home } : { HOME: home }),
}),
).toEqual({
+6 -2
View File
@@ -19,6 +19,7 @@ describe("global", () => {
XDG_CACHE_HOME: directories[1],
XDG_CONFIG_HOME: directories[2],
XDG_STATE_HOME: directories[3],
XDG_RUNTIME_DIR: "",
TMPDIR: directories[4],
},
stderr: "pipe",
@@ -70,6 +71,7 @@ describe("global", () => {
XDG_CACHE_HOME: directories[1],
XDG_CONFIG_HOME: directories[2],
XDG_STATE_HOME: directories[3],
XDG_RUNTIME_DIR: "",
TMPDIR: directories[4],
},
stdout: "pipe",
@@ -77,7 +79,9 @@ describe("global", () => {
})
expect(result.exitCode, result.stderr.toString()).toBe(0)
expect(result.stdout.toString()).toBe(fs.realpathSync(path.join(directories[4], "opencode")))
const temporary = result.stdout.toString()
expect(path.dirname(temporary)).toBe(fs.realpathSync(directories[4]))
expect(path.basename(temporary)).toMatch(/^opencode-.{6}$/)
const created = [
path.join(directories[0], "opencode"),
path.join(directories[1], "opencode", "bin"),
@@ -85,7 +89,7 @@ describe("global", () => {
path.join(directories[3], "opencode"),
path.join(directories[0], "opencode", "log"),
path.join(directories[0], "opencode", "repos"),
path.join(directories[4], "opencode"),
temporary,
]
created.forEach((directory) => expect(fs.statSync(directory).isDirectory()).toBe(true))
fs.rmSync(root, { recursive: true, force: true })