From 7dbcc3ca5013e16beac6dbc9acf587aca72a0cc8 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Mon, 17 Apr 2023 15:07:17 -0700 Subject: [PATCH] Generate key. --- action.yml | 4 ++++ index.ts | 8 ++++++-- src/cargo.ts | 42 ++++++++++++++++++++++++++++++++++++++---- src/rust.ts | 31 +++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/rust.ts diff --git a/action.yml b/action.yml index 7371bf4..8a52c54 100644 --- a/action.yml +++ b/action.yml @@ -22,6 +22,10 @@ outputs: description: 'The generated cache key used.' cache-hit: description: 'Indicates an exact match was found for the cache key.' + rust-version: + description: 'Version of the installed rustc.' + rust-hash: + description: 'Commit hash of the installed rustc.' runs: using: 'node16' main: 'dist/index.js' diff --git a/index.ts b/index.ts index 3719e79..16160fb 100644 --- a/index.ts +++ b/index.ts @@ -5,6 +5,7 @@ import * as exec from '@actions/exec'; import * as tc from '@actions/tool-cache'; import TOML from '@ltd/j-toml'; import { CACHE_ENABLED, CARGO_HOME, restoreCache } from './src/cargo'; +import { extractRustVersion } from './src/rust'; interface Toolchain { channel: string; @@ -118,7 +119,7 @@ async function installToolchain(toolchain: Toolchain) { core.info('Logging installed toolchain versions'); - await exec.exec('rustc', [`+${toolchain.channel}`, '--version', '--verbose']); + await extractRustVersion(toolchain.channel); } async function downloadAndInstallBinstall(binDir: string) { @@ -199,9 +200,12 @@ async function run() { core.exportVariable('CARGO_TERM_COLOR', 'always'); try { - await restoreCache(); await installToolchain(detectToolchain()); await installBins(); + + // Restore cache after the toolchain has been installed, + // as we use the rust version and commit hashes in the cache key! + await restoreCache(); } catch (error: unknown) { core.setFailed((error as Error).message); diff --git a/src/cargo.ts b/src/cargo.ts index 013477c..db480e5 100644 --- a/src/cargo.ts +++ b/src/cargo.ts @@ -1,5 +1,6 @@ /* eslint-disable node/no-unsupported-features/node-builtins */ +import crypto from 'crypto'; import fs from 'fs'; import os from 'os'; import path from 'path'; @@ -13,12 +14,45 @@ export const CARGO_HOME = process.env.CARGO_HOME || path.join(os.homedir(), '.ca export const CACHE_ENABLED = core.getBooleanInput('cache') || cache.isFeatureAvailable(); -export function getPrimaryCacheKey(): string { - return `setup-rustcargo-${process.platform}`; +let CACHE_KEY = ''; + +export async function getPrimaryCacheKey() { + if (CACHE_KEY) { + return CACHE_KEY; + } + + core.info('Generating cache key'); + + const rustVersion = core.getState('rust-version'); + + core.debug(`Hashing Rust version = ${rustVersion}`); + + const rustHash = core.getState('rust-hash'); + + core.debug(`Hashing Rust commit hash = ${rustHash}`); + + const lockHash = await glob.hashFiles('Cargo.lock'); + + core.debug(`Hashing Cargo.lock = ${lockHash}`); + + const hasher = crypto.createHash('sha1'); + hasher.update(rustVersion); + hasher.update(rustHash); + hasher.update(lockHash); + + // eslint-disable-next-line require-atomic-updates + CACHE_KEY = `setup-rustcargo-${process.platform}-${hasher.digest('hex')}`; + + return CACHE_KEY; } export function getPathsToCache(): string[] { - return [path.join(CARGO_HOME, 'registry')]; + return [ + // ~/.cargo/registry + path.join(CARGO_HOME, 'registry'), + // /workspace/target/debug + path.join(process.cwd(), 'target/debug'), + ]; } export async function cleanCargoRegistry() { @@ -45,7 +79,7 @@ export async function saveCache() { return; } - const primaryKey = getPrimaryCacheKey(); + const primaryKey = await getPrimaryCacheKey(); const cacheHitKey = core.getState('cache-hit-key'); if (cacheHitKey === primaryKey) { diff --git a/src/rust.ts b/src/rust.ts new file mode 100644 index 0000000..f2333b8 --- /dev/null +++ b/src/rust.ts @@ -0,0 +1,31 @@ +import * as core from '@actions/core'; +import * as exec from '@actions/exec'; + +export async function extractRustVersion(toolchain: string) { + let out = ''; + + await exec.exec('rustc', [`+${toolchain}`, '--version', '--verbose'], { + listeners: { + stdout(data: Buffer) { + out += data.toString(); + }, + }, + }); + + out.split('\n').forEach((line) => { + let key = ''; + + if (line.startsWith('commit-hash')) { + key = 'rust-hash'; + } else if (line.startsWith('release')) { + key = 'rust-version'; + } else { + return; + } + + const value = line.split(':')[1].trim(); + + core.saveState(key, value); + core.setOutput(key, value); + }); +}