This commit is contained in:
sgpinkus 2025-04-12 12:24:41 +02:00 committed by GitHub
commit 5b92af7be6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 32 additions and 30 deletions

View File

@ -1,6 +1,5 @@
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {CACHE_DEPENDENCY_BACKUP_PATH} from './constants';
export enum State { export enum State {
STATE_CACHE_PRIMARY_KEY = 'cache-primary-key', STATE_CACHE_PRIMARY_KEY = 'cache-primary-key',
@ -10,27 +9,20 @@ export enum State {
abstract class CacheDistributor { abstract class CacheDistributor {
protected CACHE_KEY_PREFIX = 'setup-python'; protected CACHE_KEY_PREFIX = 'setup-python';
constructor( protected abstract readonly packageManager: string;
protected packageManager: string,
protected cacheDependencyPath: string
) {}
protected abstract getCacheGlobalDirectories(): Promise<string[]>; protected abstract getCacheGlobalDirectories(): Promise<string[]>;
protected abstract computeKeys(): Promise<{ protected abstract computeKeys(): Promise<{
primaryKey: string; primaryKey: string;
restoreKey: string[] | undefined; restoreKey: string[] | undefined;
cacheDependencyPath: string;
}>; }>;
protected async handleLoadedCache() {} protected async handleLoadedCache() {}
public async restoreCache() { public async restoreCache() {
const {primaryKey, restoreKey} = await this.computeKeys(); const {primaryKey, restoreKey, cacheDependencyPath} = await this.computeKeys();
if (primaryKey.endsWith('-')) { if (primaryKey.endsWith('-')) {
const file = const file = cacheDependencyPath.split('\n').join(',');
this.packageManager === 'pip'
? `${this.cacheDependencyPath
.split('\n')
.join(',')} or ${CACHE_DEPENDENCY_BACKUP_PATH}`
: this.cacheDependencyPath.split('\n').join(',');
throw new Error( throw new Error(
`No file in ${process.cwd()} matched to [${file}], make sure you have checked out the target repository` `No file in ${process.cwd()} matched to [${file}], make sure you have checked out the target repository`
); );

View File

@ -1 +0,0 @@
export const CACHE_DEPENDENCY_BACKUP_PATH = '**/pyproject.toml';

View File

@ -8,16 +8,16 @@ import os from 'os';
import CacheDistributor from './cache-distributor'; import CacheDistributor from './cache-distributor';
import {getLinuxInfo, IS_LINUX, IS_WINDOWS} from '../utils'; import {getLinuxInfo, IS_LINUX, IS_WINDOWS} from '../utils';
import {CACHE_DEPENDENCY_BACKUP_PATH} from './constants';
class PipCache extends CacheDistributor { class PipCache extends CacheDistributor {
private cacheDependencyBackupPath: string = CACHE_DEPENDENCY_BACKUP_PATH; private cacheDependencyBackupPath = '**/pyproject.toml';
protected readonly packageManager = 'pip';
constructor( constructor(
private pythonVersion: string, private pythonVersion: string,
cacheDependencyPath = '**/requirements.txt' protected readonly cacheDependencyPath = '**/requirements.txt'
) { ) {
super('pip', cacheDependencyPath); super();
} }
protected async getCacheGlobalDirectories() { protected async getCacheGlobalDirectories() {
@ -59,9 +59,12 @@ class PipCache extends CacheDistributor {
} }
protected async computeKeys() { protected async computeKeys() {
const hash = let cacheDependencyPath = this.cacheDependencyPath;
(await glob.hashFiles(this.cacheDependencyPath)) || let hash = await glob.hashFiles(this.cacheDependencyPath);
(await glob.hashFiles(this.cacheDependencyBackupPath)); if(!hash) {
hash = await glob.hashFiles(this.cacheDependencyBackupPath);
cacheDependencyPath = this.cacheDependencyBackupPath;
}
let primaryKey = ''; let primaryKey = '';
let restoreKey = ''; let restoreKey = '';
@ -76,7 +79,8 @@ class PipCache extends CacheDistributor {
return { return {
primaryKey, primaryKey,
restoreKey: [restoreKey] restoreKey: [restoreKey],
cacheDependencyPath,
}; };
} }
} }

View File

@ -6,11 +6,13 @@ import * as core from '@actions/core';
import CacheDistributor from './cache-distributor'; import CacheDistributor from './cache-distributor';
class PipenvCache extends CacheDistributor { class PipenvCache extends CacheDistributor {
protected readonly packageManager = 'pipenv';
constructor( constructor(
private pythonVersion: string, private pythonVersion: string,
protected patterns: string = '**/Pipfile.lock' protected readonly cacheDependencyPath: string = '**/Pipfile.lock'
) { ) {
super('pipenv', patterns); super();
} }
protected async getCacheGlobalDirectories() { protected async getCacheGlobalDirectories() {
@ -31,12 +33,13 @@ class PipenvCache extends CacheDistributor {
} }
protected async computeKeys() { protected async computeKeys() {
const hash = await glob.hashFiles(this.patterns); const hash = await glob.hashFiles(this.cacheDependencyPath);
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
const restoreKey = undefined; const restoreKey = undefined;
return { return {
primaryKey, primaryKey,
restoreKey restoreKey,
cacheDependencyPath: this.cacheDependencyPath,
}; };
} }
} }

View File

@ -8,18 +8,21 @@ import CacheDistributor from './cache-distributor';
import {logWarning} from '../utils'; import {logWarning} from '../utils';
class PoetryCache extends CacheDistributor { class PoetryCache extends CacheDistributor {
protected readonly packageManager = 'poetry';
constructor( constructor(
private pythonVersion: string, private pythonVersion: string,
protected patterns: string = '**/poetry.lock', protected readonly cacheDependencyPath: string = '**/poetry.lock',
protected poetryProjects: Set<string> = new Set<string>() protected poetryProjects: Set<string> = new Set<string>()
) { ) {
super('poetry', patterns); super();
} }
protected async getCacheGlobalDirectories() { protected async getCacheGlobalDirectories() {
// Same virtualenvs path may appear for different projects, hence we use a Set // Same virtualenvs path may appear for different projects, hence we use a Set
const paths = new Set<string>(); const paths = new Set<string>();
const globber = await glob.create(this.patterns); const globber = await glob.create(this.cacheDependencyPath);
for await (const file of globber.globGenerator()) { for await (const file of globber.globGenerator()) {
const basedir = path.dirname(file); const basedir = path.dirname(file);
@ -45,13 +48,14 @@ class PoetryCache extends CacheDistributor {
} }
protected async computeKeys() { protected async computeKeys() {
const hash = await glob.hashFiles(this.patterns); const hash = await glob.hashFiles(this.cacheDependencyPath);
// "v2" is here to invalidate old caches of this cache distributor, which were created broken: // "v2" is here to invalidate old caches of this cache distributor, which were created broken:
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`; const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`;
const restoreKey = undefined; const restoreKey = undefined;
return { return {
primaryKey, primaryKey,
restoreKey restoreKey,
cacheDependencyPath: this.cacheDependencyPath,
}; };
} }