217 lines
6.5 KiB
JavaScript
217 lines
6.5 KiB
JavaScript
const os = require('os');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const core = require('@actions/core');
|
|
const github = require('@actions/github');
|
|
const exec = require('@actions/exec');
|
|
|
|
const VERSIONS_JSON = 'https://ziglang.org/download/index.json';
|
|
const MACH_VERSIONS_JSON = 'https://pkg.machengine.org/zig/index.json';
|
|
const CACHE_PREFIX = "setup-zig-global-cache-";
|
|
|
|
// The following regexes pull specific values out of ZON.
|
|
// This is bad and should be replaced with an actual parser -- see #50.
|
|
|
|
// Mach uses `mach_zig_version` in `build.zig.zon` to signify Mach nominated versions.
|
|
// See: https://github.com/marler8997/anyzig?tab=readme-ov-file#mach-versions-and-download-mirror
|
|
const MACH_ZIG_VERSION_REGEX = /\.\s*mach_zig_version\s*=\s*"(.*?)"/;
|
|
const MINIMUM_ZIG_VERSION_REGEX = /\.\s*minimum_zig_version\s*=\s*"(.*?)"/;
|
|
|
|
let _cached_version = null;
|
|
async function getVersion() {
|
|
if (_cached_version != null) {
|
|
return _cached_version;
|
|
}
|
|
|
|
let raw = core.getInput('version');
|
|
if (raw === '') {
|
|
try {
|
|
const zon = await fs.promises.readFile('build.zig.zon', 'utf8');
|
|
|
|
// Look for `mach_zig_version` first
|
|
let match = MACH_ZIG_VERSION_REGEX.exec(zon);
|
|
if (match !== null) {
|
|
_cached_version = await getMachVersion(match[1]);
|
|
return _cached_version;
|
|
}
|
|
|
|
// Else, look for `minimum_zig_version`
|
|
match = MINIMUM_ZIG_VERSION_REGEX.exec(zon);
|
|
if (match !== null) {
|
|
_cached_version = match[1];
|
|
return _cached_version;
|
|
}
|
|
|
|
core.info('Failed to find `mach_zig_version` or `minimum_zig_version` in build.zig.zon (using latest)');
|
|
} catch (e) {
|
|
core.info(`Failed to read build.zig.zon (using latest): ${e}`);
|
|
}
|
|
|
|
raw = 'latest';
|
|
}
|
|
|
|
if (raw === 'master') {
|
|
_cached_version = await getMasterVersion();
|
|
} else if (raw === 'latest') {
|
|
_cached_version = await getLatestVersion();
|
|
} else if (raw.includes("mach")) {
|
|
_cached_version = await getMachVersion(raw);
|
|
} else {
|
|
_cached_version = raw;
|
|
}
|
|
|
|
return _cached_version;
|
|
}
|
|
|
|
async function getMachVersion(raw) {
|
|
const resp = await fetch(MACH_VERSIONS_JSON);
|
|
const versions = await resp.json();
|
|
if (!(raw in versions)) {
|
|
throw new Error(`Mach nominated version '${raw}' not found`);
|
|
}
|
|
return versions[raw].version;
|
|
}
|
|
async function getMasterVersion() {
|
|
const resp = await fetch(VERSIONS_JSON);
|
|
const versions = await resp.json();
|
|
return versions['master'].version;
|
|
}
|
|
async function getLatestVersion() {
|
|
const resp = await fetch(VERSIONS_JSON);
|
|
const versions = await resp.json();
|
|
let latest = null;
|
|
let latest_major;
|
|
let latest_minor;
|
|
let latest_patch;
|
|
for (const version in versions) {
|
|
if (version === 'master') continue;
|
|
const [major_str, minor_str, patch_str] = version.split('.')
|
|
const major = Number(major_str);
|
|
const minor = Number(minor_str);
|
|
const patch = Number(patch_str);
|
|
if (latest === null) {
|
|
latest = version;
|
|
latest_major = major;
|
|
latest_minor = minor;
|
|
latest_patch = patch;
|
|
continue;
|
|
}
|
|
if (major > latest_major ||
|
|
(major == latest_major && minor > latest_minor) ||
|
|
(major == latest_major && minor == latest_minor && patch > latest_patch))
|
|
{
|
|
latest = version;
|
|
latest_major = major;
|
|
latest_minor = minor;
|
|
latest_patch = patch;
|
|
}
|
|
}
|
|
return latest;
|
|
}
|
|
|
|
async function getTarballName() {
|
|
const version = await getVersion();
|
|
|
|
let arch = {
|
|
arm: 'arm',
|
|
arm64: 'aarch64',
|
|
loong64: 'loongarch64',
|
|
mips: 'mips',
|
|
mipsel: 'mipsel',
|
|
mips64: 'mips64',
|
|
mips64el: 'mips64el',
|
|
ppc64: 'powerpc64',
|
|
riscv64: 'riscv64',
|
|
s390x: 's390x',
|
|
ia32: 'x86',
|
|
x64: 'x86_64',
|
|
}[os.arch()];
|
|
|
|
// For some incomprehensible reason, Node.js's brain-damaged build system explicitly throws away
|
|
// the knowledge that it is building for ppc64le, so os.arch() will identify it as ppc64 even on
|
|
// little endian.
|
|
if (arch === 'powerpc64' && os.endianness() === 'LE') {
|
|
arch = 'powerpc64le';
|
|
}
|
|
|
|
// Before 0.15.1, Zig used 'armv7a' as the arch name for ARM binaries.
|
|
if (arch === 'arm' && versionLessThan(version, "0.15.1")) {
|
|
arch = 'armv7a';
|
|
}
|
|
|
|
const platform = {
|
|
android: 'android',
|
|
freebsd: 'freebsd',
|
|
sunos: 'illumos',
|
|
linux: 'linux',
|
|
darwin: 'macos',
|
|
netbsd: 'netbsd',
|
|
openbsd: 'openbsd',
|
|
win32: 'windows',
|
|
}[os.platform()];
|
|
|
|
// Before 0.14.1, Zig tarballs were named like 'zig-linux-x86_64-0.14.0', with the arch
|
|
// and OS fields reversed from the order we use today.
|
|
if (versionLessThan(version, "0.15.0-dev.631+9a3540d61") && versionLessThan(version, "0.14.1")) {
|
|
return `zig-${platform}-${arch}-${version}`;
|
|
}
|
|
|
|
return `zig-${arch}-${platform}-${version}`;
|
|
}
|
|
|
|
// Returns `true` if `cur_ver` represents a version less then (i.e. older than) `min_ver`.
|
|
// Otherwise, returns `false`.
|
|
// If `cur_ver` or `min_ver` is malformed, returns `false`.
|
|
function versionLessThan(cur_ver, min_ver) {
|
|
const cur = parseVersion(cur_ver);
|
|
const min = parseVersion(min_ver);
|
|
if (cur === null || min === null) return false;
|
|
// Treating 0.1.2 as 0.1.2-dev+INF makes the comparisons easy!
|
|
const cur_dev = cur.dev === null ? Infinity : cur.dev;
|
|
const min_dev = min.dev === null ? Infinity : min.dev;
|
|
|
|
if (cur.major != min.major) return cur.major < min.major;
|
|
if (cur.minor != min.minor) return cur.minor < min.minor;
|
|
if (cur.patch != min.patch) return cur.patch < min.patch;
|
|
return cur.dev < min.dev;
|
|
}
|
|
|
|
// Returns object with keys 'major', 'minor', 'patch', and 'dev'.
|
|
// 'dev' is `null` if `str` was not a dev version.
|
|
// On failure, returns `null`.
|
|
function parseVersion(str) {
|
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:-dev\.(\d+)\+[0-9a-f]*)?$/.exec(str);
|
|
if (match === null) return null;
|
|
return {
|
|
major: parseInt(match[0]),
|
|
minor: parseInt(match[1]),
|
|
patch: parseInt(match[2]),
|
|
dev: match[3] === null ? null : parseInt(match[3]),
|
|
};
|
|
}
|
|
|
|
async function getTarballExt() {
|
|
if (os.platform() == 'win32') return '.zip';
|
|
return '.tar.xz';
|
|
}
|
|
|
|
async function getCachePrefix() {
|
|
const tarball_name = await getTarballName();
|
|
const job_name = github.context.job.replaceAll(/[^\w]/g, "_");
|
|
const user_key = core.getInput('cache-key');
|
|
|
|
return `setup-zig-cache-v2-${job_name}-${tarball_name}-${user_key}-`;
|
|
}
|
|
|
|
function getZigCachePath() {
|
|
return path.join(process.env['GITHUB_WORKSPACE'] ?? process.cwd(), '.zig-cache');
|
|
}
|
|
|
|
module.exports = {
|
|
getVersion,
|
|
getTarballName,
|
|
getTarballExt,
|
|
getCachePrefix,
|
|
getZigCachePath,
|
|
};
|