Include env vars in the generated cache key

This commit is contained in:
Dominik Nakamura 2021-10-07 11:35:31 +09:00
parent f8f67b7515
commit 5f6b32160d
No known key found for this signature in database
GPG Key ID: E4C6A749B2491910
4 changed files with 591 additions and 558 deletions

478
dist/restore/index.js vendored
View File

@ -59507,242 +59507,252 @@ var external_os_default = /*#__PURE__*/__nccwpck_require__.n(external_os_);
var external_path_ = __nccwpck_require__(1017); var external_path_ = __nccwpck_require__(1017);
var external_path_default = /*#__PURE__*/__nccwpck_require__.n(external_path_); var external_path_default = /*#__PURE__*/__nccwpck_require__.n(external_path_);
;// CONCATENATED MODULE: ./src/common.ts ;// CONCATENATED MODULE: ./src/common.ts
process.on("uncaughtException", (e) => { process.on("uncaughtException", (e) => {
core.info(`[warning] ${e.message}`); core.info(`[warning] ${e.message}`);
if (e.stack) { if (e.stack) {
core.info(e.stack); core.info(e.stack);
} }
}); });
const cwd = core.getInput("working-directory"); const cwd = core.getInput("working-directory");
// TODO: this could be read from .cargo config file directly // TODO: this could be read from .cargo config file directly
const targetDir = core.getInput("target-dir") || "./target"; const targetDir = core.getInput("target-dir") || "./target";
if (cwd) { if (cwd) {
process.chdir(cwd); process.chdir(cwd);
} }
const stateBins = "RUST_CACHE_BINS"; const stateBins = "RUST_CACHE_BINS";
const stateKey = "RUST_CACHE_KEY"; const stateKey = "RUST_CACHE_KEY";
const stateHash = "RUST_CACHE_HASH"; const stateHash = "RUST_CACHE_HASH";
const home = external_os_default().homedir(); const home = external_os_default().homedir();
const cargoHome = process.env.CARGO_HOME || external_path_default().join(home, ".cargo"); const cargoHome = process.env.CARGO_HOME || external_path_default().join(home, ".cargo");
const paths = { const paths = {
cargoHome, cargoHome,
index: external_path_default().join(cargoHome, "registry/index"), index: external_path_default().join(cargoHome, "registry/index"),
cache: external_path_default().join(cargoHome, "registry/cache"), cache: external_path_default().join(cargoHome, "registry/cache"),
git: external_path_default().join(cargoHome, "git"), git: external_path_default().join(cargoHome, "git"),
target: targetDir, target: targetDir,
}; };
const RefKey = "GITHUB_REF"; const RefKey = "GITHUB_REF";
function isValidEvent() { function isValidEvent() {
return RefKey in process.env && Boolean(process.env[RefKey]); return RefKey in process.env && Boolean(process.env[RefKey]);
} }
async function getCacheConfig() { async function getCacheConfig() {
let lockHash = core.getState(stateHash); let lockHash = core.getState(stateHash);
if (!lockHash) { if (!lockHash) {
lockHash = await getLockfileHash(); lockHash = await getLockfileHash();
core.saveState(stateHash, lockHash); core.saveState(stateHash, lockHash);
} }
let key = `v0-rust-`; let key = `v0-rust-`;
const sharedKey = core.getInput("sharedKey"); const sharedKey = core.getInput("sharedKey");
if (sharedKey) { if (sharedKey) {
key += `${sharedKey}-`; key += `${sharedKey}-`;
} }
else { else {
const inputKey = core.getInput("key"); const inputKey = core.getInput("key");
if (inputKey) { if (inputKey) {
key += `${inputKey}-`; key += `${inputKey}-`;
} }
const job = process.env.GITHUB_JOB; const job = process.env.GITHUB_JOB;
if (job) { if (job) {
key += `${job}-`; key += `${job}-`;
} }
} }
key += await getRustKey(); key += `${getEnvKey()}-`;
return { key += await getRustKey();
paths: [ return {
external_path_default().join(cargoHome, "bin"), paths: [
external_path_default().join(cargoHome, ".crates2.json"), external_path_default().join(cargoHome, "bin"),
external_path_default().join(cargoHome, ".crates.toml"), external_path_default().join(cargoHome, ".crates2.json"),
paths.git, external_path_default().join(cargoHome, ".crates.toml"),
paths.cache, paths.git,
paths.index, paths.cache,
paths.target, paths.index,
], paths.target,
key: `${key}-${lockHash}`, ],
restoreKeys: [key], key: `${key}-${lockHash}`,
}; restoreKeys: [key],
} };
async function getCargoBins() { }
try { async function getCargoBins() {
const { installs } = JSON.parse(await external_fs_default().promises.readFile(external_path_default().join(paths.cargoHome, ".crates2.json"), "utf8")); try {
const bins = new Set(); const { installs } = JSON.parse(await external_fs_default().promises.readFile(external_path_default().join(paths.cargoHome, ".crates2.json"), "utf8"));
for (const pkg of Object.values(installs)) { const bins = new Set();
for (const bin of pkg.bins) { for (const pkg of Object.values(installs)) {
bins.add(bin); for (const bin of pkg.bins) {
} bins.add(bin);
} }
return bins; }
} return bins;
catch { }
return new Set(); catch {
} return new Set();
} }
async function getRustKey() { }
const rustc = await getRustVersion(); function getEnvKey() {
return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`; const hasher = external_crypto_default().createHash("sha1");
} for (const [key, value] of Object.entries(process.env)) {
async function getRustVersion() { if (value) {
const stdout = await getCmdOutput("rustc", ["-vV"]); hasher.update(`${key}=${value}`);
let splits = stdout }
.split(/[\n\r]+/) }
.filter(Boolean) return hasher.digest("hex").slice(0, 20);
.map((s) => s.split(":").map((s) => s.trim())) }
.filter((s) => s.length === 2); async function getRustKey() {
return Object.fromEntries(splits); const rustc = await getRustVersion();
} return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`;
async function getCmdOutput(cmd, args = [], options = {}) { }
let stdout = ""; async function getRustVersion() {
await exec.exec(cmd, args, { const stdout = await getCmdOutput("rustc", ["-vV"]);
silent: true, let splits = stdout
listeners: { .split(/[\n\r]+/)
stdout(data) { .filter(Boolean)
stdout += data.toString(); .map((s) => s.split(":").map((s) => s.trim()))
}, .filter((s) => s.length === 2);
}, return Object.fromEntries(splits);
...options, }
}); async function getCmdOutput(cmd, args = [], options = {}) {
return stdout; let stdout = "";
} await exec.exec(cmd, args, {
async function getLockfileHash() { silent: true,
const globber = await glob.create("**/Cargo.toml\n**/Cargo.lock\nrust-toolchain\nrust-toolchain.toml", { listeners: {
followSymbolicLinks: false, stdout(data) {
}); stdout += data.toString();
const files = await globber.glob(); },
files.sort((a, b) => a.localeCompare(b)); },
const hasher = external_crypto_default().createHash("sha1"); ...options,
for (const file of files) { });
for await (const chunk of external_fs_default().createReadStream(file)) { return stdout;
hasher.update(chunk); }
} async function getLockfileHash() {
} const globber = await glob.create("**/Cargo.toml\n**/Cargo.lock\nrust-toolchain\nrust-toolchain.toml", {
return hasher.digest("hex").slice(0, 20); followSymbolicLinks: false,
} });
async function getPackages() { const files = await globber.glob();
const cwd = process.cwd(); files.sort((a, b) => a.localeCompare(b));
const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1"])); const hasher = external_crypto_default().createHash("sha1");
return meta.packages for (const file of files) {
.filter((p) => !p.manifest_path.startsWith(cwd)) for await (const chunk of external_fs_default().createReadStream(file)) {
.map((p) => { hasher.update(chunk);
const targets = p.targets.filter((t) => t.kind[0] === "lib").map((t) => t.name); }
return { name: p.name, version: p.version, targets, path: external_path_default().dirname(p.manifest_path) }; }
}); return hasher.digest("hex").slice(0, 20);
} }
async function cleanTarget(packages) { async function getPackages() {
await external_fs_default().promises.unlink(external_path_default().join(targetDir, "./.rustc_info.json")); const cwd = process.cwd();
await io.rmRF(external_path_default().join(targetDir, "./debug/examples")); const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1"]));
await io.rmRF(external_path_default().join(targetDir, "./debug/incremental")); return meta.packages
let dir; .filter((p) => !p.manifest_path.startsWith(cwd))
// remove all *files* from debug .map((p) => {
dir = await external_fs_default().promises.opendir(external_path_default().join(targetDir, "./debug")); const targets = p.targets.filter((t) => t.kind[0] === "lib").map((t) => t.name);
for await (const dirent of dir) { return { name: p.name, version: p.version, targets, path: external_path_default().dirname(p.manifest_path) };
if (dirent.isFile()) { });
await rm(dir.path, dirent); }
} async function cleanTarget(packages) {
} await external_fs_default().promises.unlink(external_path_default().join(targetDir, "./.rustc_info.json"));
const keepPkg = new Set(packages.map((p) => p.name)); await io.rmRF(external_path_default().join(targetDir, "./debug/examples"));
await rmExcept(external_path_default().join(targetDir, "./debug/build"), keepPkg); await io.rmRF(external_path_default().join(targetDir, "./debug/incremental"));
await rmExcept(external_path_default().join(targetDir, "./debug/.fingerprint"), keepPkg); let dir;
const keepDeps = new Set(packages.flatMap((p) => { // remove all *files* from debug
const names = []; dir = await external_fs_default().promises.opendir(external_path_default().join(targetDir, "./debug"));
for (const n of [p.name, ...p.targets]) { for await (const dirent of dir) {
const name = n.replace(/-/g, "_"); if (dirent.isFile()) {
names.push(name, `lib${name}`); await rm(dir.path, dirent);
} }
return names; }
})); const keepPkg = new Set(packages.map((p) => p.name));
await rmExcept(external_path_default().join(targetDir, "./debug/deps"), keepDeps); await rmExcept(external_path_default().join(targetDir, "./debug/build"), keepPkg);
} await rmExcept(external_path_default().join(targetDir, "./debug/.fingerprint"), keepPkg);
const oneWeek = 7 * 24 * 3600 * 1000; const keepDeps = new Set(packages.flatMap((p) => {
async function rmExcept(dirName, keepPrefix) { const names = [];
const dir = await external_fs_default().promises.opendir(dirName); for (const n of [p.name, ...p.targets]) {
for await (const dirent of dir) { const name = n.replace(/-/g, "_");
let name = dirent.name; names.push(name, `lib${name}`);
const idx = name.lastIndexOf("-"); }
if (idx !== -1) { return names;
name = name.slice(0, idx); }));
} await rmExcept(external_path_default().join(targetDir, "./debug/deps"), keepDeps);
const fileName = external_path_default().join(dir.path, dirent.name); }
const { mtime } = await external_fs_default().promises.stat(fileName); const oneWeek = 7 * 24 * 3600 * 1000;
// we dont really know async function rmExcept(dirName, keepPrefix) {
if (!keepPrefix.has(name) || Date.now() - mtime.getTime() > oneWeek) { const dir = await external_fs_default().promises.opendir(dirName);
await rm(dir.path, dirent); for await (const dirent of dir) {
} let name = dirent.name;
} const idx = name.lastIndexOf("-");
} if (idx !== -1) {
async function rm(parent, dirent) { name = name.slice(0, idx);
try { }
const fileName = external_path_default().join(parent, dirent.name); const fileName = external_path_default().join(dir.path, dirent.name);
core.debug(`deleting "${fileName}"`); const { mtime } = await external_fs_default().promises.stat(fileName);
if (dirent.isFile()) { // we dont really know
await external_fs_default().promises.unlink(fileName); if (!keepPrefix.has(name) || Date.now() - mtime.getTime() > oneWeek) {
} await rm(dir.path, dirent);
else if (dirent.isDirectory()) { }
await io.rmRF(fileName); }
} }
} async function rm(parent, dirent) {
catch { } try {
} const fileName = external_path_default().join(parent, dirent.name);
core.debug(`deleting "${fileName}"`);
if (dirent.isFile()) {
await external_fs_default().promises.unlink(fileName);
}
else if (dirent.isDirectory()) {
await io.rmRF(fileName);
}
}
catch { }
}
;// CONCATENATED MODULE: ./src/restore.ts ;// CONCATENATED MODULE: ./src/restore.ts
async function run() { async function run() {
try { try {
var cacheOnFailure = core.getInput("cache-on-failure").toLowerCase(); var cacheOnFailure = core.getInput("cache-on-failure").toLowerCase();
if (cacheOnFailure !== "true") { if (cacheOnFailure !== "true") {
cacheOnFailure = "false"; cacheOnFailure = "false";
} }
core.exportVariable("CACHE_ON_FAILURE", cacheOnFailure); core.exportVariable("CACHE_ON_FAILURE", cacheOnFailure);
core.exportVariable("CARGO_INCREMENTAL", 0); core.exportVariable("CARGO_INCREMENTAL", 0);
const { paths, key, restoreKeys } = await getCacheConfig(); const { paths, key, restoreKeys } = await getCacheConfig();
const bins = await getCargoBins(); const bins = await getCargoBins();
core.saveState(stateBins, JSON.stringify([...bins])); core.saveState(stateBins, JSON.stringify([...bins]));
core.info(`Restoring paths:\n ${paths.join("\n ")}`); core.info(`Restoring paths:\n ${paths.join("\n ")}`);
core.info(`In directory:\n ${process.cwd()}`); core.info(`In directory:\n ${process.cwd()}`);
core.info(`Using keys:\n ${[key, ...restoreKeys].join("\n ")}`); core.info(`Using keys:\n ${[key, ...restoreKeys].join("\n ")}`);
const restoreKey = await cache.restoreCache(paths, key, restoreKeys); const restoreKey = await cache.restoreCache(paths, key, restoreKeys);
if (restoreKey) { if (restoreKey) {
core.info(`Restored from cache key "${restoreKey}".`); core.info(`Restored from cache key "${restoreKey}".`);
core.saveState(stateKey, restoreKey); core.saveState(stateKey, restoreKey);
if (restoreKey !== key) { if (restoreKey !== key) {
// pre-clean the target directory on cache mismatch // pre-clean the target directory on cache mismatch
const packages = await getPackages(); const packages = await getPackages();
await cleanTarget(packages); await cleanTarget(packages);
} }
setCacheHitOutput(restoreKey === key); setCacheHitOutput(restoreKey === key);
} }
else { else {
core.info("No cache found."); core.info("No cache found.");
setCacheHitOutput(false); setCacheHitOutput(false);
} }
} }
catch (e) { catch (e) {
setCacheHitOutput(false); setCacheHitOutput(false);
core.info(`[warning] ${e.message}`); core.info(`[warning] ${e.message}`);
} }
} }
function setCacheHitOutput(cacheHit) { function setCacheHitOutput(cacheHit) {
core.setOutput("cache-hit", cacheHit.toString()); core.setOutput("cache-hit", cacheHit.toString());
} }
run(); run();
})(); })();

