3
0
Fork 0
mirror of https://github.com/Swatinem/rust-cache synced 2026-06-26 02:00:35 +00:00

Add source-keyed target cache

This commit is contained in:
Gary Sassano 2026-06-14 00:45:34 +02:00
parent c106961fee
commit c020f6afef
No known key found for this signature in database
GPG key ID: F8FE82821AD22F8F
12 changed files with 420 additions and 141 deletions

View file

@ -1,4 +1,4 @@
import { f as debug, m as getDefaultExportFromCjs, n as mkdirP, l as exec, w as which, o as warning, i as info, H as HttpCodes, p as HttpClientError, q as HttpClient, t as isDebug, u as setSecret, B as BearerCredentialHandler, e as error } from './cleanup-ChNUL7jL.js';
import { f as debug, m as getDefaultExportFromCjs, n as mkdirP, l as exec, w as which, o as warning, i as info, H as HttpCodes, p as HttpClientError, q as HttpClient, t as isDebug, u as setSecret, B as BearerCredentialHandler, e as error } from './cleanup-ctNqmXyy.js';
import * as path from 'path';
import * as fs from 'fs';
import { writeFileSync, existsSync } from 'fs';

View file

@ -1,4 +1,4 @@
import { v as commonjsGlobal, x as requireTunnel, m as getDefaultExportFromCjs, y as getAugmentedNamespace } from './cleanup-ChNUL7jL.js';
import { v as commonjsGlobal, x as requireTunnel, m as getDefaultExportFromCjs, y as getAugmentedNamespace } from './cleanup-ctNqmXyy.js';
import os__default from 'os';
import crypto__default from 'crypto';
import fs__default from 'fs';

View file

