Snapshot only committed extensions and publish the last-good marker atomically
This commit is contained in:
@@ -31486,7 +31486,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
|
||||
const loaderGit = async (...args) => {
|
||||
for (let attempt = 0; ; attempt++) {
|
||||
try {
|
||||
const result = await exec(["git", ...args], { cwd: repo, timeout: 120, signal: commands.signal });
|
||||
const result = await exec(["git", ...args], { cwd: repo, signal: commands.signal });
|
||||
if (result.code) throw new Error(result.stderr || `git exited ${result.code}`);
|
||||
return result.stdout.trim();
|
||||
} catch (error) {
|
||||
@@ -31502,7 +31502,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
|
||||
const publish2 = async () => {
|
||||
await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context);
|
||||
ops2.op_extension_status(JSON.stringify(state));
|
||||
await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? "");
|
||||
await fs.write("/src/sausage/.git/sausage-last-good.tmp", state.good ?? "");
|
||||
await fs.rename("/src/sausage/.git/sausage-last-good.tmp", "/src/sausage/.git/sausage-last-good");
|
||||
};
|
||||
const dispose = async (entries2) => {
|
||||
for (const facet of entries2) for (const cleanup of facet.close) {
|
||||
@@ -31592,8 +31593,19 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
|
||||
try {
|
||||
await fs.stat(snapshot);
|
||||
} catch {
|
||||
await loaderGit("worktree", "prune");
|
||||
await loaderGit("worktree", "add", "--detach", snapshot, sha);
|
||||
const staging = `${snapshot}.tmp`, archive = `${snapshot}.tar`;
|
||||
try {
|
||||
await fs.mkdir(staging);
|
||||
} catch (error) {
|
||||
if (error.code !== "already_exists") throw error;
|
||||
}
|
||||
if (await loaderGit("ls-tree", "--name-only", sha, "extensions")) {
|
||||
await loaderGit("archive", "--format=tar", `--output=${archive}`, sha, "extensions");
|
||||
const result = await exec(["tar", "-xf", archive, "-C", staging], { cwd: repo, signal: commands.signal });
|
||||
if (result.code) throw new Error(`tar: ${result.stderr || result.code}`);
|
||||
await fs.remove(archive);
|
||||
}
|
||||
await fs.rename(staging, snapshot);
|
||||
}
|
||||
const modules = [];
|
||||
for (const entry2 of await fs.list(`${snapshot}/extensions`).catch((error) => {
|
||||
@@ -31720,6 +31732,9 @@ var harness = await Harness.open(storage, { models, registry, settings: { get ex
|
||||
} } }, BACKGROUND_CONTEXT);
|
||||
var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "faux", modelId: "faux-1" } } });
|
||||
globalThis.shared = { gate: Promise.withResolvers(), started: false, wait: false };
|
||||
var markerWrite = fs.write;
|
||||
var markerBlocked = Promise.withResolvers();
|
||||
var markerRelease = Promise.withResolvers();
|
||||
var loader = await loadExtensions(harness, registry, storage, models, BACKGROUND_CONTEXT);
|
||||
harness.resume();
|
||||
var turn = async () => {
|
||||
@@ -31783,15 +31798,30 @@ return defineExtension({name:'demo',tools:[defineTool({name:'demo',description:'
|
||||
globalThis.shared.gate.resolve();
|
||||
assert((await running).includes("result A"), "Old call must finish on A");
|
||||
assert((await turn()).includes("result C"), "Next call must use C");
|
||||
await loader.reload();
|
||||
fs.write = async (path, text) => {
|
||||
if (path.includes("sausage-last-good")) {
|
||||
fs.write = markerWrite;
|
||||
await markerWrite(path, "");
|
||||
markerBlocked.resolve();
|
||||
await markerRelease.promise;
|
||||
}
|
||||
return markerWrite(path, text);
|
||||
};
|
||||
await git("/src/sausage", "update-ref", "refs/heads/main", b);
|
||||
await until2(() => loader.state().current === b && !!loader.state().error);
|
||||
assert((await exec(["extensions-revert"], { cwd: "/" })).code === 0, "Revert command");
|
||||
await markerBlocked.promise;
|
||||
const reverted = await exec(["extensions-revert"], { cwd: "/" });
|
||||
markerRelease.resolve();
|
||||
assert(reverted.code === 0, `Revert command: ${JSON.stringify(reverted)}`);
|
||||
await until2(() => loader.state().current === c && !loader.state().error);
|
||||
await git("/src/sausage", "update-ref", "refs/heads/main", b);
|
||||
await until2(() => loader.state().current === b && !!loader.state().error);
|
||||
await fs.write("/src/sausage/good.txt", c);
|
||||
}
|
||||
} finally {
|
||||
markerRelease.resolve();
|
||||
fs.write = markerWrite;
|
||||
globalThis.shared.gate.resolve();
|
||||
await loader.close();
|
||||
await harness.close(BACKGROUND_CONTEXT);
|
||||
|
||||
Reference in New Issue
Block a user