656
dist/save/index.js vendored
View File

@ -59507,331 +59507,341 @@ var external_crypto_default = /*#__PURE__*/__nccwpck_require__.n(external_crypto
var external_os_ = __nccwpck_require__(2037); var external_os_ = __nccwpck_require__(2037);
var external_os_default = /*#__PURE__*/__nccwpck_require__.n(external_os_); var external_os_default = /*#__PURE__*/__nccwpck_require__.n(external_os_);
;// CONCATENATED MODULE: ./src/common.ts ;// CONCATENATED MODULE: ./src/common.ts
process.on("uncaughtException", (e) => { process.on("uncaughtException", (e) => {
core.info(`[warning] ${e.message}`); core.info(`[warning] ${e.message}`);
if (e.stack) { if (e.stack) {
core.info(e.stack); core.info(e.stack);
} }
}); });
const cwd = core.getInput("working-directory"); const cwd = core.getInput("working-directory");
// TODO: this could be read from .cargo config file directly // TODO: this could be read from .cargo config file directly
const targetDir = core.getInput("target-dir") || "./target"; const targetDir = core.getInput("target-dir") || "./target";
if (cwd) { if (cwd) {
process.chdir(cwd); process.chdir(cwd);
} }
const stateBins = "RUST_CACHE_BINS"; const stateBins = "RUST_CACHE_BINS";
const stateKey = "RUST_CACHE_KEY"; const stateKey = "RUST_CACHE_KEY";
const stateHash = "RUST_CACHE_HASH"; const stateHash = "RUST_CACHE_HASH";
const home = external_os_default().homedir(); const home = external_os_default().homedir();
const cargoHome = process.env.CARGO_HOME || external_path_default().join(home, ".cargo"); const cargoHome = process.env.CARGO_HOME || external_path_default().join(home, ".cargo");
const paths = { const paths = {
cargoHome, cargoHome,
index: external_path_default().join(cargoHome, "registry/index"), index: external_path_default().join(cargoHome, "registry/index"),
cache: external_path_default().join(cargoHome, "registry/cache"), cache: external_path_default().join(cargoHome, "registry/cache"),
git: external_path_default().join(cargoHome, "git"), git: external_path_default().join(cargoHome, "git"),
target: targetDir, target: targetDir,
}; };
const RefKey = "GITHUB_REF"; const RefKey = "GITHUB_REF";
function isValidEvent() { function isValidEvent() {
return RefKey in process.env && Boolean(process.env[RefKey]); return RefKey in process.env && Boolean(process.env[RefKey]);
} }
async function getCacheConfig() { async function getCacheConfig() {
let lockHash = core.getState(stateHash); let lockHash = core.getState(stateHash);
if (!lockHash) { if (!lockHash) {
lockHash = await getLockfileHash(); lockHash = await getLockfileHash();
core.saveState(stateHash, lockHash); core.saveState(stateHash, lockHash);
} }
let key = `v0-rust-`; let key = `v0-rust-`;
const sharedKey = core.getInput("sharedKey"); const sharedKey = core.getInput("sharedKey");
if (sharedKey) { if (sharedKey) {
key += `${sharedKey}-`; key += `${sharedKey}-`;
} }
else { else {
const inputKey = core.getInput("key"); const inputKey = core.getInput("key");
if (inputKey) { if (inputKey) {
key += `${inputKey}-`; key += `${inputKey}-`;
} }
const job = process.env.GITHUB_JOB; const job = process.env.GITHUB_JOB;
if (job) { if (job) {
key += `${job}-`; key += `${job}-`;
} }
} }
key += await getRustKey(); key += `${getEnvKey()}-`;
return { key += await getRustKey();
paths: [ return {
external_path_default().join(cargoHome, "bin"), paths: [
external_path_default().join(cargoHome, ".crates2.json"), external_path_default().join(cargoHome, "bin"),
external_path_default().join(cargoHome, ".crates.toml"), external_path_default().join(cargoHome, ".crates2.json"),
paths.git, external_path_default().join(cargoHome, ".crates.toml"),
paths.cache, paths.git,
paths.index, paths.cache,
paths.target, paths.index,
], paths.target,
key: `${key}-${lockHash}`, ],
restoreKeys: [key], key: `${key}-${lockHash}`,
}; restoreKeys: [key],
} };
async function getCargoBins() { }
try { async function getCargoBins() {
const { installs } = JSON.parse(await external_fs_default().promises.readFile(external_path_default().join(paths.cargoHome, ".crates2.json"), "utf8")); try {
const bins = new Set(); const { installs } = JSON.parse(await external_fs_default().promises.readFile(external_path_default().join(paths.cargoHome, ".crates2.json"), "utf8"));
for (const pkg of Object.values(installs)) { const bins = new Set();
for (const bin of pkg.bins) { for (const pkg of Object.values(installs)) {
bins.add(bin); for (const bin of pkg.bins) {
} bins.add(bin);
} }
return bins; }
} return bins;
catch { }
return new Set(); catch {
} return new Set();
} }
async function getRustKey() { }
const rustc = await getRustVersion(); function getEnvKey() {
return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`; const hasher = external_crypto_default().createHash("sha1");
} for (const [key, value] of Object.entries(process.env)) {
async function getRustVersion() { if (value) {
const stdout = await getCmdOutput("rustc", ["-vV"]); hasher.update(`${key}=${value}`);
let splits = stdout }
.split(/[\n\r]+/) }
.filter(Boolean) return hasher.digest("hex").slice(0, 20);
.map((s) => s.split(":").map((s) => s.trim())) }
.filter((s) => s.length === 2); async function getRustKey() {
return Object.fromEntries(splits); const rustc = await getRustVersion();
} return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`;
async function getCmdOutput(cmd, args = [], options = {}) { }
let stdout = ""; async function getRustVersion() {
await exec.exec(cmd, args, { const stdout = await getCmdOutput("rustc", ["-vV"]);
silent: true, let splits = stdout
listeners: { .split(/[\n\r]+/)
stdout(data) { .filter(Boolean)
stdout += data.toString(); .map((s) => s.split(":").map((s) => s.trim()))
}, .filter((s) => s.length === 2);
}, return Object.fromEntries(splits);
...options, }
}); async function getCmdOutput(cmd, args = [], options = {}) {
return stdout; let stdout = "";
} await exec.exec(cmd, args, {
async function getLockfileHash() { silent: true,
const globber = await glob.create("**/Cargo.toml\n**/Cargo.lock\nrust-toolchain\nrust-toolchain.toml", { listeners: {
followSymbolicLinks: false, stdout(data) {
}); stdout += data.toString();
const files = await globber.glob(); },
files.sort((a, b) => a.localeCompare(b)); },
const hasher = external_crypto_default().createHash("sha1"); ...options,
for (const file of files) { });
for await (const chunk of external_fs_default().createReadStream(file)) { return stdout;
hasher.update(chunk); }
} async function getLockfileHash() {
} const globber = await glob.create("**/Cargo.toml\n**/Cargo.lock\nrust-toolchain\nrust-toolchain.toml", {
return hasher.digest("hex").slice(0, 20); followSymbolicLinks: false,
} });
async function getPackages() { const files = await globber.glob();
const cwd = process.cwd(); files.sort((a, b) => a.localeCompare(b));
const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1"])); const hasher = external_crypto_default().createHash("sha1");
return meta.packages for (const file of files) {
.filter((p) => !p.manifest_path.startsWith(cwd)) for await (const chunk of external_fs_default().createReadStream(file)) {
.map((p) => { hasher.update(chunk);
const targets = p.targets.filter((t) => t.kind[0] === "lib").map((t) => t.name); }
return { name: p.name, version: p.version, targets, path: external_path_default().dirname(p.manifest_path) }; }
}); return hasher.digest("hex").slice(0, 20);
} }
async function cleanTarget(packages) { async function getPackages() {
await external_fs_default().promises.unlink(external_path_default().join(targetDir, "./.rustc_info.json")); const cwd = process.cwd();
await io.rmRF(external_path_default().join(targetDir, "./debug/examples")); const meta = JSON.parse(await getCmdOutput("cargo", ["metadata", "--all-features", "--format-version", "1"]));
await io.rmRF(external_path_default().join(targetDir, "./debug/incremental")); return meta.packages
let dir; .filter((p) => !p.manifest_path.startsWith(cwd))
// remove all *files* from debug .map((p) => {
dir = await external_fs_default().promises.opendir(external_path_default().join(targetDir, "./debug")); const targets = p.targets.filter((t) => t.kind[0] === "lib").map((t) => t.name);
for await (const dirent of dir) { return { name: p.name, version: p.version, targets, path: external_path_default().dirname(p.manifest_path) };
if (dirent.isFile()) { });
await rm(dir.path, dirent); }
} async function cleanTarget(packages) {
} await external_fs_default().promises.unlink(external_path_default().join(targetDir, "./.rustc_info.json"));
const keepPkg = new Set(packages.map((p) => p.name)); await io.rmRF(external_path_default().join(targetDir, "./debug/examples"));
await rmExcept(external_path_default().join(targetDir, "./debug/build"), keepPkg); await io.rmRF(external_path_default().join(targetDir, "./debug/incremental"));
await rmExcept(external_path_default().join(targetDir, "./debug/.fingerprint"), keepPkg); let dir;
const keepDeps = new Set(packages.flatMap((p) => { // remove all *files* from debug
const names = []; dir = await external_fs_default().promises.opendir(external_path_default().join(targetDir, "./debug"));
for (const n of [p.name, ...p.targets]) { for await (const dirent of dir) {
const name = n.replace(/-/g, "_"); if (dirent.isFile()) {
names.push(name, `lib${name}`); await rm(dir.path, dirent);
} }
return names; }
})); const keepPkg = new Set(packages.map((p) => p.name));
await rmExcept(external_path_default().join(targetDir, "./debug/deps"), keepDeps); await rmExcept(external_path_default().join(targetDir, "./debug/build"), keepPkg);
} await rmExcept(external_path_default().join(targetDir, "./debug/.fingerprint"), keepPkg);
const oneWeek = 7 * 24 * 3600 * 1000; const keepDeps = new Set(packages.flatMap((p) => {
async function rmExcept(dirName, keepPrefix) { const names = [];
const dir = await external_fs_default().promises.opendir(dirName); for (const n of [p.name, ...p.targets]) {
for await (const dirent of dir) { const name = n.replace(/-/g, "_");
let name = dirent.name; names.push(name, `lib${name}`);
const idx = name.lastIndexOf("-"); }
if (idx !== -1) { return names;
name = name.slice(0, idx); }));
} await rmExcept(external_path_default().join(targetDir, "./debug/deps"), keepDeps);
const fileName = external_path_default().join(dir.path, dirent.name); }
const { mtime } = await external_fs_default().promises.stat(fileName); const oneWeek = 7 * 24 * 3600 * 1000;
// we dont really know async function rmExcept(dirName, keepPrefix) {
if (!keepPrefix.has(name) || Date.now() - mtime.getTime() > oneWeek) { const dir = await external_fs_default().promises.opendir(dirName);
await rm(dir.path, dirent); for await (const dirent of dir) {
} let name = dirent.name;
} const idx = name.lastIndexOf("-");
} if (idx !== -1) {
async function rm(parent, dirent) { name = name.slice(0, idx);
try { }
const fileName = external_path_default().join(parent, dirent.name); const fileName = external_path_default().join(dir.path, dirent.name);
core.debug(`deleting "${fileName}"`); const { mtime } = await external_fs_default().promises.stat(fileName);
if (dirent.isFile()) { // we dont really know
await external_fs_default().promises.unlink(fileName); if (!keepPrefix.has(name) || Date.now() - mtime.getTime() > oneWeek) {
} await rm(dir.path, dirent);
else if (dirent.isDirectory()) { }
await io.rmRF(fileName); }
} }
} async function rm(parent, dirent) {
catch { } try {
} const fileName = external_path_default().join(parent, dirent.name);
core.debug(`deleting "${fileName}"`);
if (dirent.isFile()) {
await external_fs_default().promises.unlink(fileName);
}
else if (dirent.isDirectory()) {
await io.rmRF(fileName);
}
}
catch { }
}
;// CONCATENATED MODULE: ./src/save.ts ;// CONCATENATED MODULE: ./src/save.ts
async function run() { async function run() {
try { try {
const { paths: savePaths, key } = await getCacheConfig(); const { paths: savePaths, key } = await getCacheConfig();
if (core.getState(stateKey) === key) { if (core.getState(stateKey) === key) {
core.info(`Cache up-to-date.`); core.info(`Cache up-to-date.`);
return; return;
} }
// TODO: remove this once https://github.com/actions/toolkit/pull/553 lands // TODO: remove this once https://github.com/actions/toolkit/pull/553 lands
await macOsWorkaround(); await macOsWorkaround();
const registryName = await getRegistryName(); const registryName = await getRegistryName();
const packages = await getPackages(); const packages = await getPackages();
try { try {
await cleanRegistry(registryName, packages); await cleanRegistry(registryName, packages);
} }
catch { } catch { }
try { try {
await cleanBin(); await cleanBin();
} }
catch { } catch { }
try { try {
await cleanGit(packages); await cleanGit(packages);
} }
catch { } catch { }
try { try {
await cleanTarget(packages); await cleanTarget(packages);
} }
catch { } catch { }
core.info(`Saving paths:\n ${savePaths.join("\n ")}`); core.info(`Saving paths:\n ${savePaths.join("\n ")}`);
core.info(`In directory:\n ${process.cwd()}`); core.info(`In directory:\n ${process.cwd()}`);
core.info(`Using key:\n ${key}`); core.info(`Using key:\n ${key}`);
await cache.saveCache(savePaths, key); await cache.saveCache(savePaths, key);
} }
catch (e) { catch (e) {
core.info(`[warning] ${e.message}`); core.info(`[warning] ${e.message}`);
} }
} }
run(); run();
async function getRegistryName() { async function getRegistryName() {
const globber = await glob.create(`${paths.index}/**/.last-updated`, { followSymbolicLinks: false }); const globber = await glob.create(`${paths.index}/**/.last-updated`, { followSymbolicLinks: false });
const files = await globber.glob(); const files = await globber.glob();
if (files.length > 1) { if (files.length > 1) {
core.warning(`got multiple registries: "${files.join('", "')}"`); core.warning(`got multiple registries: "${files.join('", "')}"`);
} }
const first = files.shift(); const first = files.shift();
return external_path_default().basename(external_path_default().dirname(first)); return external_path_default().basename(external_path_default().dirname(first));
} }
async function cleanBin() { async function cleanBin() {
const bins = await getCargoBins(); const bins = await getCargoBins();
const oldBins = JSON.parse(core.getState(stateBins)); const oldBins = JSON.parse(core.getState(stateBins));
for (const bin of oldBins) { for (const bin of oldBins) {
bins.delete(bin); bins.delete(bin);
} }
const dir = await external_fs_default().promises.opendir(external_path_default().join(paths.cargoHome, "bin")); const dir = await external_fs_default().promises.opendir(external_path_default().join(paths.cargoHome, "bin"));
for await (const dirent of dir) { for await (const dirent of dir) {
if (dirent.isFile() && !bins.has(dirent.name)) { if (dirent.isFile() && !bins.has(dirent.name)) {
await rm(dir.path, dirent); await rm(dir.path, dirent);
} }
} }
} }
async function cleanRegistry(registryName, packages) { async function cleanRegistry(registryName, packages) {
await io.rmRF(external_path_default().join(paths.index, registryName, ".cache")); await io.rmRF(external_path_default().join(paths.index, registryName, ".cache"));
const pkgSet = new Set(packages.map((p) => `${p.name}-${p.version}.crate`)); const pkgSet = new Set(packages.map((p) => `${p.name}-${p.version}.crate`));
const dir = await external_fs_default().promises.opendir(external_path_default().join(paths.cache, registryName)); const dir = await external_fs_default().promises.opendir(external_path_default().join(paths.cache, registryName));
for await (const dirent of dir) { for await (const dirent of dir) {
if (dirent.isFile() && !pkgSet.has(dirent.name)) { if (dirent.isFile() && !pkgSet.has(dirent.name)) {
await rm(dir.path, dirent); await rm(dir.path, dirent);
} }
} }
} }
async function cleanGit(packages) { async function cleanGit(packages) {
const coPath = external_path_default().join(paths.git, "checkouts"); const coPath = external_path_default().join(paths.git, "checkouts");
const dbPath = external_path_default().join(paths.git, "db"); const dbPath = external_path_default().join(paths.git, "db");
const repos = new Map(); const repos = new Map();
for (const p of packages) { for (const p of packages) {
if (!p.path.startsWith(coPath)) { if (!p.path.startsWith(coPath)) {
continue; continue;
} }
const [repo, ref] = p.path.slice(coPath.length + 1).split((external_path_default()).sep); const [repo, ref] = p.path.slice(coPath.length + 1).split((external_path_default()).sep);
const refs = repos.get(repo); const refs = repos.get(repo);
if (refs) { if (refs) {
refs.add(ref); refs.add(ref);
} }
else { else {
repos.set(repo, new Set([ref])); repos.set(repo, new Set([ref]));
} }
} }
// we have to keep both the clone, and the checkout, removing either will // we have to keep both the clone, and the checkout, removing either will
// trigger a rebuild // trigger a rebuild
let dir; let dir;
// clean the db // clean the db
dir = await external_fs_default().promises.opendir(dbPath); dir = await external_fs_default().promises.opendir(dbPath);
for await (const dirent of dir) { for await (const dirent of dir) {
if (!repos.has(dirent.name)) { if (!repos.has(dirent.name)) {
await rm(dir.path, dirent); await rm(dir.path, dirent);
} }
} }
// clean the checkouts // clean the checkouts
dir = await external_fs_default().promises.opendir(coPath); dir = await external_fs_default().promises.opendir(coPath);
for await (const dirent of dir) { for await (const dirent of dir) {
const refs = repos.get(dirent.name); const refs = repos.get(dirent.name);
if (!refs) { if (!refs) {
await rm(dir.path, dirent); await rm(dir.path, dirent);
continue; continue;
} }
if (!dirent.isDirectory()) { if (!dirent.isDirectory()) {
continue; continue;
} }
const refsDir = await external_fs_default().promises.opendir(external_path_default().join(dir.path, dirent.name)); const refsDir = await external_fs_default().promises.opendir(external_path_default().join(dir.path, dirent.name));
for await (const dirent of refsDir) { for await (const dirent of refsDir) {
if (!refs.has(dirent.name)) { if (!refs.has(dirent.name)) {
await rm(refsDir.path, dirent); await rm(refsDir.path, dirent);
} }
} }
} }
} }
async function macOsWorkaround() { async function macOsWorkaround() {
try { try {
// Workaround for https://github.com/actions/cache/issues/403 // Workaround for https://github.com/actions/cache/issues/403
// Also see https://github.com/rust-lang/cargo/issues/8603 // Also see https://github.com/rust-lang/cargo/issues/8603
await exec.exec("sudo", ["/usr/sbin/purge"], { silent: true }); await exec.exec("sudo", ["/usr/sbin/purge"], { silent: true });
} }
catch { } catch { }
} }
})(); })();

