mirror of
				https://gitea.com/actions/setup-python.git
				synced 2025-10-31 19:58:55 +08:00 
			
		
		
		
	graalpy: add graalpy early-access and windows builds (#880)
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/test-graalpy.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test-graalpy.yml
									
									
									
									
										vendored
									
									
								
							| @@ -106,7 +106,7 @@ jobs: | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         os: [ubuntu-latest, macos-latest, macos-13] | ||||
|         os: [ubuntu-latest, windows-latest, macos-latest, macos-13] | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - name: Setup GraalPy and check latest | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -10,7 +10,7 @@ import * as path from 'path'; | ||||
| import * as semver from 'semver'; | ||||
|  | ||||
| import * as finder from '../src/find-graalpy'; | ||||
| import {IGraalPyManifestRelease, IS_WINDOWS} from '../src/utils'; | ||||
| import {IGraalPyManifestRelease} from '../src/utils'; | ||||
|  | ||||
| import manifestData from './data/graalpy.json'; | ||||
|  | ||||
| @@ -19,9 +19,6 @@ const architecture = 'x64'; | ||||
| const toolDir = path.join(__dirname, 'runner', 'tools'); | ||||
| const tempDir = path.join(__dirname, 'runner', 'temp'); | ||||
|  | ||||
| /* GraalPy doesn't have a windows release yet */ | ||||
| const describeSkipOnWindows = IS_WINDOWS ? describe.skip : describe; | ||||
|  | ||||
| describe('parseGraalPyVersion', () => { | ||||
|   it.each([ | ||||
|     ['graalpy-23', '23'], | ||||
| @@ -108,7 +105,7 @@ describe('findGraalPyToolCache', () => { | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describeSkipOnWindows('findGraalPyVersion', () => { | ||||
| describe('findGraalPyVersion', () => { | ||||
|   let getBooleanInputSpy: jest.SpyInstance; | ||||
|   let warningSpy: jest.SpyInstance; | ||||
|   let debugSpy: jest.SpyInstance; | ||||
| @@ -358,13 +355,13 @@ describeSkipOnWindows('findGraalPyVersion', () => { | ||||
|   it('found and install successfully, pre-release fallback', async () => { | ||||
|     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||
|     spyCacheDir.mockImplementation(() => | ||||
|       path.join(toolDir, 'GraalPy', '23.1', architecture) | ||||
|       path.join(toolDir, 'GraalPy', '24.1', architecture) | ||||
|     ); | ||||
|     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||
|     spyChmodSync.mockImplementation(() => undefined); | ||||
|     await expect( | ||||
|       finder.findGraalPyVersion( | ||||
|         'graalpy23.1', | ||||
|         'graalpy24.1', | ||||
|         architecture, | ||||
|         false, | ||||
|         false, | ||||
| @@ -372,7 +369,7 @@ describeSkipOnWindows('findGraalPyVersion', () => { | ||||
|       ) | ||||
|     ).rejects.toThrow(); | ||||
|     await expect( | ||||
|       finder.findGraalPyVersion('graalpy23.1', architecture, false, false, true) | ||||
|     ).resolves.toEqual('23.1.0-a.1'); | ||||
|       finder.findGraalPyVersion('graalpy24.1', architecture, false, false, true) | ||||
|     ).resolves.toEqual('24.1.0-ea.9'); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -21,24 +21,21 @@ const architecture = 'x64'; | ||||
| const toolDir = path.join(__dirname, 'runner', 'tools'); | ||||
| const tempDir = path.join(__dirname, 'runner', 'temp'); | ||||
|  | ||||
| /* GraalPy doesn't have a windows release yet */ | ||||
| const describeSkipOnWindows = IS_WINDOWS ? describe.skip : describe; | ||||
|  | ||||
| describe('graalpyVersionToSemantic', () => { | ||||
|   it.each([ | ||||
|     ['23.0.0a1', '23.0.0a1'], | ||||
|     ['23.0.0', '23.0.0'], | ||||
|     ['23.0.x', '23.0.x'], | ||||
|     ['23.x', '23.x'] | ||||
|     ['graalpy-24.1.0-ea.09', '24.1.0-ea.9'], | ||||
|     ['graal-23.0.0', '23.0.0'], | ||||
|     ['vm-23.0.x', '23.0.x'], | ||||
|     ['graal-23.x', '23.x'] | ||||
|   ])('%s -> %s', (input, expected) => { | ||||
|     expect(installer.graalPyTagToVersion(input)).toEqual(expected); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describeSkipOnWindows('findRelease', () => { | ||||
| describe('findRelease', () => { | ||||
|   const result = JSON.stringify(manifestData); | ||||
|   const releases = JSON.parse(result) as IGraalPyManifestRelease[]; | ||||
|   const extension = 'tar.gz'; | ||||
|   const extension = IS_WINDOWS ? 'zip' : 'tar.gz'; | ||||
|   const arch = installer.toGraalPyArchitecture(architecture); | ||||
|   const platform = installer.toGraalPyPlatform(process.platform); | ||||
|   const extensionName = `${platform}-${arch}.${extension}`; | ||||
| @@ -47,8 +44,8 @@ describeSkipOnWindows('findRelease', () => { | ||||
|     browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.0.0/graalpython-23.0.0-${extensionName}` | ||||
|   }; | ||||
|   const filesRC1: IGraalPyManifestAsset = { | ||||
|     name: `graalpython-23.1.0a1-${extensionName}`, | ||||
|     browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.1.0a1/graalpython-23.1.0a1-${extensionName}` | ||||
|     name: `graalpy-24.1.0-ea.09-${extensionName}`, | ||||
|     browser_download_url: `https://github.com/graalvm/graal-languages-ea-builds/releases/download/graalpy-24.1.0-ea.09/graalpy-24.1.0-ea.09-${extensionName}` | ||||
|   }; | ||||
|  | ||||
|   let warningSpy: jest.SpyInstance; | ||||
| @@ -84,15 +81,15 @@ describeSkipOnWindows('findRelease', () => { | ||||
|   }); | ||||
|  | ||||
|   it('Preview version of GraalPy is found', () => { | ||||
|     const graalpyVersion = installer.graalPyTagToVersion('vm-23.1.0a1'); | ||||
|     const graalpyVersion = installer.graalPyTagToVersion('vm-24.1.0-ea.09'); | ||||
|     expect( | ||||
|       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||
|     ).toMatchObject({ | ||||
|       foundAsset: { | ||||
|         name: `graalpython-23.1.0a1-${extensionName}`, | ||||
|         browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.1.0a1/graalpython-23.1.0a1-${extensionName}` | ||||
|         name: `graalpy-24.1.0-ea.09-${extensionName}`, | ||||
|         browser_download_url: `https://github.com/graalvm/graal-languages-ea-builds/releases/download/graalpy-24.1.0-ea.09/graalpy-24.1.0-ea.09-${extensionName}` | ||||
|       }, | ||||
|       resolvedGraalPyVersion: '23.1.0-a.1' | ||||
|       resolvedGraalPyVersion: '24.1.0-ea.9' | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
| @@ -107,7 +104,7 @@ describeSkipOnWindows('findRelease', () => { | ||||
|   }); | ||||
|  | ||||
|   it('GraalPy version matches semver (pre-release)', () => { | ||||
|     const graalpyVersion = '23.1.x'; | ||||
|     const graalpyVersion = '24.1.x'; | ||||
|     expect( | ||||
|       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||
|     ).toBeNull(); | ||||
| @@ -115,12 +112,12 @@ describeSkipOnWindows('findRelease', () => { | ||||
|       installer.findRelease(releases, graalpyVersion, architecture, true) | ||||
|     ).toMatchObject({ | ||||
|       foundAsset: filesRC1, | ||||
|       resolvedGraalPyVersion: '23.1.0-a.1' | ||||
|       resolvedGraalPyVersion: '24.1.0-ea.9' | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| describeSkipOnWindows('installGraalPy', () => { | ||||
| describe('installGraalPy', () => { | ||||
|   let tcFind: jest.SpyInstance; | ||||
|   let warningSpy: jest.SpyInstance; | ||||
|   let debugSpy: jest.SpyInstance; | ||||
| @@ -232,20 +229,20 @@ describeSkipOnWindows('installGraalPy', () => { | ||||
|   it('found and install GraalPy, pre-release fallback', async () => { | ||||
|     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||
|     spyCacheDir.mockImplementation(() => | ||||
|       path.join(toolDir, 'GraalPy', '23.1.0', architecture) | ||||
|       path.join(toolDir, 'GraalPy', '24.1.0', architecture) | ||||
|     ); | ||||
|  | ||||
|     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||
|     spyChmodSync.mockImplementation(() => undefined); | ||||
|  | ||||
|     await expect( | ||||
|       installer.installGraalPy('23.1.x', architecture, false, undefined) | ||||
|       installer.installGraalPy('24.1.x', architecture, false, undefined) | ||||
|     ).rejects.toThrow(); | ||||
|     await expect( | ||||
|       installer.installGraalPy('23.1.x', architecture, true, undefined) | ||||
|       installer.installGraalPy('24.1.x', architecture, true, undefined) | ||||
|     ).resolves.toEqual({ | ||||
|       installDir: path.join(toolDir, 'GraalPy', '23.1.0', architecture), | ||||
|       resolvedGraalPyVersion: '23.1.0-a.1' | ||||
|       installDir: path.join(toolDir, 'GraalPy', '24.1.0', architecture), | ||||
|       resolvedGraalPyVersion: '24.1.0-ea.9' | ||||
|     }); | ||||
|  | ||||
|     expect(spyHttpClient).toHaveBeenCalled(); | ||||
|   | ||||
							
								
								
									
										36
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							| @@ -96769,8 +96769,8 @@ async function findGraalPyVersion(versionSpec, architecture, updateEnvironment, | ||||
|     const pipDir = utils_1.IS_WINDOWS ? 'Scripts' : 'bin'; | ||||
|     const _binDir = path.join(installDir, pipDir); | ||||
|     const binaryExtension = utils_1.IS_WINDOWS ? '.exe' : ''; | ||||
|     const pythonPath = path.join(utils_1.IS_WINDOWS ? installDir : _binDir, `python${binaryExtension}`); | ||||
|     const pythonLocation = (0, utils_1.getBinaryDirectory)(installDir); | ||||
|     const pythonPath = path.join(_binDir, `python${binaryExtension}`); | ||||
|     const pythonLocation = path.join(installDir, 'bin'); | ||||
|     if (updateEnvironment) { | ||||
|         core.exportVariable('pythonLocation', installDir); | ||||
|         // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
 | ||||
| @@ -97315,7 +97315,12 @@ async function installGraalPy(graalpyVersion, architecture, allowPreReleases, re | ||||
|     try { | ||||
|         const graalpyPath = await tc.downloadTool(downloadUrl, undefined, AUTH); | ||||
|         core.info('Extracting downloaded archive...'); | ||||
|         downloadDir = await tc.extractTar(graalpyPath); | ||||
|         if (utils_1.IS_WINDOWS) { | ||||
|             downloadDir = await tc.extractZip(graalpyPath); | ||||
|         } | ||||
|         else { | ||||
|             downloadDir = await tc.extractTar(graalpyPath); | ||||
|         } | ||||
|         // root folder in archive can have unpredictable name so just take the first folder
 | ||||
|         // downloadDir is unique folder under TEMP and can't contain any other folders
 | ||||
|         const archiveName = fs_1.default.readdirSync(downloadDir)[0]; | ||||
| @@ -97324,7 +97329,7 @@ async function installGraalPy(graalpyVersion, architecture, allowPreReleases, re | ||||
|         if (!(0, utils_1.isNightlyKeyword)(resolvedGraalPyVersion)) { | ||||
|             installDir = await tc.cacheDir(toolDir, 'GraalPy', resolvedGraalPyVersion, architecture); | ||||
|         } | ||||
|         const binaryPath = (0, utils_1.getBinaryDirectory)(installDir); | ||||
|         const binaryPath = path.join(installDir, 'bin'); | ||||
|         await createGraalPySymlink(binaryPath, resolvedGraalPyVersion); | ||||
|         await installPip(binaryPath); | ||||
|         return { installDir, resolvedGraalPyVersion }; | ||||
| @@ -97352,6 +97357,9 @@ async function getAvailableGraalPyVersions() { | ||||
|     if (AUTH) { | ||||
|         headers.authorization = AUTH; | ||||
|     } | ||||
|     /* | ||||
|     Get releases first. | ||||
|     */ | ||||
|     let url = 'https://api.github.com/repos/oracle/graalpython/releases'; | ||||
|     const result = []; | ||||
|     do { | ||||
| @@ -97362,6 +97370,19 @@ async function getAvailableGraalPyVersions() { | ||||
|         result.push(...response.result); | ||||
|         url = (0, utils_1.getNextPageUrl)(response); | ||||
|     } while (url); | ||||
|     /* | ||||
|     Add pre-release builds. | ||||
|     */ | ||||
|     url = | ||||
|         'https://api.github.com/repos/graalvm/graal-languages-ea-builds/releases'; | ||||
|     do { | ||||
|         const response = await http.getJson(url, headers); | ||||
|         if (!response.result) { | ||||
|             throw new Error(`Unable to retrieve the list of available GraalPy versions from '${url}'`); | ||||
|         } | ||||
|         result.push(...response.result); | ||||
|         url = (0, utils_1.getNextPageUrl)(response); | ||||
|     } while (url); | ||||
|     return result; | ||||
| } | ||||
| async function createGraalPySymlink(graalpyBinaryPath, graalpyVersion) { | ||||
| @@ -97381,7 +97402,7 @@ async function installPip(pythonLocation) { | ||||
|     await exec.exec(`${pythonBinary} -m ensurepip --default-pip`); | ||||
| } | ||||
| function graalPyTagToVersion(tag) { | ||||
|     const versionPattern = /.*-(\d+\.\d+\.\d+(?:\.\d+)?)((?:a|b|rc))?(\d*)?/; | ||||
|     const versionPattern = /.*-(\d+\.\d+\.\d+(?:\.\d+)?)(?:-((?:ea|a|b|rc))\.0*(\d+))?/; | ||||
|     const match = tag.match(versionPattern); | ||||
|     if (match && match[2]) { | ||||
|         return `${match[1]}-${match[2]}.${match[3]}`; | ||||
| @@ -97431,8 +97452,9 @@ function toGraalPyArchitecture(architecture) { | ||||
| function findAsset(item, architecture, platform) { | ||||
|     const graalpyArch = toGraalPyArchitecture(architecture); | ||||
|     const graalpyPlatform = toGraalPyPlatform(platform); | ||||
|     const graalpyExt = platform == 'win32' ? 'zip' : 'tar.gz'; | ||||
|     const found = item.assets.filter(file => file.name.startsWith('graalpy') && | ||||
|         file.name.endsWith(`-${graalpyPlatform}-${graalpyArch}.tar.gz`)); | ||||
|         file.name.endsWith(`-${graalpyPlatform}-${graalpyArch}.${graalpyExt}`)); | ||||
|     /* | ||||
|     In the future there could be more variants of GraalPy for a single release. Pick the shortest name, that one is the most likely to be the primary variant. | ||||
|     */ | ||||
| @@ -98363,7 +98385,7 @@ function getVersionInputFromFile(versionFile) { | ||||
|     } | ||||
| } | ||||
| /** | ||||
|  * Get the directory containing interpreter binary from installation directory of PyPy or GraalPy | ||||
|  * Get the directory containing interpreter binary from installation directory of PyPy | ||||
|  *  - On Linux and macOS, the Python interpreter is in 'bin'. | ||||
|  *  - On Windows, it is in the installation root. | ||||
|  */ | ||||
|   | ||||
| @@ -1,11 +1,6 @@ | ||||
| import * as path from 'path'; | ||||
| import * as graalpyInstall from './install-graalpy'; | ||||
| import { | ||||
|   IS_WINDOWS, | ||||
|   validateVersion, | ||||
|   IGraalPyManifestRelease, | ||||
|   getBinaryDirectory | ||||
| } from './utils'; | ||||
| import {IS_WINDOWS, validateVersion, IGraalPyManifestRelease} from './utils'; | ||||
|  | ||||
| import * as semver from 'semver'; | ||||
| import * as core from '@actions/core'; | ||||
| @@ -62,11 +57,8 @@ export async function findGraalPyVersion( | ||||
|   const pipDir = IS_WINDOWS ? 'Scripts' : 'bin'; | ||||
|   const _binDir = path.join(installDir, pipDir); | ||||
|   const binaryExtension = IS_WINDOWS ? '.exe' : ''; | ||||
|   const pythonPath = path.join( | ||||
|     IS_WINDOWS ? installDir : _binDir, | ||||
|     `python${binaryExtension}` | ||||
|   ); | ||||
|   const pythonLocation = getBinaryDirectory(installDir); | ||||
|   const pythonPath = path.join(_binDir, `python${binaryExtension}`); | ||||
|   const pythonLocation = path.join(installDir, 'bin'); | ||||
|   if (updateEnvironment) { | ||||
|     core.exportVariable('pythonLocation', installDir); | ||||
|     // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython | ||||
|   | ||||
| @@ -15,7 +15,6 @@ import { | ||||
|   IGraalPyManifestRelease, | ||||
|   createSymlinkInFolder, | ||||
|   isNightlyKeyword, | ||||
|   getBinaryDirectory, | ||||
|   getNextPageUrl | ||||
| } from './utils'; | ||||
|  | ||||
| @@ -64,7 +63,11 @@ export async function installGraalPy( | ||||
|     const graalpyPath = await tc.downloadTool(downloadUrl, undefined, AUTH); | ||||
|  | ||||
|     core.info('Extracting downloaded archive...'); | ||||
|     downloadDir = await tc.extractTar(graalpyPath); | ||||
|     if (IS_WINDOWS) { | ||||
|       downloadDir = await tc.extractZip(graalpyPath); | ||||
|     } else { | ||||
|       downloadDir = await tc.extractTar(graalpyPath); | ||||
|     } | ||||
|  | ||||
|     // root folder in archive can have unpredictable name so just take the first folder | ||||
|     // downloadDir is unique folder under TEMP and can't contain any other folders | ||||
| @@ -81,7 +84,7 @@ export async function installGraalPy( | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     const binaryPath = getBinaryDirectory(installDir); | ||||
|     const binaryPath = path.join(installDir, 'bin'); | ||||
|     await createGraalPySymlink(binaryPath, resolvedGraalPyVersion); | ||||
|     await installPip(binaryPath); | ||||
|  | ||||
| @@ -115,6 +118,9 @@ export async function getAvailableGraalPyVersions() { | ||||
|     headers.authorization = AUTH; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|   Get releases first. | ||||
|   */ | ||||
|   let url: string | null = | ||||
|     'https://api.github.com/repos/oracle/graalpython/releases'; | ||||
|   const result: IGraalPyManifestRelease[] = []; | ||||
| @@ -130,6 +136,23 @@ export async function getAvailableGraalPyVersions() { | ||||
|     url = getNextPageUrl(response); | ||||
|   } while (url); | ||||
|  | ||||
|   /* | ||||
|   Add pre-release builds. | ||||
|   */ | ||||
|   url = | ||||
|     'https://api.github.com/repos/graalvm/graal-languages-ea-builds/releases'; | ||||
|   do { | ||||
|     const response: ifm.TypedResponse<IGraalPyManifestRelease[]> = | ||||
|       await http.getJson(url, headers); | ||||
|     if (!response.result) { | ||||
|       throw new Error( | ||||
|         `Unable to retrieve the list of available GraalPy versions from '${url}'` | ||||
|       ); | ||||
|     } | ||||
|     result.push(...response.result); | ||||
|     url = getNextPageUrl(response); | ||||
|   } while (url); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| @@ -175,7 +198,8 @@ async function installPip(pythonLocation: string) { | ||||
| } | ||||
|  | ||||
| export function graalPyTagToVersion(tag: string) { | ||||
|   const versionPattern = /.*-(\d+\.\d+\.\d+(?:\.\d+)?)((?:a|b|rc))?(\d*)?/; | ||||
|   const versionPattern = | ||||
|     /.*-(\d+\.\d+\.\d+(?:\.\d+)?)(?:-((?:ea|a|b|rc))\.0*(\d+))?/; | ||||
|   const match = tag.match(versionPattern); | ||||
|   if (match && match[2]) { | ||||
|     return `${match[1]}-${match[2]}.${match[3]}`; | ||||
| @@ -251,10 +275,11 @@ export function findAsset( | ||||
| ) { | ||||
|   const graalpyArch = toGraalPyArchitecture(architecture); | ||||
|   const graalpyPlatform = toGraalPyPlatform(platform); | ||||
|   const graalpyExt = platform == 'win32' ? 'zip' : 'tar.gz'; | ||||
|   const found = item.assets.filter( | ||||
|     file => | ||||
|       file.name.startsWith('graalpy') && | ||||
|       file.name.endsWith(`-${graalpyPlatform}-${graalpyArch}.tar.gz`) | ||||
|       file.name.endsWith(`-${graalpyPlatform}-${graalpyArch}.${graalpyExt}`) | ||||
|   ); | ||||
|   /* | ||||
|   In the future there could be more variants of GraalPy for a single release. Pick the shortest name, that one is the most likely to be the primary variant. | ||||
|   | ||||
| @@ -379,7 +379,7 @@ export function getVersionInputFromFile(versionFile: string): string[] { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the directory containing interpreter binary from installation directory of PyPy or GraalPy | ||||
|  * Get the directory containing interpreter binary from installation directory of PyPy | ||||
|  *  - On Linux and macOS, the Python interpreter is in 'bin'. | ||||
|  *  - On Windows, it is in the installation root. | ||||
|  */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tim Felgentreff
					Tim Felgentreff