@ -34120,10 +34120,10 @@ async function getCacheProvider() {
let cache;
switch (cacheProvider) {
case "github":
cache = await import('./cache-Cb-Up9r2.js');
cache = await import('./cache-BSoAyDaq.js');
break;
case "warpbuild":
cache = await import('./cache-1jS6aShy.js').then(function (n) { return n.c; });
cache = await import('./cache-D5WyUDMY.js').then(function (n) { return n.c; });
break;
default:
throw new Error(`The \`cache-provider\` \`${cacheProvider}\` is not valid.`);
@ -34192,6 +34192,18 @@ class CacheConfig {
cacheKey = "";
/** The secondary (restore) key that only contains the prefix and environment */
restoreKey = "";
/** Whether the primary cache needs saving in the post action */
cacheNeedsSave = true;
/** Workspace target paths cached separately when `target-key` is used */
targetCachePaths = [];
/** The source-keyed workspace target cache key */
targetCacheKey = "";
/** The source-keyed workspace target restore keys */
targetRestoreKeys = [];
/** Whether workspace targets are cached separately from CARGO_HOME */
targetCacheEnabled = false;
/** Whether the workspace target cache needs saving in the post action */
targetCacheNeedsSave = false;
/** Whether to cache CARGO_HOME/.bin */
cacheBin = true;
/** The workspace configurations */
@ -34387,22 +34399,41 @@ class CacheConfig {
let lockHash = digest(hasher);
key += `-${lockHash}`;
}
self.cacheKey = key;
self.cachePaths = [path__default.join(CARGO_HOME, "registry"), path__default.join(CARGO_HOME, "git")];
const baseCacheKey = key;
const baseRestoreKey = self.restoreKey;
const cargoCachePaths = [path__default.join(CARGO_HOME, "registry"), path__default.join(CARGO_HOME, "git")];
if (self.cacheBin) {
self.cachePaths = [
path__default.join(CARGO_HOME, "bin"),
path__default.join(CARGO_HOME, ".crates.toml"),
path__default.join(CARGO_HOME, ".crates2.json"),
...self.cachePaths,
];
cargoCachePaths.unshift(path__default.join(CARGO_HOME, "bin"), path__default.join(CARGO_HOME, ".crates.toml"), path__default.join(CARGO_HOME, ".crates2.json"));
}
const cacheTargets = getInput("cache-targets").toLowerCase() || "true";
if (cacheTargets === "true") {
self.cachePaths.push(...workspaces.map((ws) => ws.target));
const targetCachePaths = cacheTargets === "true" ? workspaces.map((ws) => ws.target) : [];
const cacheDirectories = getInput("cache-directories").trim().split(/\s+/).filter(Boolean);
const targetKey = getInput("target-key");
const workspaceCrates = getInput("cache-workspace-crates").toLowerCase() || "false";
if (targetKey && cacheTargets !== "true") {
warning("`target-key` is ignored because `cache-targets` is not `true`.");
}
const cacheDirectories = getInput("cache-directories");
for (const dir of cacheDirectories.trim().split(/\s+/).filter(Boolean)) {
if (targetKey && workspaceCrates !== "true") {
warning("`target-key` is ignored because `cache-workspace-crates` is not `true`.");
}
self.targetCacheEnabled = Boolean(targetKey) && cacheTargets === "true" && workspaceCrates === "true";
if (self.targetCacheEnabled) {
self.cacheKey = baseCacheKey;
self.cachePaths = [...cargoCachePaths, ...cacheDirectories];
const targetKeyPrefix = `${baseRestoreKey}-target`;
const targetKeyEnvironment = baseCacheKey.slice(baseRestoreKey.length);
self.targetCachePaths = targetCachePaths;
self.targetCacheKey = `${targetKeyPrefix}${targetKeyEnvironment}-${targetKey}`;
self.targetRestoreKeys = uniqInOrder([`${targetKeyPrefix}${targetKeyEnvironment}-`, `${targetKeyPrefix}-`]);
}
else {
self.cacheKey = baseCacheKey;
self.cachePaths = [...cargoCachePaths];
}
if (!self.targetCacheEnabled && cacheTargets === "true") {
self.cachePaths.push(...targetCachePaths);
}
for (const dir of self.targetCacheEnabled ? [] : cacheDirectories) {
self.cachePaths.push(dir);
}
const bins = await getCargoBins();
@ -34438,14 +34469,26 @@ class CacheConfig {
for (const workspace of this.workspaces) {
info(` ${workspace.root}`);
}
info(`Cache Paths:`);
info(`${this.targetCacheEnabled ? "Cargo Cache" : "Cache"} Paths:`);
for (const path of this.cachePaths) {
info(` ${path}`);
}
info(`Restore Key:`);
info(`${this.targetCacheEnabled ? "Cargo Restore" : "Restore"} Key:`);
info(` ${this.restoreKey}`);
info(`Cache Key:`);
info(`${this.targetCacheEnabled ? "Cargo Cache" : "Cache"} Key:`);
info(` ${this.cacheKey}`);
if (this.targetCacheEnabled) {
info(`Target Cache Paths:`);
for (const path of this.targetCachePaths) {
info(` ${path}`);
}
info(`Target Restore Keys:`);
for (const key of this.targetRestoreKeys) {
info(` ${key}`);
}
info(`Target Cache Key:`);
info(` ${this.targetCacheKey}`);
}
info(`.. Prefix:`);
info(` - ${this.keyPrefix}`);
info(`.. Environment considered:`);
@ -34563,6 +34606,9 @@ function sort_and_uniq(a) {
return accumulator;
}, []);
}
function uniqInOrder(a) {
return a.filter((value, index) => a.indexOf(value) === index);
}
async function cleanTargetDir(targetDir, packages, checkTimestamp = false) {
debug(`cleaning target directory "${targetDir}"`);

77
dist/restore.js vendored
View file

@ -1,4 +1,4 @@
import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, c as cleanTargetDir, r as reportError, s as setOutput } from './cleanup-ChNUL7jL.js';
import { e as error, g as getCacheProvider, a as getInput, b as exportVariable, C as CacheConfig, i as info, r as reportError, s as setOutput, c as cleanTargetDir } from './cleanup-ctNqmXyy.js';
import 'os';
import 'crypto';
import 'fs';
@ -47,44 +47,43 @@ async function run() {
return;
}
try {
var cacheOnFailure = getInput("cache-on-failure").toLowerCase();
let cacheOnFailure = getInput("cache-on-failure").toLowerCase();
if (cacheOnFailure !== "true") {
cacheOnFailure = "false";
}
var lookupOnly = getInput("lookup-only").toLowerCase() === "true";
const lookupOnly = getInput("lookup-only").toLowerCase() === "true";
exportVariable("CACHE_ON_FAILURE", cacheOnFailure);
exportVariable("CARGO_INCREMENTAL", 0);
const config = await CacheConfig.new();
config.printInfo(cacheProvider);
info("");
info(`... ${lookupOnly ? "Checking" : "Restoring"} cache ...`);
const key = config.cacheKey;
// Pass a copy of cachePaths to avoid mutating the original array as reported by:
// https://github.com/actions/toolkit/pull/1378
// TODO: remove this once the underlying bug is fixed.
const restoreKey = await cacheProvider.cache.restoreCache(config.cachePaths.slice(), key, [config.restoreKey], {
lookupOnly,
});
if (restoreKey) {
const match = restoreKey.localeCompare(key, undefined, {
sensitivity: "accent",
}) === 0;
info(`${lookupOnly ? "Found" : "Restored from"} cache key "${restoreKey}" full match: ${match}.`);
if (!match) {
// pre-clean the target directory on cache mismatch
for (const workspace of config.workspaces) {
try {
await cleanTargetDir(workspace.target, [], true);
}
catch { }
}
// We restored the cache but it is not a full match.
const cacheResult = await restoreCache(cacheProvider, config.cachePaths, config.cacheKey, [config.restoreKey], lookupOnly);
config.cacheNeedsSave = !cacheResult.match;
if (config.targetCacheEnabled) {
if (cacheResult.found && !cacheResult.match) {
// pre-clean the target directory on cargo cache mismatch before restoring target cache
await cleanTargets(config);
}
const targetResult = await restoreCache(cacheProvider, config.targetCachePaths, config.targetCacheKey, config.targetRestoreKeys, lookupOnly, "target");
config.targetCacheNeedsSave = !targetResult.match;
if (targetResult.found && !targetResult.match) {
// pre-clean the target directory on target cache mismatch
await cleanTargets(config);
}
if (!cacheResult.match || !targetResult.match) {
config.saveState();
}
setCacheHitOutput(match);
setCacheHitOutput(cacheResult.match && targetResult.match);
}
else if (cacheResult.match) {
setCacheHitOutput(true);
}
else {
info("No cache found.");
if (cacheResult.found) {
// pre-clean the target directory on cache mismatch
await cleanTargets(config);
}
config.saveState();
setCacheHitOutput(false);
}
@ -98,4 +97,30 @@ async function run() {
function setCacheHitOutput(cacheHit) {
setOutput("cache-hit", cacheHit.toString());
}
async function restoreCache(cacheProvider, paths, key, restoreKeys, lookupOnly, name = "") {
const label = name ? `${name} cache` : "cache";
// Pass a copy of cachePaths to avoid mutating the original array as reported by:
// https://github.com/actions/toolkit/pull/1378
// TODO: remove this once the underlying bug is fixed.
const restoreKey = await cacheProvider.cache.restoreCache(paths.slice(), key, restoreKeys, {
lookupOnly,
});
if (!restoreKey) {
info(`No ${label} found.`);
return { found: false, match: false };
}
const match = restoreKey.localeCompare(key, undefined, {
sensitivity: "accent",
}) === 0;
info(`${lookupOnly ? "Found" : "Restored from"} ${label} key "${restoreKey}" full match: ${match}.`);
return { found: true, match };
}
async function cleanTargets(config) {
for (const workspace of config.workspaces) {
try {
await cleanTargetDir(workspace.target, [], true);
}
catch { }
}
}
run();

83
dist/save.js vendored
View file

@ -1,4 +1,4 @@
import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-ChNUL7jL.js';
import { e as error, g as getCacheProvider, a as getInput, d as isCacheUpToDate, i as info, C as CacheConfig, c as cleanTargetDir, f as debug, h as cleanRegistry, j as cleanBin, k as cleanGit, r as reportError, l as exec } from './cleanup-ctNqmXyy.js';
import 'os';
import 'crypto';
import 'fs';
@ -58,6 +58,8 @@ async function run() {
if (process.env["RUNNER_OS"] == "macOS") {
await macOsWorkaround();
}
const cleanCargo = !config.targetCacheEnabled || config.cacheNeedsSave;
const cleanTargets = !config.targetCacheEnabled || config.targetCacheNeedsSave;
const workspaceCrates = getInput("cache-workspace-crates").toLowerCase() || "false";
const allPackages = [];
for (const workspace of config.workspaces) {
@ -67,43 +69,62 @@ async function run() {
packages.push(...wsMembers);
}
allPackages.push(...packages);
if (cleanTargets) {
try {
info(`... Cleaning ${workspace.target} ...`);
await cleanTargetDir(workspace.target, packages);
}
catch (e) {
debug(`${e.stack}`);
}
}
}
if (cleanCargo) {
try {
info(`... Cleaning ${workspace.target} ...`);
await cleanTargetDir(workspace.target, packages);
const crates = getInput("cache-all-crates").toLowerCase() || "false";
info(`... Cleaning cargo registry (cache-all-crates: ${crates}) ...`);
await cleanRegistry(allPackages, crates !== "true");
}
catch (e) {
debug(`${e.stack}`);
}
if (config.cacheBin) {
try {
info(`... Cleaning cargo/bin ...`);
await cleanBin(config.cargoBins);
}
catch (e) {
debug(`${e.stack}`);
}
}
try {
info(`... Cleaning cargo git cache ...`);
await cleanGit(allPackages);
}
catch (e) {
debug(`${e.stack}`);
}
}
try {
const crates = getInput("cache-all-crates").toLowerCase() || "false";
info(`... Cleaning cargo registry (cache-all-crates: ${crates}) ...`);
await cleanRegistry(allPackages, crates !== "true");
}
catch (e) {
debug(`${e.stack}`);
}
if (config.cacheBin) {
try {
info(`... Cleaning cargo/bin ...`);
await cleanBin(config.cargoBins);
if (config.targetCacheEnabled) {
if (config.cacheNeedsSave) {
info(`... Saving cargo cache ...`);
await saveCache(cacheProvider, config.cachePaths, config.cacheKey);
}
catch (e) {
debug(`${e.stack}`);
else {
info(`Cargo cache up-to-date.`);
}
if (config.targetCacheNeedsSave) {
info(`... Saving target cache ...`);
await saveCache(cacheProvider, config.targetCachePaths, config.targetCacheKey);
}
else {
info(`Target cache up-to-date.`);
}
}
try {
info(`... Cleaning cargo git cache ...`);
await cleanGit(allPackages);
else {
info(`... Saving cache ...`);
await saveCache(cacheProvider, config.cachePaths, config.cacheKey);
}
catch (e) {
debug(`${e.stack}`);
}
info(`... Saving cache ...`);
// Pass a copy of cachePaths to avoid mutating the original array as reported by:
// https://github.com/actions/toolkit/pull/1378
// TODO: remove this once the underlying bug is fixed.
await cacheProvider.cache.saveCache(config.cachePaths.slice(), config.cacheKey);
}
catch (e) {
reportError(e);
@ -111,6 +132,12 @@ async function run() {
process.exit();
}
run();
async function saveCache(cacheProvider, paths, key) {
// Pass a copy of cachePaths to avoid mutating the original array as reported by:
// https://github.com/actions/toolkit/pull/1378
// TODO: remove this once the underlying bug is fixed.
await cacheProvider.cache.saveCache(paths.slice(), key);
}
async function macOsWorkaround() {
try {
// Workaround for https://github.com/actions/cache/issues/403