Files
nexe/tasks/build.ts
T
2025-12-07 01:30:14 -08:00

141 lines
3.8 KiB
TypeScript

import * as nexe from "../lib/nexe";
import { getUnBuiltReleases, getLatestGitRelease } from "../lib/releases";
import { runDockerBuild } from "./docker";
import { getTarget, targetsEqual, NexeTarget } from "../lib/target";
import {
pathExistsAsync,
readFileAsync,
execFileAsync,
semverGt,
} from "../lib/util";
import axios from "axios";
import FormData from "form-data";
import { cpus } from "os";
const env = process.env,
isPullRequest = env.BUILD_REASON === "PullRequest",
isWindows = process.platform === "win32",
isLinux = process.platform === "linux",
buildHost = env.AGENT_JOBNAME || (isWindows && "windows_2017_2015") || "",
isMac = process.platform === "darwin",
headers = {
Authorization: "token " + env.GITHUB_TOKEN,
"User-Agent": "nexe (https://www.npmjs.com/package/nexe)",
};
if (require.main === module) {
if (!isPullRequest) {
build().catch((x) => {
console.error(x);
process.exit(1);
});
}
}
async function build() {
const releases = await getUnBuiltReleases({ headers });
if (!releases.length) {
return;
}
const windowsBuild = releases.find((x) => x.platform === "windows"),
macBuild = releases.find((x) => x.platform === "mac"),
linux = releases.find((x) => x.platform === "linux"),
alpine = releases.find((x) => x.platform === "alpine");
let target: NexeTarget | undefined;
if (env.NEXE_VERSION) target = getTarget(env.NEXE_VERSION);
else if (isWindows) target = windowsBuild;
else if (isMac) target = macBuild;
else if (isLinux) target = linux;
if (buildHost.includes("alpine")) target = alpine;
if (!target) {
return console.log("Nothing to build...");
}
if (
isWindows &&
buildHost.includes("2017") &&
!semverGt(target.version, "9.99.99")
) {
return console.log(`Not building ${target} on this host...`);
}
if (
isWindows &&
buildHost.includes("2015") &&
semverGt(target.version, "9.99.99")
) {
return console.log(`Not building ${target} on this host...`);
}
const output = isWindows ? "./out.exe" : "./out",
options = {
mangle: false,
build: true,
verbose: Boolean(env.NEXE_VERBOSE!),
target,
make: ["-j" + cpus().length],
output,
};
console.log("Building: " + target + " on " + buildHost);
const stop = keepalive();
if (
[/*'arm7l', 'arm6l', 'arm64', */ "alpine"].includes(target.platform) &&
buildHost.includes("alpine")
) {
await runDockerBuild(target);
} else {
await nexe.compile(options);
}
stop();
if (await pathExistsAsync(output)) {
await assertNexeBinary(output);
const gitRelease = await getLatestGitRelease({ headers }),
unbuiltReleases = await getUnBuiltReleases({ headers });
if (!unbuiltReleases.some((x) => targetsEqual(x, target!))) {
console.log(`${target} already uploaded.`);
process.exit(0);
return;
}
// Create form data for file upload
const formData = new FormData();
formData.append("file", await readFileAsync(output), {
filename: target.toString(),
contentType: "application/octet-stream",
});
const uploadUrl = gitRelease.upload_url.split("{")[0];
await axios
.post(uploadUrl, formData, {
params: { name: target.toString() },
headers: {
...headers,
...formData.getHeaders(),
},
})
.catch((reason) => {
console.log(reason && reason.response && reason.response.data);
throw reason;
});
console.log(target + " uploaded.");
process.exit(0);
}
}
function keepalive() {
const keepalive = setInterval(() => console.log("Building..."), 300 * 1000);
return () => clearInterval(keepalive);
}
function assertNexeBinary(file: string) {
return execFileAsync(file).catch((e) => {
if (e && e.stack && e.stack.includes("Invalid Nexe binary")) {
return;
}
throw e;
});
}