mirror of
https://github.com/DeterminateSystems/magic-nix-cache-action.git
synced 2024-12-27 01:30:35 +01:00
Switch to tsup-based build
This commit is contained in:
parent
6025e25baf
commit
9a6afa777f
9 changed files with 1653 additions and 240 deletions
1
dist/index.d.ts
generated
vendored
1
dist/index.d.ts
generated
vendored
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
457
dist/index.js
generated
vendored
457
dist/index.js
generated
vendored
|
@ -95085,7 +95085,8 @@ function mungeDiagnosticEndpoint(inputUrl) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ./dist/index.js
|
;// CONCATENATED MODULE: ./dist/main.js
|
||||||
|
// src/main.ts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -95097,266 +95098,254 @@ function mungeDiagnosticEndpoint(inputUrl) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR";
|
var ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR";
|
||||||
const gotClient = got_dist_source.extend({
|
var gotClient = got_dist_source.extend({
|
||||||
retry: {
|
retry: {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"],
|
methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"]
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeRetry: [
|
beforeRetry: [
|
||||||
(error, retryCount) => {
|
(error, retryCount) => {
|
||||||
core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`);
|
core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`);
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
async function fetchAutoCacher(toolbox) {
|
async function fetchAutoCacher(toolbox) {
|
||||||
const closurePath = await toolbox.fetch();
|
const closurePath = await toolbox.fetch();
|
||||||
toolbox.recordEvent("load_closure");
|
toolbox.recordEvent("load_closure");
|
||||||
const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)(`cat "${closurePath}" | xz -d | nix-store --import`);
|
const { stdout } = await (0,external_node_util_.promisify)(external_node_child_process_namespaceObject.exec)(
|
||||||
const paths = stdout.split(external_node_os_.EOL);
|
`cat "${closurePath}" | xz -d | nix-store --import`
|
||||||
// Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last).
|
);
|
||||||
const last_path = paths.at(-2);
|
const paths = stdout.split(external_node_os_.EOL);
|
||||||
return `${last_path}/bin/magic-nix-cache`;
|
const last_path = paths.at(-2);
|
||||||
|
return `${last_path}/bin/magic-nix-cache`;
|
||||||
}
|
}
|
||||||
function tailLog(daemonDir) {
|
function tailLog(daemonDir) {
|
||||||
const log = new tail/* Tail */.x(external_node_path_namespaceObject.join(daemonDir, "daemon.log"));
|
const log = new tail/* Tail */.x(external_node_path_namespaceObject.join(daemonDir, "daemon.log"));
|
||||||
core.debug(`tailing daemon.log...`);
|
core.debug(`tailing daemon.log...`);
|
||||||
log.on("line", (line) => {
|
log.on("line", (line) => {
|
||||||
core.info(line);
|
core.info(line);
|
||||||
});
|
});
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
async function setUpAutoCache(toolbox) {
|
async function setUpAutoCache(toolbox) {
|
||||||
const tmpdir = process.env["RUNNER_TEMP"] || external_node_os_.tmpdir();
|
const tmpdir2 = process.env["RUNNER_TEMP"] || external_node_os_.tmpdir();
|
||||||
const required_env = [
|
const required_env = [
|
||||||
"ACTIONS_CACHE_URL",
|
"ACTIONS_CACHE_URL",
|
||||||
"ACTIONS_RUNTIME_URL",
|
"ACTIONS_RUNTIME_URL",
|
||||||
"ACTIONS_RUNTIME_TOKEN",
|
"ACTIONS_RUNTIME_TOKEN"
|
||||||
];
|
];
|
||||||
let anyMissing = false;
|
let anyMissing = false;
|
||||||
for (const n of required_env) {
|
for (const n of required_env) {
|
||||||
if (!process.env.hasOwnProperty(n)) {
|
if (!process.env.hasOwnProperty(n)) {
|
||||||
anyMissing = true;
|
anyMissing = true;
|
||||||
core.warning(`Disabling automatic caching since required environment ${n} isn't available`);
|
core.warning(
|
||||||
}
|
`Disabling automatic caching since required environment ${n} isn't available`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (anyMissing) {
|
}
|
||||||
return;
|
if (anyMissing) {
|
||||||
}
|
return;
|
||||||
core.debug(`GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`);
|
}
|
||||||
const daemonDir = await promises_namespaceObject.mkdtemp(external_node_path_namespaceObject.join(tmpdir, "magic-nix-cache-"));
|
core.debug(`GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`);
|
||||||
let daemonBin;
|
const daemonDir = await promises_namespaceObject.mkdtemp(external_node_path_namespaceObject.join(tmpdir2, "magic-nix-cache-"));
|
||||||
if (core.getInput("source-binary")) {
|
let daemonBin;
|
||||||
daemonBin = core.getInput("source-binary");
|
if (core.getInput("source-binary")) {
|
||||||
}
|
daemonBin = core.getInput("source-binary");
|
||||||
else {
|
} else {
|
||||||
daemonBin = await fetchAutoCacher(toolbox);
|
daemonBin = await fetchAutoCacher(toolbox);
|
||||||
}
|
}
|
||||||
let runEnv;
|
let runEnv;
|
||||||
if (core.isDebug()) {
|
if (core.isDebug()) {
|
||||||
runEnv = {
|
runEnv = {
|
||||||
RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug",
|
RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug",
|
||||||
RUST_BACKTRACE: "full",
|
RUST_BACKTRACE: "full",
|
||||||
...process.env,
|
...process.env
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
runEnv = process.env;
|
|
||||||
}
|
|
||||||
const notifyPort = core.getInput("startup-notification-port");
|
|
||||||
const notifyPromise = new Promise((resolveListening) => {
|
|
||||||
const promise = new Promise(async (resolveQuit) => {
|
|
||||||
const notifyServer = external_http_.createServer((req, res) => {
|
|
||||||
if (req.method === "POST" && req.url === "/") {
|
|
||||||
core.debug(`Notify server shutting down.`);
|
|
||||||
res.writeHead(200, { "Content-Type": "application/json" });
|
|
||||||
res.end("{}");
|
|
||||||
notifyServer.close(() => {
|
|
||||||
resolveQuit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
notifyServer.listen(notifyPort, () => {
|
|
||||||
core.debug(`Notify server running.`);
|
|
||||||
resolveListening(promise);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// Start tailing the daemon log.
|
|
||||||
const outputPath = `${daemonDir}/daemon.log`;
|
|
||||||
const output = (0,external_node_fs_namespaceObject.openSync)(outputPath, "a");
|
|
||||||
const log = tailLog(daemonDir);
|
|
||||||
const netrc = await netrcPath();
|
|
||||||
const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`;
|
|
||||||
const daemonCliFlags = [
|
|
||||||
"--startup-notification-url",
|
|
||||||
`http://127.0.0.1:${notifyPort}`,
|
|
||||||
"--listen",
|
|
||||||
core.getInput("listen"),
|
|
||||||
"--upstream",
|
|
||||||
core.getInput("upstream-cache"),
|
|
||||||
"--diagnostic-endpoint",
|
|
||||||
core.getInput("diagnostic-endpoint"),
|
|
||||||
"--nix-conf",
|
|
||||||
nixConfPath,
|
|
||||||
]
|
|
||||||
.concat(core.getBooleanInput("use-flakehub")
|
|
||||||
? [
|
|
||||||
"--use-flakehub",
|
|
||||||
"--flakehub-cache-server",
|
|
||||||
core.getInput("flakehub-cache-server"),
|
|
||||||
"--flakehub-api-server",
|
|
||||||
core.getInput("flakehub-api-server"),
|
|
||||||
"--flakehub-api-server-netrc",
|
|
||||||
netrc,
|
|
||||||
"--flakehub-flake-name",
|
|
||||||
core.getInput("flakehub-flake-name"),
|
|
||||||
]
|
|
||||||
: [])
|
|
||||||
.concat(core.getBooleanInput("use-gha-cache") ? ["--use-gha-cache"] : []);
|
|
||||||
const opts = {
|
|
||||||
stdio: ["ignore", output, output],
|
|
||||||
env: runEnv,
|
|
||||||
detached: true,
|
|
||||||
};
|
};
|
||||||
// Display the final command for debugging purposes
|
} else {
|
||||||
core.debug("Full daemon start command:");
|
runEnv = process.env;
|
||||||
core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`);
|
}
|
||||||
// Start the server. Once it is ready, it will notify us via the notification server.
|
const notifyPort = core.getInput("startup-notification-port");
|
||||||
const daemon = (0,external_node_child_process_namespaceObject.spawn)(daemonBin, daemonCliFlags, opts);
|
const notifyPromise = new Promise((resolveListening) => {
|
||||||
const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid");
|
const promise = new Promise(async (resolveQuit) => {
|
||||||
await promises_namespaceObject.writeFile(pidFile, `${daemon.pid}`);
|
const notifyServer = external_http_.createServer((req, res) => {
|
||||||
core.info("Waiting for magic-nix-cache to start...");
|
if (req.method === "POST" && req.url === "/") {
|
||||||
await new Promise((resolve, reject) => {
|
core.debug(`Notify server shutting down.`);
|
||||||
notifyPromise
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
// eslint-disable-next-line github/no-then
|
res.end("{}");
|
||||||
.then((_value) => {
|
notifyServer.close(() => {
|
||||||
resolve();
|
resolveQuit();
|
||||||
})
|
});
|
||||||
// eslint-disable-next-line github/no-then
|
}
|
||||||
.catch((err) => {
|
});
|
||||||
reject(new Error(`error in notifyPromise: ${err}`));
|
notifyServer.listen(notifyPort, () => {
|
||||||
});
|
core.debug(`Notify server running.`);
|
||||||
daemon.on("exit", async (code, signal) => {
|
resolveListening(promise);
|
||||||
if (signal) {
|
});
|
||||||
reject(new Error(`Daemon was killed by signal ${signal}`));
|
|
||||||
}
|
|
||||||
else if (code) {
|
|
||||||
reject(new Error(`Daemon exited with code ${code}`));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reject(new Error(`Daemon unexpectedly exited`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
daemon.unref();
|
});
|
||||||
core.info("Launched Magic Nix Cache");
|
const outputPath = `${daemonDir}/daemon.log`;
|
||||||
core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir);
|
const output = (0,external_node_fs_namespaceObject.openSync)(outputPath, "a");
|
||||||
log.unwatch();
|
const log = tailLog(daemonDir);
|
||||||
|
const netrc = await netrcPath();
|
||||||
|
const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`;
|
||||||
|
const daemonCliFlags = [
|
||||||
|
"--startup-notification-url",
|
||||||
|
`http://127.0.0.1:${notifyPort}`,
|
||||||
|
"--listen",
|
||||||
|
core.getInput("listen"),
|
||||||
|
"--upstream",
|
||||||
|
core.getInput("upstream-cache"),
|
||||||
|
"--diagnostic-endpoint",
|
||||||
|
core.getInput("diagnostic-endpoint"),
|
||||||
|
"--nix-conf",
|
||||||
|
nixConfPath
|
||||||
|
].concat(
|
||||||
|
core.getBooleanInput("use-flakehub") ? [
|
||||||
|
"--use-flakehub",
|
||||||
|
"--flakehub-cache-server",
|
||||||
|
core.getInput("flakehub-cache-server"),
|
||||||
|
"--flakehub-api-server",
|
||||||
|
core.getInput("flakehub-api-server"),
|
||||||
|
"--flakehub-api-server-netrc",
|
||||||
|
netrc,
|
||||||
|
"--flakehub-flake-name",
|
||||||
|
core.getInput("flakehub-flake-name")
|
||||||
|
] : []
|
||||||
|
).concat(core.getBooleanInput("use-gha-cache") ? ["--use-gha-cache"] : []);
|
||||||
|
const opts = {
|
||||||
|
stdio: ["ignore", output, output],
|
||||||
|
env: runEnv,
|
||||||
|
detached: true
|
||||||
|
};
|
||||||
|
core.debug("Full daemon start command:");
|
||||||
|
core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`);
|
||||||
|
const daemon = (0,external_node_child_process_namespaceObject.spawn)(daemonBin, daemonCliFlags, opts);
|
||||||
|
const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid");
|
||||||
|
await promises_namespaceObject.writeFile(pidFile, `${daemon.pid}`);
|
||||||
|
core.info("Waiting for magic-nix-cache to start...");
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
notifyPromise.then((_value) => {
|
||||||
|
resolve();
|
||||||
|
}).catch((err) => {
|
||||||
|
reject(new Error(`error in notifyPromise: ${err}`));
|
||||||
|
});
|
||||||
|
daemon.on("exit", async (code, signal) => {
|
||||||
|
if (signal) {
|
||||||
|
reject(new Error(`Daemon was killed by signal ${signal}`));
|
||||||
|
} else if (code) {
|
||||||
|
reject(new Error(`Daemon exited with code ${code}`));
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Daemon unexpectedly exited`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
daemon.unref();
|
||||||
|
core.info("Launched Magic Nix Cache");
|
||||||
|
core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir);
|
||||||
|
log.unwatch();
|
||||||
}
|
}
|
||||||
async function notifyAutoCache() {
|
async function notifyAutoCache() {
|
||||||
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
||||||
if (!daemonDir) {
|
if (!daemonDir) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
core.debug(`Indicating workflow start`);
|
core.debug(`Indicating workflow start`);
|
||||||
const res = await gotClient
|
const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-start`).json();
|
||||||
.post(`http://${core.getInput("listen")}/api/workflow-start`)
|
core.debug(`back from post: ${res}`);
|
||||||
.json();
|
} catch (e) {
|
||||||
core.debug(`back from post: ${res}`);
|
core.info(`Error marking the workflow as started:`);
|
||||||
}
|
core.info((0,external_node_util_.inspect)(e));
|
||||||
catch (e) {
|
core.info(`Magic Nix Cache may not be running for this workflow.`);
|
||||||
core.info(`Error marking the workflow as started:`);
|
}
|
||||||
core.info((0,external_node_util_.inspect)(e));
|
|
||||||
core.info(`Magic Nix Cache may not be running for this workflow.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async function netrcPath() {
|
async function netrcPath() {
|
||||||
const expectedNetrcPath = external_node_path_namespaceObject.join(process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(), "determinate-nix-installer-netrc");
|
const expectedNetrcPath = external_node_path_namespaceObject.join(
|
||||||
|
process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(),
|
||||||
|
"determinate-nix-installer-netrc"
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await promises_namespaceObject.access(expectedNetrcPath);
|
||||||
|
return expectedNetrcPath;
|
||||||
|
} catch {
|
||||||
|
const destinedNetrcPath = external_node_path_namespaceObject.join(
|
||||||
|
process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(),
|
||||||
|
"magic-nix-cache-netrc"
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
await promises_namespaceObject.access(expectedNetrcPath);
|
await flakehub_login(destinedNetrcPath);
|
||||||
return expectedNetrcPath;
|
} catch (e) {
|
||||||
}
|
core.info("FlakeHub cache disabled.");
|
||||||
catch {
|
core.debug(`Error while logging into FlakeHub: ${e}`);
|
||||||
// `nix-installer` was not used, the user may be registered with FlakeHub though.
|
|
||||||
const destinedNetrcPath = external_node_path_namespaceObject.join(process.env["RUNNER_TEMP"] || external_node_os_.tmpdir(), "magic-nix-cache-netrc");
|
|
||||||
try {
|
|
||||||
await flakehub_login(destinedNetrcPath);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
core.info("FlakeHub cache disabled.");
|
|
||||||
core.debug(`Error while logging into FlakeHub: ${e}`);
|
|
||||||
}
|
|
||||||
return destinedNetrcPath;
|
|
||||||
}
|
}
|
||||||
|
return destinedNetrcPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function flakehub_login(netrc) {
|
async function flakehub_login(netrc) {
|
||||||
const jwt = await core.getIDToken("api.flakehub.com");
|
const jwt = await core.getIDToken("api.flakehub.com");
|
||||||
await promises_namespaceObject.writeFile(netrc, [
|
await promises_namespaceObject.writeFile(
|
||||||
`machine api.flakehub.com login flakehub password ${jwt}`,
|
netrc,
|
||||||
`machine flakehub.com login flakehub password ${jwt}`,
|
[
|
||||||
`machine cache.flakehub.com login flakehub password ${jwt}`,
|
`machine api.flakehub.com login flakehub password ${jwt}`,
|
||||||
].join("\n"));
|
`machine flakehub.com login flakehub password ${jwt}`,
|
||||||
core.info("Logged in to FlakeHub.");
|
`machine cache.flakehub.com login flakehub password ${jwt}`
|
||||||
|
].join("\n")
|
||||||
|
);
|
||||||
|
core.info("Logged in to FlakeHub.");
|
||||||
}
|
}
|
||||||
async function tearDownAutoCache() {
|
async function tearDownAutoCache() {
|
||||||
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
||||||
if (!daemonDir) {
|
if (!daemonDir) {
|
||||||
core.debug("magic-nix-cache not started - Skipping");
|
core.debug("magic-nix-cache not started - Skipping");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid");
|
||||||
|
const pid = parseInt(await promises_namespaceObject.readFile(pidFile, { encoding: "ascii" }));
|
||||||
|
core.debug(`found daemon pid: ${pid}`);
|
||||||
|
if (!pid) {
|
||||||
|
throw new Error("magic-nix-cache did not start successfully");
|
||||||
|
}
|
||||||
|
const log = tailLog(daemonDir);
|
||||||
|
try {
|
||||||
|
core.debug(`about to post to localhost`);
|
||||||
|
const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-finish`).json();
|
||||||
|
core.debug(`back from post: ${res}`);
|
||||||
|
} finally {
|
||||||
|
core.debug(`unwatching the daemon log`);
|
||||||
|
log.unwatch();
|
||||||
|
}
|
||||||
|
core.debug(`killing`);
|
||||||
|
try {
|
||||||
|
process.kill(pid, "SIGTERM");
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") {
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
const pidFile = external_node_path_namespaceObject.join(daemonDir, "daemon.pid");
|
} finally {
|
||||||
const pid = parseInt(await promises_namespaceObject.readFile(pidFile, { encoding: "ascii" }));
|
if (core.isDebug()) {
|
||||||
core.debug(`found daemon pid: ${pid}`);
|
core.info("Entire log:");
|
||||||
if (!pid) {
|
const entireLog = (0,external_node_fs_namespaceObject.readFileSync)(external_node_path_namespaceObject.join(daemonDir, "daemon.log"));
|
||||||
throw new Error("magic-nix-cache did not start successfully");
|
core.info(entireLog.toString());
|
||||||
}
|
|
||||||
const log = tailLog(daemonDir);
|
|
||||||
try {
|
|
||||||
core.debug(`about to post to localhost`);
|
|
||||||
const res = await gotClient
|
|
||||||
.post(`http://${core.getInput("listen")}/api/workflow-finish`)
|
|
||||||
.json();
|
|
||||||
core.debug(`back from post: ${res}`);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
core.debug(`unwatching the daemon log`);
|
|
||||||
log.unwatch();
|
|
||||||
}
|
|
||||||
core.debug(`killing`);
|
|
||||||
try {
|
|
||||||
process.kill(pid, "SIGTERM");
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (core.isDebug()) {
|
|
||||||
core.info("Entire log:");
|
|
||||||
const entireLog = (0,external_node_fs_namespaceObject.readFileSync)(external_node_path_namespaceObject.join(daemonDir, "daemon.log"));
|
|
||||||
core.info(entireLog.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const idslib = new IdsToolbox({
|
var idslib = new IdsToolbox({
|
||||||
name: "magic-nix-cache",
|
name: "magic-nix-cache",
|
||||||
fetchStyle: "gh-env-style",
|
fetchStyle: "gh-env-style",
|
||||||
idsProjectName: "magic-nix-cache-closure",
|
idsProjectName: "magic-nix-cache-closure",
|
||||||
requireNix: "warn",
|
requireNix: "warn"
|
||||||
});
|
});
|
||||||
idslib.onMain(async () => {
|
idslib.onMain(async () => {
|
||||||
await setUpAutoCache(idslib);
|
await setUpAutoCache(idslib);
|
||||||
await notifyAutoCache();
|
await notifyAutoCache();
|
||||||
});
|
});
|
||||||
idslib.onPost(async () => {
|
idslib.onPost(async () => {
|
||||||
await tearDownAutoCache();
|
await tearDownAutoCache();
|
||||||
});
|
});
|
||||||
idslib.execute();
|
idslib.execute();
|
||||||
|
//# sourceMappingURL=main.js.map
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
2
dist/main.d.ts
generated
vendored
Normal file
2
dist/main.d.ts
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
export { }
|
261
dist/main.js
generated
vendored
Normal file
261
dist/main.js
generated
vendored
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
// src/main.ts
|
||||||
|
import * as fs from "node:fs/promises";
|
||||||
|
import * as os from "node:os";
|
||||||
|
import * as path from "node:path";
|
||||||
|
import { spawn, exec } from "node:child_process";
|
||||||
|
import { openSync, readFileSync } from "node:fs";
|
||||||
|
import { inspect, promisify } from "node:util";
|
||||||
|
import * as http from "http";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import { Tail } from "tail";
|
||||||
|
import got from "got";
|
||||||
|
import { IdsToolbox } from "detsys-ts";
|
||||||
|
var ENV_CACHE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR";
|
||||||
|
var gotClient = got.extend({
|
||||||
|
retry: {
|
||||||
|
limit: 1,
|
||||||
|
methods: ["POST", "GET", "PUT", "HEAD", "DELETE", "OPTIONS", "TRACE"]
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeRetry: [
|
||||||
|
(error, retryCount) => {
|
||||||
|
core.info(`Retrying after error ${error.code}, retry #: ${retryCount}`);
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
async function fetchAutoCacher(toolbox) {
|
||||||
|
const closurePath = await toolbox.fetch();
|
||||||
|
toolbox.recordEvent("load_closure");
|
||||||
|
const { stdout } = await promisify(exec)(
|
||||||
|
`cat "${closurePath}" | xz -d | nix-store --import`
|
||||||
|
);
|
||||||
|
const paths = stdout.split(os.EOL);
|
||||||
|
const last_path = paths.at(-2);
|
||||||
|
return `${last_path}/bin/magic-nix-cache`;
|
||||||
|
}
|
||||||
|
function tailLog(daemonDir) {
|
||||||
|
const log = new Tail(path.join(daemonDir, "daemon.log"));
|
||||||
|
core.debug(`tailing daemon.log...`);
|
||||||
|
log.on("line", (line) => {
|
||||||
|
core.info(line);
|
||||||
|
});
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
async function setUpAutoCache(toolbox) {
|
||||||
|
const tmpdir2 = process.env["RUNNER_TEMP"] || os.tmpdir();
|
||||||
|
const required_env = [
|
||||||
|
"ACTIONS_CACHE_URL",
|
||||||
|
"ACTIONS_RUNTIME_URL",
|
||||||
|
"ACTIONS_RUNTIME_TOKEN"
|
||||||
|
];
|
||||||
|
let anyMissing = false;
|
||||||
|
for (const n of required_env) {
|
||||||
|
if (!process.env.hasOwnProperty(n)) {
|
||||||
|
anyMissing = true;
|
||||||
|
core.warning(
|
||||||
|
`Disabling automatic caching since required environment ${n} isn't available`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anyMissing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
core.debug(`GitHub Action Cache URL: ${process.env["ACTIONS_CACHE_URL"]}`);
|
||||||
|
const daemonDir = await fs.mkdtemp(path.join(tmpdir2, "magic-nix-cache-"));
|
||||||
|
let daemonBin;
|
||||||
|
if (core.getInput("source-binary")) {
|
||||||
|
daemonBin = core.getInput("source-binary");
|
||||||
|
} else {
|
||||||
|
daemonBin = await fetchAutoCacher(toolbox);
|
||||||
|
}
|
||||||
|
let runEnv;
|
||||||
|
if (core.isDebug()) {
|
||||||
|
runEnv = {
|
||||||
|
RUST_LOG: "trace,magic_nix_cache=debug,gha_cache=debug",
|
||||||
|
RUST_BACKTRACE: "full",
|
||||||
|
...process.env
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
runEnv = process.env;
|
||||||
|
}
|
||||||
|
const notifyPort = core.getInput("startup-notification-port");
|
||||||
|
const notifyPromise = new Promise((resolveListening) => {
|
||||||
|
const promise = new Promise(async (resolveQuit) => {
|
||||||
|
const notifyServer = http.createServer((req, res) => {
|
||||||
|
if (req.method === "POST" && req.url === "/") {
|
||||||
|
core.debug(`Notify server shutting down.`);
|
||||||
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
|
res.end("{}");
|
||||||
|
notifyServer.close(() => {
|
||||||
|
resolveQuit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
notifyServer.listen(notifyPort, () => {
|
||||||
|
core.debug(`Notify server running.`);
|
||||||
|
resolveListening(promise);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const outputPath = `${daemonDir}/daemon.log`;
|
||||||
|
const output = openSync(outputPath, "a");
|
||||||
|
const log = tailLog(daemonDir);
|
||||||
|
const netrc = await netrcPath();
|
||||||
|
const nixConfPath = `${process.env["HOME"]}/.config/nix/nix.conf`;
|
||||||
|
const daemonCliFlags = [
|
||||||
|
"--startup-notification-url",
|
||||||
|
`http://127.0.0.1:${notifyPort}`,
|
||||||
|
"--listen",
|
||||||
|
core.getInput("listen"),
|
||||||
|
"--upstream",
|
||||||
|
core.getInput("upstream-cache"),
|
||||||
|
"--diagnostic-endpoint",
|
||||||
|
core.getInput("diagnostic-endpoint"),
|
||||||
|
"--nix-conf",
|
||||||
|
nixConfPath
|
||||||
|
].concat(
|
||||||
|
core.getBooleanInput("use-flakehub") ? [
|
||||||
|
"--use-flakehub",
|
||||||
|
"--flakehub-cache-server",
|
||||||
|
core.getInput("flakehub-cache-server"),
|
||||||
|
"--flakehub-api-server",
|
||||||
|
core.getInput("flakehub-api-server"),
|
||||||
|
"--flakehub-api-server-netrc",
|
||||||
|
netrc,
|
||||||
|
"--flakehub-flake-name",
|
||||||
|
core.getInput("flakehub-flake-name")
|
||||||
|
] : []
|
||||||
|
).concat(core.getBooleanInput("use-gha-cache") ? ["--use-gha-cache"] : []);
|
||||||
|
const opts = {
|
||||||
|
stdio: ["ignore", output, output],
|
||||||
|
env: runEnv,
|
||||||
|
detached: true
|
||||||
|
};
|
||||||
|
core.debug("Full daemon start command:");
|
||||||
|
core.debug(`${daemonBin} ${daemonCliFlags.join(" ")}`);
|
||||||
|
const daemon = spawn(daemonBin, daemonCliFlags, opts);
|
||||||
|
const pidFile = path.join(daemonDir, "daemon.pid");
|
||||||
|
await fs.writeFile(pidFile, `${daemon.pid}`);
|
||||||
|
core.info("Waiting for magic-nix-cache to start...");
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
notifyPromise.then((_value) => {
|
||||||
|
resolve();
|
||||||
|
}).catch((err) => {
|
||||||
|
reject(new Error(`error in notifyPromise: ${err}`));
|
||||||
|
});
|
||||||
|
daemon.on("exit", async (code, signal) => {
|
||||||
|
if (signal) {
|
||||||
|
reject(new Error(`Daemon was killed by signal ${signal}`));
|
||||||
|
} else if (code) {
|
||||||
|
reject(new Error(`Daemon exited with code ${code}`));
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Daemon unexpectedly exited`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
daemon.unref();
|
||||||
|
core.info("Launched Magic Nix Cache");
|
||||||
|
core.exportVariable(ENV_CACHE_DAEMONDIR, daemonDir);
|
||||||
|
log.unwatch();
|
||||||
|
}
|
||||||
|
async function notifyAutoCache() {
|
||||||
|
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
||||||
|
if (!daemonDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
core.debug(`Indicating workflow start`);
|
||||||
|
const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-start`).json();
|
||||||
|
core.debug(`back from post: ${res}`);
|
||||||
|
} catch (e) {
|
||||||
|
core.info(`Error marking the workflow as started:`);
|
||||||
|
core.info(inspect(e));
|
||||||
|
core.info(`Magic Nix Cache may not be running for this workflow.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function netrcPath() {
|
||||||
|
const expectedNetrcPath = path.join(
|
||||||
|
process.env["RUNNER_TEMP"] || os.tmpdir(),
|
||||||
|
"determinate-nix-installer-netrc"
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await fs.access(expectedNetrcPath);
|
||||||
|
return expectedNetrcPath;
|
||||||
|
} catch {
|
||||||
|
const destinedNetrcPath = path.join(
|
||||||
|
process.env["RUNNER_TEMP"] || os.tmpdir(),
|
||||||
|
"magic-nix-cache-netrc"
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await flakehub_login(destinedNetrcPath);
|
||||||
|
} catch (e) {
|
||||||
|
core.info("FlakeHub cache disabled.");
|
||||||
|
core.debug(`Error while logging into FlakeHub: ${e}`);
|
||||||
|
}
|
||||||
|
return destinedNetrcPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function flakehub_login(netrc) {
|
||||||
|
const jwt = await core.getIDToken("api.flakehub.com");
|
||||||
|
await fs.writeFile(
|
||||||
|
netrc,
|
||||||
|
[
|
||||||
|
`machine api.flakehub.com login flakehub password ${jwt}`,
|
||||||
|
`machine flakehub.com login flakehub password ${jwt}`,
|
||||||
|
`machine cache.flakehub.com login flakehub password ${jwt}`
|
||||||
|
].join("\n")
|
||||||
|
);
|
||||||
|
core.info("Logged in to FlakeHub.");
|
||||||
|
}
|
||||||
|
async function tearDownAutoCache() {
|
||||||
|
const daemonDir = process.env[ENV_CACHE_DAEMONDIR];
|
||||||
|
if (!daemonDir) {
|
||||||
|
core.debug("magic-nix-cache not started - Skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pidFile = path.join(daemonDir, "daemon.pid");
|
||||||
|
const pid = parseInt(await fs.readFile(pidFile, { encoding: "ascii" }));
|
||||||
|
core.debug(`found daemon pid: ${pid}`);
|
||||||
|
if (!pid) {
|
||||||
|
throw new Error("magic-nix-cache did not start successfully");
|
||||||
|
}
|
||||||
|
const log = tailLog(daemonDir);
|
||||||
|
try {
|
||||||
|
core.debug(`about to post to localhost`);
|
||||||
|
const res = await gotClient.post(`http://${core.getInput("listen")}/api/workflow-finish`).json();
|
||||||
|
core.debug(`back from post: ${res}`);
|
||||||
|
} finally {
|
||||||
|
core.debug(`unwatching the daemon log`);
|
||||||
|
log.unwatch();
|
||||||
|
}
|
||||||
|
core.debug(`killing`);
|
||||||
|
try {
|
||||||
|
process.kill(pid, "SIGTERM");
|
||||||
|
} catch (e) {
|
||||||
|
if (typeof e === "object" && e && "code" in e && e.code !== "ESRCH") {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (core.isDebug()) {
|
||||||
|
core.info("Entire log:");
|
||||||
|
const entireLog = readFileSync(path.join(daemonDir, "daemon.log"));
|
||||||
|
core.info(entireLog.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var idslib = new IdsToolbox({
|
||||||
|
name: "magic-nix-cache",
|
||||||
|
fetchStyle: "gh-env-style",
|
||||||
|
idsProjectName: "magic-nix-cache-closure",
|
||||||
|
requireNix: "warn"
|
||||||
|
});
|
||||||
|
idslib.onMain(async () => {
|
||||||
|
await setUpAutoCache(idslib);
|
||||||
|
await notifyAutoCache();
|
||||||
|
});
|
||||||
|
idslib.onPost(async () => {
|
||||||
|
await tearDownAutoCache();
|
||||||
|
});
|
||||||
|
idslib.execute();
|
||||||
|
//# sourceMappingURL=main.js.map
|
1
dist/main.js.map
generated
vendored
Normal file
1
dist/main.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -2,14 +2,14 @@
|
||||||
"name": "magic-nix-cache-action",
|
"name": "magic-nix-cache-action",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/main.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/main.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsup",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"lint": "eslint src/**/*.ts",
|
"lint": "eslint src/**/*.ts",
|
||||||
"package": "ncc build",
|
"package": "ncc build ./dist/main.js",
|
||||||
"all": "pnpm run format && pnpm run lint && pnpm run build && pnpm run package"
|
"all": "pnpm run format && pnpm run lint && pnpm run build && pnpm run package"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
|
"tsup": "^8.0.2",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1147
pnpm-lock.yaml
1147
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
15
tsup.config.ts
Normal file
15
tsup.config.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { defineConfig } from "tsup";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
name: "detsys-ts",
|
||||||
|
entry: ["src/main.ts"],
|
||||||
|
format: ["esm"],
|
||||||
|
target: "node20",
|
||||||
|
bundle: true,
|
||||||
|
splitting: false,
|
||||||
|
sourcemap: true,
|
||||||
|
clean: true,
|
||||||
|
dts: {
|
||||||
|
resolve: true,
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in a new issue