mirror of
				https://gitea.com/actions/setup-python.git
				synced 2025-10-31 07:47:08 +00:00 
			
		
		
		
	Merge branch 'actions:main' into main
This commit is contained in:
		| @@ -41,12 +41,17 @@ abstract class CacheDistributor { | ||||
|       restoreKey | ||||
|     ); | ||||
|  | ||||
|     this.handleMatchResult(matchedKey, primaryKey); | ||||
|   } | ||||
|  | ||||
|   public handleMatchResult(matchedKey: string | undefined, primaryKey: string) { | ||||
|     if (matchedKey) { | ||||
|       core.saveState(State.CACHE_MATCHED_KEY, matchedKey); | ||||
|       core.info(`Cache restored from key: ${matchedKey}`); | ||||
|     } else { | ||||
|       core.info(`${this.packageManager} cache is not found`); | ||||
|     } | ||||
|     core.setOutput('cache-hit', matchedKey === primaryKey); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,11 @@ | ||||
| import PipCache from './pip-cache'; | ||||
| import PipenvCache from './pipenv-cache'; | ||||
| import PoetryCache from './poetry-cache'; | ||||
|  | ||||
| export enum PackageManagers { | ||||
|   Pip = 'pip', | ||||
|   Pipenv = 'pipenv' | ||||
|   Pipenv = 'pipenv', | ||||
|   Poetry = 'poetry' | ||||
| } | ||||
|  | ||||
| export function getCacheDistributor( | ||||
| @@ -16,6 +18,8 @@ export function getCacheDistributor( | ||||
|       return new PipCache(pythonVersion, cacheDependencyPath); | ||||
|     case PackageManagers.Pipenv: | ||||
|       return new PipenvCache(pythonVersion, cacheDependencyPath); | ||||
|     case PackageManagers.Poetry: | ||||
|       return new PoetryCache(pythonVersion, cacheDependencyPath); | ||||
|     default: | ||||
|       throw new Error(`Caching for '${packageManager}' is not supported`); | ||||
|   } | ||||
|   | ||||
							
								
								
									
										76
									
								
								src/cache-distributions/poetry-cache.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/cache-distributions/poetry-cache.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| import * as glob from '@actions/glob'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as exec from '@actions/exec'; | ||||
|  | ||||
| import CacheDistributor from './cache-distributor'; | ||||
|  | ||||
| class PoetryCache extends CacheDistributor { | ||||
|   constructor( | ||||
|     private pythonVersion: string, | ||||
|     protected patterns: string = '**/poetry.lock' | ||||
|   ) { | ||||
|     super('poetry', patterns); | ||||
|   } | ||||
|  | ||||
|   protected async getCacheGlobalDirectories() { | ||||
|     const poetryConfig = await this.getPoetryConfiguration(); | ||||
|  | ||||
|     const cacheDir = poetryConfig['cache-dir']; | ||||
|     const virtualenvsPath = poetryConfig['virtualenvs.path'].replace( | ||||
|       '{cache-dir}', | ||||
|       cacheDir | ||||
|     ); | ||||
|  | ||||
|     const paths = [virtualenvsPath]; | ||||
|  | ||||
|     if (poetryConfig['virtualenvs.in-project'] === true) { | ||||
|       paths.push(path.join(process.cwd(), '.venv')); | ||||
|     } | ||||
|  | ||||
|     return paths; | ||||
|   } | ||||
|  | ||||
|   protected async computeKeys() { | ||||
|     const hash = await glob.hashFiles(this.patterns); | ||||
|     const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; | ||||
|     const restoreKey = undefined; | ||||
|     return { | ||||
|       primaryKey, | ||||
|       restoreKey | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   private async getPoetryConfiguration() { | ||||
|     const {stdout, stderr, exitCode} = await exec.getExecOutput('poetry', [ | ||||
|       'config', | ||||
|       '--list' | ||||
|     ]); | ||||
|  | ||||
|     if (exitCode && stderr) { | ||||
|       throw new Error( | ||||
|         'Could not get cache folder path for poetry package manager' | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     const lines = stdout.trim().split('\n'); | ||||
|  | ||||
|     const config: any = {}; | ||||
|  | ||||
|     for (let line of lines) { | ||||
|       line = line.replace(/#.*$/, ''); | ||||
|  | ||||
|       const [key, value] = line.split('=').map(part => part.trim()); | ||||
|  | ||||
|       config[key] = JSON.parse(value); | ||||
|     } | ||||
|  | ||||
|     return config as { | ||||
|       'cache-dir': string; | ||||
|       'virtualenvs.in-project': boolean; | ||||
|       'virtualenvs.path': string; | ||||
|     }; | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default PoetryCache; | ||||
| @@ -52,6 +52,7 @@ export async function findPyPyVersion( | ||||
|   core.exportVariable('pythonLocation', pythonLocation); | ||||
|   core.addPath(pythonLocation); | ||||
|   core.addPath(_binDir); | ||||
|   core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim()); | ||||
|  | ||||
|   return {resolvedPyPyVersion, resolvedPythonVersion}; | ||||
| } | ||||
|   | ||||
| @@ -30,52 +30,7 @@ function binDir(installDir: string): string { | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Note on the tool cache layout for PyPy: | ||||
| // PyPy has its own versioning scheme that doesn't follow the Python versioning scheme. | ||||
| // A particular version of PyPy may contain one or more versions of the Python interpreter. | ||||
| // For example, PyPy 7.0 contains Python 2.7, 3.5, and 3.6-alpha. | ||||
| // We only care about the Python version, so we don't use the PyPy version for the tool cache. | ||||
| function usePyPy( | ||||
|   majorVersion: '2' | '3.6', | ||||
|   architecture: string | ||||
| ): InstalledVersion { | ||||
|   const findPyPy = tc.find.bind(undefined, 'PyPy', majorVersion); | ||||
|   let installDir: string | null = findPyPy(architecture); | ||||
|  | ||||
|   if (!installDir && IS_WINDOWS) { | ||||
|     // PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64. | ||||
|     // On our Windows virtual environments, we only install an x86 version. | ||||
|     // Fall back to x86. | ||||
|     installDir = findPyPy('x86'); | ||||
|   } | ||||
|  | ||||
|   if (!installDir) { | ||||
|     // PyPy not installed in $(Agent.ToolsDirectory) | ||||
|     throw new Error(`PyPy ${majorVersion} not found`); | ||||
|   } | ||||
|  | ||||
|   // For PyPy, Windows uses 'bin', not 'Scripts'. | ||||
|   const _binDir = path.join(installDir, 'bin'); | ||||
|  | ||||
|   // On Linux and macOS, the Python interpreter is in 'bin'. | ||||
|   // On Windows, it is in the installation root. | ||||
|   const pythonLocation = IS_WINDOWS ? installDir : _binDir; | ||||
|   core.exportVariable('pythonLocation', pythonLocation); | ||||
|  | ||||
|   core.addPath(installDir); | ||||
|   core.addPath(_binDir); | ||||
|   // Starting from PyPy 7.3.1, the folder that is used for pip and anything that pip installs should be "Scripts" on Windows. | ||||
|   if (IS_WINDOWS) { | ||||
|     core.addPath(path.join(installDir, 'Scripts')); | ||||
|   } | ||||
|  | ||||
|   const impl = 'pypy' + majorVersion.toString(); | ||||
|   core.setOutput('python-version', impl); | ||||
|  | ||||
|   return {impl: impl, version: versionFromPath(installDir)}; | ||||
| } | ||||
|  | ||||
| async function useCpythonVersion( | ||||
| export async function useCpythonVersion( | ||||
|   version: string, | ||||
|   architecture: string | ||||
| ): Promise<InstalledVersion> { | ||||
| @@ -186,18 +141,3 @@ export function pythonVersionToSemantic(versionSpec: string) { | ||||
|   const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g; | ||||
|   return versionSpec.replace(prereleaseVersion, '$1-$2'); | ||||
| } | ||||
|  | ||||
| export async function findPythonVersion( | ||||
|   version: string, | ||||
|   architecture: string | ||||
| ): Promise<InstalledVersion> { | ||||
|   switch (version.toUpperCase()) { | ||||
|     case 'PYPY2': | ||||
|       return usePyPy('2', architecture); | ||||
|     case 'PYPY3': | ||||
|       // keep pypy3 pointing to 3.6 for backward compatibility | ||||
|       return usePyPy('3.6', architecture); | ||||
|     default: | ||||
|       return await useCpythonVersion(version, architecture); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,16 +4,13 @@ import * as finderPyPy from './find-pypy'; | ||||
| import * as path from 'path'; | ||||
| import * as os from 'os'; | ||||
| import {getCacheDistributor} from './cache-distributions/cache-factory'; | ||||
| import {isGhes} from './utils'; | ||||
| import {isCacheFeatureAvailable} from './utils'; | ||||
|  | ||||
| function isPyPyVersion(versionSpec: string) { | ||||
|   return versionSpec.startsWith('pypy-'); | ||||
| } | ||||
|  | ||||
| async function cacheDependencies(cache: string, pythonVersion: string) { | ||||
|   if (isGhes()) { | ||||
|     throw new Error('Caching is not supported on GHES'); | ||||
|   } | ||||
|   const cacheDependencyPath = | ||||
|     core.getInput('cache-dependency-path') || undefined; | ||||
|   const cacheDistributor = getCacheDistributor( | ||||
| @@ -47,13 +44,13 @@ async function run() { | ||||
|           `Successfully setup PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` | ||||
|         ); | ||||
|       } else { | ||||
|         const installed = await finder.findPythonVersion(version, arch); | ||||
|         const installed = await finder.useCpythonVersion(version, arch); | ||||
|         pythonVersion = installed.version; | ||||
|         core.info(`Successfully setup ${installed.impl} (${pythonVersion})`); | ||||
|       } | ||||
|  | ||||
|       const cache = core.getInput('cache'); | ||||
|       if (cache) { | ||||
|       if (cache && isCacheFeatureAvailable()) { | ||||
|         await cacheDependencies(cache, pythonVersion); | ||||
|       } | ||||
|     } | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/utils.ts
									
									
									
									
									
								
							| @@ -1,3 +1,5 @@ | ||||
| import * as cache from '@actions/cache'; | ||||
| import * as core from '@actions/core'; | ||||
| import fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
| import * as semver from 'semver'; | ||||
| @@ -99,3 +101,21 @@ export function isGhes(): boolean { | ||||
|   ); | ||||
|   return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'; | ||||
| } | ||||
|  | ||||
| export function isCacheFeatureAvailable(): boolean { | ||||
|   if (!cache.isFeatureAvailable()) { | ||||
|     if (isGhes()) { | ||||
|       throw new Error( | ||||
|         'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.' | ||||
|       ); | ||||
|     } else { | ||||
|       core.warning( | ||||
|         'The runner was not able to contact the cache service. Caching will be skipped' | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sergey Dolin
					Sergey Dolin