1
package-lock.json generated
View File

@ -5,6 +5,7 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "rust-cache",
"version": "1.2.0", "version": "1.2.0",
"license": "LGPL-3.0", "license": "LGPL-3.0",
"dependencies": { "dependencies": {

View File

@ -71,6 +71,7 @@ export async function getCacheConfig(): Promise<CacheConfig> {
} }
} }
key += `${getEnvKey()}-`;
key += await getRustKey(); key += await getRustKey();
return { return {
@ -105,6 +106,17 @@ export async function getCargoBins(): Promise<Set<string>> {
} }
} }
function getEnvKey(): string {
const hasher = crypto.createHash("sha1");
for (const [key, value] of Object.entries(process.env)) {
if (value) {
hasher.update(`${key}=${value}`);
}
}
return hasher.digest("hex").slice(0, 20);
}
async function getRustKey(): Promise<string> { async function getRustKey(): Promise<string> {
const rustc = await getRustVersion(); const rustc = await getRustVersion();
return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`; return `${rustc.release}-${rustc.host}-${rustc["commit-hash"].slice(0, 12)}`;
@ -249,5 +261,5 @@ export async function rm(parent: string, dirent: fs.Dirent) {
} else if (dirent.isDirectory()) { } else if (dirent.isDirectory()) {
await io.rmRF(fileName); await io.rmRF(fileName);
} }
} catch {} } catch { }
} }