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
54 changes: 54 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
on: [workflow_dispatch]
jobs:
test-from-project:
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v6
with: { fetch-depth: 0 }
- name: 'Create build.zig.zon'
run: |
cat >build.zig.zon <<EOF
.{
.name = "test-project"
.version = "0.0.0",
.minimum_zig_version = "0.13.0",
.paths = .{""},
.fingerprint = 0x43eaf07faceda5c3,
}
EOF
- name: 'Setup Zig'
uses: ./
with: { version: '0.13.0' }
- name: 'Check `zig version`'
run: |
if [ "$(zig version)" != '0.13.0' ]; then
echo "version mismatch: expected '0.13.0', got '$(zig version)'"
exit 1
fi
test:
runs-on: ubuntu-latest
strategy:
matrix:
zig_version:
- 'master'
- 'latest'
- '2024.5.0-mach'
- '0.14.0'
- '0.14.1' # zig-linux-x86_64 -> zig-x86_64-linux
- '0.15.0'
- '0.15.1' # armv7a -> arm (though testing on ARM is TODO!)
- '0.15.2' # some x.x.2
steps:
- name: 'Checkout'
uses: actions/checkout@v6
with: { fetch-depth: 0 }
- name: 'Setup Zig'
uses: ./
with: { version: '${{ matrix.zig_version }}' }
- name: 'Test `zig init`'
run: |
mkdir init
cd init
zig init
zig build test
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ be https://ziglang.org/download to avoid the official website being hit with lar
If you've experienced issues with a default mirror, please [open an issue][report-bad-mirror] on the Zig
website repository, which is where the list of mirrors is maintained.

If necessary, the caching of the global Zig cache directory can be disabled by setting the option
If necessary, the caching of the global and local Zig cache directories can be disabled by setting the option
`use-cache: false`. Don't do this without reason: preserving the Zig cache will typically speed things up
and decrease the load on GitHub's runners.

Expand Down Expand Up @@ -82,4 +82,4 @@ ziglang.org is used. If you are interested in hosting a mirror of your own, chec
setup-zig, but also any other tooling which wants to fetch Zig!

[mirrors]: https://ziglang.org/download/community-mirrors/
[host-mirror]: https://github.com/ziglang/www.ziglang.org/blob/main/MIRRORS.md
[host-mirror]: https://github.com/ziglang/www.ziglang.org/blob/main/MIRRORS.md
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ inputs:
required: false
default: ''
use-cache:
description: 'Whether to cache the global Zig cache directory.'
description: 'Whether to cache the global and local Zig cache directories.'
required: true
default: true
cache-key:
Expand Down
142 changes: 48 additions & 94 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ const CACHE_PREFIX = "setup-zig-global-cache-";
// 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*"(.*?)"/;
// This is tied quite precisely to the output of `zig env`. It's just a temporary workaround until
// I get around to implementing a ZON parser here.
const ZIG_ENV_CACHE_DIR_REGEX = /^\s*\.global_cache_dir = "(.*)",$/m;

let _cached_version = null;
async function getVersion() {
Expand Down Expand Up @@ -116,7 +113,7 @@ async function getTarballName() {
const version = await getVersion();

let arch = {
arm: 'armv7a',
arm: 'arm',
arm64: 'aarch64',
loong64: 'loongarch64',
mips: 'mips',
Expand All @@ -137,119 +134,77 @@ async function getTarballName() {
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 = {
aix: 'aix',
android: 'android',
freebsd: 'freebsd',
sunos: 'illumos',
linux: 'linux',
darwin: 'macos',
netbsd: 'netbsd',
openbsd: 'openbsd',
sunos: 'solaris',
win32: 'windows',
}[os.platform()];

if (useLegacyTarballName(version)) {
// 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}`;
} else {
return `zig-${arch}-${platform}-${version}`;
}

return `zig-${arch}-${platform}-${version}`;
}
// Before version 0.14.1 / dev version 0.15.0-dev.631+9a3540d61, Zig tarballs were named like:
// `zig-linux-x86_64-0.14.0`
// After that version, they are named like:
// `zig-x86_64-linux-0.14.0`
// So, the architecture and OS fields were flipped to align with how target triples work.
function useLegacyTarballName(version) {
// We are looking for full versions above
const parts = version.split('.');
if (parts.length == 3) {
// We have a full version like '0.14.0'
if (parts[0] !== "0") return false; // 1.x.x or greater
if (parts[1] === "14" && parts[2] !== "0") return false; // 0.14.1 or greater
const minor = parseInt(parts[1]);
if (!Number.isFinite(minor)) return false; // malformed minor version
if (minor >= 15) return false; // 0.15.x or greater
return true; // 0.14.1
} else if (parts.length == 4) {
// We have a dev version like '0.15.0-dev.631+9a3540d61'
if (parts[0] !== "0") return false; // 1.x.x or greater
if (parts[1] === "15" && parts[2] == "0-dev") {
const dev_version = parseInt(parts[3].split('+')[0]); // this is the '631' part in the example above
if (!Number.isFinite(dev_version)) return false; // malformed dev version
if (dev_version >= 631) return false; // 0.15.0-dev.631+9a3540d61 or greater
return true; // 0.15.0-dev before the change
}
const minor = parseInt(parts[1]);
if (!Number.isFinite(minor)) return false; // malformed minor version
if (minor >= 15) return false; // 0.15.1-dev or greater (in practice this is 0.16.0-dev or greater)
return true; // We caught 0.15.0-dev above, so this must be 0.14.x-dev or below.
} else {
// Malformed version
return false;
}

// 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;
}

async function getTarballExt() {
// 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 {
linux: '.tar.xz',
darwin: '.tar.xz',
win32: '.zip',
}[os.platform()];
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-${job_name}-${tarball_name}-${user_key}-`;
}

async function getZigCachePath() {
const env_zon = (await exec.getExecOutput('zig', ['env'])).stdout;
if (env_zon[0] !== '.') {
// JSON (legacy)
return JSON.parse(env_zon)['global_cache_dir'];
}
const match = ZIG_ENV_CACHE_DIR_REGEX.exec(env_zon);
if (!match) throw new Error("Failed to parse cache directory from 'zig env' output");
return parseZigString(match[1]);
}
function parseZigString(raw) {
// This function is neither complete (Unicode codepoint literals), nor correct (byte-escapes
// aren't really compatible with JS "strings"). It's just a temporary best-effort implementation
// which can hopefully handle any real-world directory path we encounter.
let result = "";
let i = 0;
while (i < raw.length) {
if (raw[i] != '\\') {
result += raw[i];
i += 1;
continue;
}
i += 2;
switch (raw[i - 1]) {
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case '\\': result += '\\'; break;
case 't': result += '\t'; break;
case '\'': result += '\''; break;
case '"': result += '"'; break;
case 'x': {
const byte_val = parseInt(raw.slice(i, i + 2), 16);
result += String.fromCharCode(byte_val);
i += 2;
break;
}
case 'u': throw new Error("unsupported Unicode codepoint literal in string");
default: throw new Error("invalid escape code in string");
}
}
return result;
return `setup-zig-cache-v2-${job_name}-${tarball_name}-${user_key}-`;
}

async function getTarballCachePath() {
return path.join(process.env['RUNNER_TEMP'], await getTarballName());
function getZigCachePath() {
return path.join(process.env['GITHUB_WORKSPACE'] ?? process.cwd(), '.zig-cache');
}

module.exports = {
Expand All @@ -258,5 +213,4 @@ module.exports = {
getTarballExt,
getCachePrefix,
getZigCachePath,
getTarballCachePath,
};
Loading
Loading