Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/moshcode.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ async function main() {
return results.filter((r) => !r.ok).length ? 1 : 0;
},
write: (path, body) => fsp.writeFile(path, body),
runner: (cmd2, args2) => new Promise((res) => execFile(cmd2, args2, () => res({ ok: true }))),
runner: (cmd2, args2) => new Promise((res) => execFile(cmd2, args2, (err) => res({ ok: !err }))),
})) || 0;
return;
}
Expand Down
12 changes: 10 additions & 2 deletions src/selfupdate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,16 @@ export async function selfUpdateCommand(args = [], out = console.log, deps = {})
await write(`/etc/systemd/system/${name}`, body);
out(` wrote /etc/systemd/system/${name}`);
}
await runner("systemctl", ["daemon-reload"]);
await runner("systemctl", ["enable", "--now", "moshcode-update.timer"]);
const reload = await runner("systemctl", ["daemon-reload"]);
const enable = await runner("systemctl", ["enable", "--now", "moshcode-update.timer"]);
// The units are on disk, but they only run if systemd actually took them.
// On a host without systemd (a container, WSL, macOS) or without root, the
// enable fails — and saying "checking on a schedule now" then would promise
// an auto-update that will never fire. Report the failure instead.
if (reload?.ok === false || enable?.ok === false) {
out("moshcode update: wrote the units but systemctl could not start the timer — it is not checking on a schedule yet. run `systemctl enable --now moshcode-update.timer` as root.");
return 1;
}
out("checking on a schedule now. `systemctl list-timers moshcode-update` to see when.");
return 0;
}
Expand Down
22 changes: 22 additions & 0 deletions test/selfupdate.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ test("control: a valid --interval still writes the units it always did", async (
assert.match(lines.join("\n"), /checking on a schedule/);
});

// The units on disk mean nothing if systemd never took them. When `systemctl
// enable --now` fails — no systemd (container/WSL/macOS) or no root — the
// command must not claim it is "checking on a schedule now"; that would promise
// an auto-update that never fires.
test("--install reports failure when systemctl cannot start the timer", async () => {
const written = new Map();
const lines = [];
const code = await selfUpdateCommand(
["--timer", "--interval", "1h", "--install"],
(l) => lines.push(l),
{
write: async (p, b) => written.set(p, b),
runner: async (cmd, args) => (cmd === "systemctl" && args[0] === "enable" ? { ok: false } : { ok: true }),
},
);

assert.equal(code, 1);
assert.equal(written.size, 2); // units were still written, we just did not lie about the timer
assert.doesNotMatch(lines.join("\n"), /checking on a schedule now/);
assert.match(lines.join("\n"), /systemctl could not start the timer/);
});

test("control: --timer with no --interval is still the default", async () => {
const lines = [];
assert.equal(await selfUpdateCommand(["--timer"], (l) => lines.push(l), {}), 0);
Expand Down
Loading