mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 19:31:24 +00:00
Browser/Logging: share default openclaw tmp dir resolver
This commit is contained in:
64
src/infra/tmp-openclaw-dir.test.ts
Normal file
64
src/infra/tmp-openclaw-dir.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { POSIX_OPENCLAW_TMP_DIR, resolvePreferredOpenClawTmpDir } from "./tmp-openclaw-dir.js";
|
||||
|
||||
describe("resolvePreferredOpenClawTmpDir", () => {
|
||||
it("prefers /tmp/openclaw when it already exists and is writable", () => {
|
||||
const accessSync = vi.fn();
|
||||
const statSync = vi.fn(() => ({ isDirectory: () => true }));
|
||||
const tmpdir = vi.fn(() => "/var/fallback");
|
||||
|
||||
const resolved = resolvePreferredOpenClawTmpDir({ accessSync, statSync, tmpdir });
|
||||
|
||||
expect(statSync).toHaveBeenCalledTimes(1);
|
||||
expect(accessSync).toHaveBeenCalledTimes(1);
|
||||
expect(resolved).toBe(POSIX_OPENCLAW_TMP_DIR);
|
||||
expect(tmpdir).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("prefers /tmp/openclaw when it does not exist but /tmp is writable", () => {
|
||||
const accessSync = vi.fn();
|
||||
const statSync = vi.fn(() => {
|
||||
const err = new Error("missing") as Error & { code?: string };
|
||||
err.code = "ENOENT";
|
||||
throw err;
|
||||
});
|
||||
const tmpdir = vi.fn(() => "/var/fallback");
|
||||
|
||||
const resolved = resolvePreferredOpenClawTmpDir({ accessSync, statSync, tmpdir });
|
||||
|
||||
expect(resolved).toBe(POSIX_OPENCLAW_TMP_DIR);
|
||||
expect(accessSync).toHaveBeenCalledWith("/tmp", expect.any(Number));
|
||||
expect(tmpdir).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to os.tmpdir()/openclaw when /tmp/openclaw is not a directory", () => {
|
||||
const accessSync = vi.fn();
|
||||
const statSync = vi.fn(() => ({ isDirectory: () => false }));
|
||||
const tmpdir = vi.fn(() => "/var/fallback");
|
||||
|
||||
const resolved = resolvePreferredOpenClawTmpDir({ accessSync, statSync, tmpdir });
|
||||
|
||||
expect(resolved).toBe(path.join("/var/fallback", "openclaw"));
|
||||
expect(tmpdir).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("falls back to os.tmpdir()/openclaw when /tmp is not writable", () => {
|
||||
const accessSync = vi.fn((target: string) => {
|
||||
if (target === "/tmp") {
|
||||
throw new Error("read-only");
|
||||
}
|
||||
});
|
||||
const statSync = vi.fn(() => {
|
||||
const err = new Error("missing") as Error & { code?: string };
|
||||
err.code = "ENOENT";
|
||||
throw err;
|
||||
});
|
||||
const tmpdir = vi.fn(() => "/var/fallback");
|
||||
|
||||
const resolved = resolvePreferredOpenClawTmpDir({ accessSync, statSync, tmpdir });
|
||||
|
||||
expect(resolved).toBe(path.join("/var/fallback", "openclaw"));
|
||||
expect(tmpdir).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
50
src/infra/tmp-openclaw-dir.ts
Normal file
50
src/infra/tmp-openclaw-dir.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
export const POSIX_OPENCLAW_TMP_DIR = "/tmp/openclaw";
|
||||
|
||||
type ResolvePreferredOpenClawTmpDirOptions = {
|
||||
accessSync?: (path: string, mode?: number) => void;
|
||||
statSync?: (path: string) => { isDirectory(): boolean };
|
||||
tmpdir?: () => string;
|
||||
};
|
||||
|
||||
type MaybeNodeError = { code?: string };
|
||||
|
||||
function isNodeErrorWithCode(err: unknown, code: string): err is MaybeNodeError {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
"code" in err &&
|
||||
(err as MaybeNodeError).code === code
|
||||
);
|
||||
}
|
||||
|
||||
export function resolvePreferredOpenClawTmpDir(
|
||||
options: ResolvePreferredOpenClawTmpDirOptions = {},
|
||||
): string {
|
||||
const accessSync = options.accessSync ?? fs.accessSync;
|
||||
const statSync = options.statSync ?? fs.statSync;
|
||||
const tmpdir = options.tmpdir ?? os.tmpdir;
|
||||
|
||||
try {
|
||||
const preferred = statSync(POSIX_OPENCLAW_TMP_DIR);
|
||||
if (!preferred.isDirectory()) {
|
||||
return path.join(tmpdir(), "openclaw");
|
||||
}
|
||||
accessSync(POSIX_OPENCLAW_TMP_DIR, fs.constants.W_OK | fs.constants.X_OK);
|
||||
return POSIX_OPENCLAW_TMP_DIR;
|
||||
} catch (err) {
|
||||
if (!isNodeErrorWithCode(err, "ENOENT")) {
|
||||
return path.join(tmpdir(), "openclaw");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
accessSync("/tmp", fs.constants.W_OK | fs.constants.X_OK);
|
||||
return POSIX_OPENCLAW_TMP_DIR;
|
||||
} catch {
|
||||
return path.join(tmpdir(), "openclaw");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user