From 881ca6e47731b87e35fd347eb1a7815ab033bb1c Mon Sep 17 00:00:00 2001 From: Oran Avraham Date: Fri, 9 Dec 2022 17:48:00 +0200 Subject: [PATCH] poetry: Run `poetry env use` only after cache is loaded The virtualenv cache might contain invalid entries, such as virtualenvs built in previous, buggy versions of this action. The `poetry env use` command will recreate virtualenvs in case they are invalid, but it has to be run only *after* the cache is loaded. Refactor `CacheDistributor` a bit such that the validation (and possible recreation) of virtualenvs happens only after the cache is loaded. --- dist/cache-save/index.js | 4 ++ dist/setup/index.js | 45 ++++++++++++------ src/cache-distributions/cache-distributor.ts | 3 ++ src/cache-distributions/poetry-cache.ts | 50 ++++++++++++-------- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index da8fdef70..09a9fc6ec 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -59711,6 +59711,9 @@ class CacheDistributor { this.cacheDependencyPath = cacheDependencyPath; this.CACHE_KEY_PREFIX = 'setup-python'; } + handleLoadedCache() { + return __awaiter(this, void 0, void 0, function* () { }); + } restoreCache() { return __awaiter(this, void 0, void 0, function* () { const { primaryKey, restoreKey } = yield this.computeKeys(); @@ -59723,6 +59726,7 @@ class CacheDistributor { core.saveState(State.CACHE_PATHS, cachePath); core.saveState(State.STATE_CACHE_PRIMARY_KEY, primaryKey); const matchedKey = yield cache.restoreCache(cachePath, primaryKey, restoreKey); + yield this.handleLoadedCache(); this.handleMatchResult(matchedKey, primaryKey); }); } diff --git a/dist/setup/index.js b/dist/setup/index.js index 28e3cee72..41ed58a1f 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -65787,6 +65787,9 @@ class CacheDistributor { this.cacheDependencyPath = cacheDependencyPath; this.CACHE_KEY_PREFIX = 'setup-python'; } + handleLoadedCache() { + return __awaiter(this, void 0, void 0, function* () { }); + } restoreCache() { return __awaiter(this, void 0, void 0, function* () { const { primaryKey, restoreKey } = yield this.computeKeys(); @@ -65799,6 +65802,7 @@ class CacheDistributor { core.saveState(State.CACHE_PATHS, cachePath); core.saveState(State.STATE_CACHE_PRIMARY_KEY, primaryKey); const matchedKey = yield cache.restoreCache(cachePath, primaryKey, restoreKey); + yield this.handleLoadedCache(); this.handleMatchResult(matchedKey, primaryKey); }); } @@ -66097,10 +66101,11 @@ const core = __importStar(__nccwpck_require__(2186)); const cache_distributor_1 = __importDefault(__nccwpck_require__(8953)); const utils_1 = __nccwpck_require__(1314); class PoetryCache extends cache_distributor_1.default { - constructor(pythonVersion, patterns = '**/poetry.lock') { + constructor(pythonVersion, patterns = '**/poetry.lock', poetryProjects = new Set()) { super('poetry', patterns); this.pythonVersion = pythonVersion; this.patterns = patterns; + this.poetryProjects = poetryProjects; } getCacheGlobalDirectories() { var e_1, _a; @@ -66108,18 +66113,12 @@ class PoetryCache extends cache_distributor_1.default { // Same virtualenvs path may appear for different projects, hence we use a Set const paths = new Set(); const globber = yield glob.create(this.patterns); - const pythonLocation = yield io.which('python'); - if (pythonLocation) { - core.debug(`pythonLocation is ${pythonLocation}`); - } - else { - utils_1.logWarning('python binaries were not found in PATH'); - } try { for (var _b = __asyncValues(globber.globGenerator()), _c; _c = yield _b.next(), !_c.done;) { const file = _c.value; const basedir = path.dirname(file); core.debug(`Processing Poetry project at ${basedir}`); + this.poetryProjects.add(basedir); const poetryConfig = yield this.getPoetryConfiguration(basedir); const cacheDir = poetryConfig['cache-dir']; const virtualenvsPath = poetryConfig['virtualenvs.path'].replace('{cache-dir}', cacheDir); @@ -66127,12 +66126,6 @@ class PoetryCache extends cache_distributor_1.default { if (poetryConfig['virtualenvs.in-project']) { paths.add(path.join(basedir, '.venv')); } - if (pythonLocation) { - const { exitCode, stderr } = yield exec.getExecOutput('poetry', ['env', 'use', pythonLocation], { ignoreReturnCode: true, cwd: basedir }); - if (exitCode) { - utils_1.logWarning(stderr); - } - } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } @@ -66156,6 +66149,30 @@ class PoetryCache extends cache_distributor_1.default { }; }); } + handleLoadedCache() { + const _super = Object.create(null, { + handleLoadedCache: { get: () => super.handleLoadedCache } + }); + return __awaiter(this, void 0, void 0, function* () { + yield _super.handleLoadedCache.call(this); + // After the cache is loaded -- make sure virtualenvs use the correct Python version (the one that we have just installed). + // This will handle invalid caches, recreating virtualenvs if necessary. + const pythonLocation = yield io.which('python'); + if (pythonLocation) { + core.debug(`pythonLocation is ${pythonLocation}`); + } + else { + utils_1.logWarning('python binaries were not found in PATH'); + return; + } + for (const poetryProject of this.poetryProjects) { + const { exitCode, stderr } = yield exec.getExecOutput('poetry', ['env', 'use', pythonLocation], { ignoreReturnCode: true, cwd: poetryProject }); + if (exitCode) { + utils_1.logWarning(stderr); + } + } + }); + } getPoetryConfiguration(basedir) { return __awaiter(this, void 0, void 0, function* () { const { stdout, stderr, exitCode } = yield exec.getExecOutput('poetry', ['config', '--list'], { cwd: basedir }); diff --git a/src/cache-distributions/cache-distributor.ts b/src/cache-distributions/cache-distributor.ts index f24c78dab..2e46c961d 100644 --- a/src/cache-distributions/cache-distributor.ts +++ b/src/cache-distributions/cache-distributor.ts @@ -19,6 +19,7 @@ abstract class CacheDistributor { primaryKey: string; restoreKey: string[] | undefined; }>; + protected async handleLoadedCache() {} public async restoreCache() { const {primaryKey, restoreKey} = await this.computeKeys(); @@ -41,6 +42,8 @@ abstract class CacheDistributor { restoreKey ); + await this.handleLoadedCache(); + this.handleMatchResult(matchedKey, primaryKey); } diff --git a/src/cache-distributions/poetry-cache.ts b/src/cache-distributions/poetry-cache.ts index 24a96b13b..ebbffbacf 100644 --- a/src/cache-distributions/poetry-cache.ts +++ b/src/cache-distributions/poetry-cache.ts @@ -10,7 +10,8 @@ import {logWarning} from '../utils'; class PoetryCache extends CacheDistributor { constructor( private pythonVersion: string, - protected patterns: string = '**/poetry.lock' + protected patterns: string = '**/poetry.lock', + protected poetryProjects: Set = new Set() ) { super('poetry', patterns); } @@ -20,16 +21,10 @@ class PoetryCache extends CacheDistributor { const paths = new Set(); const globber = await glob.create(this.patterns); - const pythonLocation = await io.which('python'); - if (pythonLocation) { - core.debug(`pythonLocation is ${pythonLocation}`); - } else { - logWarning('python binaries were not found in PATH'); - } - for await (const file of globber.globGenerator()) { const basedir = path.dirname(file); core.debug(`Processing Poetry project at ${basedir}`); + this.poetryProjects.add(basedir); const poetryConfig = await this.getPoetryConfiguration(basedir); @@ -44,18 +39,6 @@ class PoetryCache extends CacheDistributor { if (poetryConfig['virtualenvs.in-project']) { paths.add(path.join(basedir, '.venv')); } - - if (pythonLocation) { - const {exitCode, stderr} = await exec.getExecOutput( - 'poetry', - ['env', 'use', pythonLocation], - {ignoreReturnCode: true, cwd: basedir} - ); - - if (exitCode) { - logWarning(stderr); - } - } } return [...paths]; @@ -71,6 +54,33 @@ class PoetryCache extends CacheDistributor { }; } + protected async handleLoadedCache() { + await super.handleLoadedCache(); + + // After the cache is loaded -- make sure virtualenvs use the correct Python version (the one that we have just installed). + // This will handle invalid caches, recreating virtualenvs if necessary. + + const pythonLocation = await io.which('python'); + if (pythonLocation) { + core.debug(`pythonLocation is ${pythonLocation}`); + } else { + logWarning('python binaries were not found in PATH'); + return; + } + + for (const poetryProject of this.poetryProjects) { + const {exitCode, stderr} = await exec.getExecOutput( + 'poetry', + ['env', 'use', pythonLocation], + {ignoreReturnCode: true, cwd: poetryProject} + ); + + if (exitCode) { + logWarning(stderr); + } + } + } + private async getPoetryConfiguration(basedir: string) { const {stdout, stderr, exitCode} = await exec.getExecOutput( 'poetry',