mirror of
				https://kkgithub.com/actions/setup-python.git
				synced 2025-11-04 12:44:05 +08:00 
			
		
		
		
	* Add ESLint, update Prettier * Update docs * Update tests * Update licenses * Fix review points
		
			
				
	
	
		
			191 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as path from 'path';
 | 
						|
import * as pypyInstall from './install-pypy';
 | 
						|
import {
 | 
						|
  IS_WINDOWS,
 | 
						|
  WINDOWS_ARCHS,
 | 
						|
  validateVersion,
 | 
						|
  getPyPyVersionFromPath,
 | 
						|
  readExactPyPyVersionFile,
 | 
						|
  validatePythonVersionFormatForPyPy,
 | 
						|
  IPyPyManifestRelease
 | 
						|
} from './utils';
 | 
						|
 | 
						|
import * as semver from 'semver';
 | 
						|
import * as core from '@actions/core';
 | 
						|
import * as tc from '@actions/tool-cache';
 | 
						|
 | 
						|
interface IPyPyVersionSpec {
 | 
						|
  pypyVersion: string;
 | 
						|
  pythonVersion: string;
 | 
						|
}
 | 
						|
 | 
						|
export async function findPyPyVersion(
 | 
						|
  versionSpec: string,
 | 
						|
  architecture: string,
 | 
						|
  updateEnvironment: boolean,
 | 
						|
  checkLatest: boolean,
 | 
						|
  allowPreReleases: boolean
 | 
						|
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
 | 
						|
  let resolvedPyPyVersion = '';
 | 
						|
  let resolvedPythonVersion = '';
 | 
						|
  let installDir: string | null;
 | 
						|
  let releases: IPyPyManifestRelease[] | undefined;
 | 
						|
 | 
						|
  const pypyVersionSpec = parsePyPyVersion(versionSpec);
 | 
						|
 | 
						|
  if (checkLatest) {
 | 
						|
    releases = await pypyInstall.getAvailablePyPyVersions();
 | 
						|
    if (releases && releases.length > 0) {
 | 
						|
      const releaseData = pypyInstall.findRelease(
 | 
						|
        releases,
 | 
						|
        pypyVersionSpec.pythonVersion,
 | 
						|
        pypyVersionSpec.pypyVersion,
 | 
						|
        architecture,
 | 
						|
        false
 | 
						|
      );
 | 
						|
 | 
						|
      if (releaseData) {
 | 
						|
        core.info(
 | 
						|
          `Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`
 | 
						|
        );
 | 
						|
        pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
 | 
						|
        pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion;
 | 
						|
      } else {
 | 
						|
        core.info(
 | 
						|
          `Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest`
 | 
						|
        );
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache(
 | 
						|
    pypyVersionSpec.pythonVersion,
 | 
						|
    pypyVersionSpec.pypyVersion,
 | 
						|
    architecture
 | 
						|
  ));
 | 
						|
 | 
						|
  if (!installDir) {
 | 
						|
    ({installDir, resolvedPythonVersion, resolvedPyPyVersion} =
 | 
						|
      await pypyInstall.installPyPy(
 | 
						|
        pypyVersionSpec.pypyVersion,
 | 
						|
        pypyVersionSpec.pythonVersion,
 | 
						|
        architecture,
 | 
						|
        allowPreReleases,
 | 
						|
        releases
 | 
						|
      ));
 | 
						|
  }
 | 
						|
 | 
						|
  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 = pypyInstall.getPyPyBinaryPath(installDir);
 | 
						|
  if (updateEnvironment) {
 | 
						|
    core.exportVariable('pythonLocation', installDir);
 | 
						|
    // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython
 | 
						|
    core.exportVariable('Python_ROOT_DIR', installDir);
 | 
						|
    // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2
 | 
						|
    core.exportVariable('Python2_ROOT_DIR', installDir);
 | 
						|
    // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3
 | 
						|
    core.exportVariable('Python3_ROOT_DIR', installDir);
 | 
						|
    core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig');
 | 
						|
    core.addPath(pythonLocation);
 | 
						|
    core.addPath(_binDir);
 | 
						|
  }
 | 
						|
  core.setOutput('python-version', 'pypy' + resolvedPyPyVersion);
 | 
						|
  core.setOutput('python-path', pythonPath);
 | 
						|
 | 
						|
  return {resolvedPyPyVersion, resolvedPythonVersion};
 | 
						|
}
 | 
						|
 | 
						|
export function findPyPyToolCache(
 | 
						|
  pythonVersion: string,
 | 
						|
  pypyVersion: string,
 | 
						|
  architecture: string
 | 
						|
) {
 | 
						|
  let resolvedPyPyVersion = '';
 | 
						|
  let resolvedPythonVersion = '';
 | 
						|
  let installDir: string | null = IS_WINDOWS
 | 
						|
    ? findPyPyInstallDirForWindows(pythonVersion)
 | 
						|
    : tc.find('PyPy', pythonVersion, architecture);
 | 
						|
 | 
						|
  if (installDir) {
 | 
						|
    // 'tc.find' finds tool based on Python version but we also need to check
 | 
						|
    // whether PyPy version satisfies requested version.
 | 
						|
    resolvedPythonVersion = getPyPyVersionFromPath(installDir);
 | 
						|
    resolvedPyPyVersion = readExactPyPyVersionFile(installDir);
 | 
						|
 | 
						|
    const isPyPyVersionSatisfies = semver.satisfies(
 | 
						|
      resolvedPyPyVersion,
 | 
						|
      pypyVersion
 | 
						|
    );
 | 
						|
    if (!isPyPyVersionSatisfies) {
 | 
						|
      installDir = null;
 | 
						|
      resolvedPyPyVersion = '';
 | 
						|
      resolvedPythonVersion = '';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!installDir) {
 | 
						|
    core.info(
 | 
						|
      `PyPy version ${pythonVersion} (${pypyVersion}) was not found in the local cache`
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  return {installDir, resolvedPythonVersion, resolvedPyPyVersion};
 | 
						|
}
 | 
						|
 | 
						|
export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
 | 
						|
  const versions = versionSpec.split('-').filter(item => !!item);
 | 
						|
 | 
						|
  if (/^(pypy)(.+)/.test(versions[0])) {
 | 
						|
    const pythonVersion = versions[0].replace('pypy', '');
 | 
						|
    versions.splice(0, 1, 'pypy', pythonVersion);
 | 
						|
  }
 | 
						|
 | 
						|
  if (versions.length < 2 || versions[0] != 'pypy') {
 | 
						|
    throw new Error(
 | 
						|
      "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or 'pypy-<python-version>'. See README for examples and documentation."
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  const pythonVersion = versions[1];
 | 
						|
  let pypyVersion: string;
 | 
						|
  if (versions.length > 2) {
 | 
						|
    pypyVersion = pypyInstall.pypyVersionToSemantic(versions[2]);
 | 
						|
  } else {
 | 
						|
    pypyVersion = 'x';
 | 
						|
  }
 | 
						|
 | 
						|
  if (!validateVersion(pythonVersion) || !validateVersion(pypyVersion)) {
 | 
						|
    throw new Error(
 | 
						|
      "Invalid 'version' property for PyPy. Both Python version and PyPy versions should satisfy SemVer notation. See README for examples and documentation."
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  if (!validatePythonVersionFormatForPyPy(pythonVersion)) {
 | 
						|
    throw new Error(
 | 
						|
      "Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation."
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  return {
 | 
						|
    pypyVersion: pypyVersion,
 | 
						|
    pythonVersion: pythonVersion
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
export function findPyPyInstallDirForWindows(pythonVersion: string): string {
 | 
						|
  let installDir = '';
 | 
						|
 | 
						|
  WINDOWS_ARCHS.forEach(
 | 
						|
    architecture =>
 | 
						|
      (installDir = installDir || tc.find('PyPy', pythonVersion, architecture))
 | 
						|
  );
 | 
						|
 | 
						|
  return installDir;
 | 
						|
}
 |