Merge pull request #139 from aminya/python-fix [skip ci]

This commit is contained in:
Amin Yahyaabadi 2022-11-04 20:16:57 -07:00 committed by GitHub
commit 9c8f057dbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 106 additions and 78 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,13 @@ import { dirname, join } from "patha"
import { hasDnf } from "../utils/env/hasDnf" import { hasDnf } from "../utils/env/hasDnf"
import { setupDnfPack } from "../utils/setup/setupDnfPack" import { setupDnfPack } from "../utils/setup/setupDnfPack"
import { isUbuntu } from "../utils/env/isUbuntu" import { isUbuntu } from "../utils/env/isUbuntu"
import { getExecOutput } from "@actions/exec"
import { existsSync } from "fs"
import { isBinUptoDate } from "../utils/setup/version"
import { getVersion } from "../versions/versions"
import assert from "assert"
import execa from "execa"
import { unique } from "../utils/std"
export async function setupPython(version: string, setupDir: string, arch: string) { export async function setupPython(version: string, setupDir: string, arch: string) {
if (ciDetect() !== "github-actions") { if (ciDetect() !== "github-actions") {
@ -48,7 +55,7 @@ export async function setupPythonViaSystem(
join(setupDir, "python.exe") join(setupDir, "python.exe")
const pythonSetupDir = dirname(pythonBinPath) const pythonSetupDir = dirname(pythonBinPath)
/** The directory which the tool is installed to */ /** The directory which the tool is installed to */
await activateWinPython(pythonSetupDir) await addPath(pythonSetupDir)
return { installDir: pythonSetupDir, binDir: pythonSetupDir } return { installDir: pythonSetupDir, binDir: pythonSetupDir }
} }
case "darwin": { case "darwin": {
@ -76,7 +83,67 @@ export async function setupPythonViaSystem(
} }
} }
async function activateWinPython(binDir: string) { let setupPythonAndPipTried = false
info(`Add ${binDir} to PATH`)
await addPath(binDir) /// setup python and pip if needed
export async function setupPythonAndPip(): Promise<string> {
let foundPython: string
// install python
if (which.sync("python3", { nothrow: true }) !== null) {
foundPython = "python3"
} else if (which.sync("python", { nothrow: true }) !== null && (await isBinUptoDate("python", "3.0.0"))) {
foundPython = "python"
} else {
info("python3 was not found. Installing python")
await setupPython(getVersion("python", undefined), "", process.arch)
// try again
if (setupPythonAndPipTried) {
throw new Error("Failed to install python")
}
setupPythonAndPipTried = true
return setupPythonAndPip() // recurse
}
assert(typeof foundPython === "string")
// install pip
if (process.platform === "win32") {
// downgrade pip on Windows
// https://github.com/pypa/pip/issues/10875#issuecomment-1030293005
execa.sync(foundPython, ["-m", "pip", "install", "-U", "pip==21.3.1"], { stdio: "inherit" })
} else if (process.platform === "linux") {
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
if (isArch()) {
setupPacmanPack("python-pip")
} else if (hasDnf()) {
setupDnfPack("python3-pip")
} else if (isUbuntu()) {
await setupAptPack("python3-pip")
}
}
// install wheel (required for Conan, Meson, etc.)
execa.sync(foundPython, ["-m", "pip", "install", "-U", "wheel"], { stdio: "inherit" })
return foundPython
}
export async function addPythonBaseExecPrefix(python: string) {
const dirs: string[] = []
// detection based on the platform
if (process.platform === "linux") {
dirs.push("/home/runner/.local/bin/")
} else if (process.platform === "darwin") {
dirs.push("/usr/local/bin/")
}
// detection using python.sys
const base_exec_prefix = (await getExecOutput(`${python} -c "import sys;print(sys.base_exec_prefix);"`)).stdout.trim()
// any of these are possible depending on the operating system!
dirs.push(join(base_exec_prefix, "Scripts"), join(base_exec_prefix, "Scripts", "bin"), join(base_exec_prefix, "bin"))
// remove duplicates
return unique(dirs)
} }

View File

@ -1,91 +1,49 @@
/* eslint-disable require-atomic-updates */ /* eslint-disable require-atomic-updates */
import { getExecOutput } from "@actions/exec"
import execa from "execa" import execa from "execa"
import which from "which"
import { info } from "@actions/core" import { info } from "@actions/core"
import { addPath } from "../env/addEnv" import { addPythonBaseExecPrefix, setupPythonAndPip } from "../../python/python"
import { setupPython } from "../../python/python"
import { isBinUptoDate } from "./version"
import { join } from "patha"
import { getVersion } from "../../versions/versions"
import { InstallationInfo } from "./setupBin" import { InstallationInfo } from "./setupBin"
import { setupAptPack } from "./setupAptPack" import { existsSync } from "fs"
import { setupPacmanPack } from "./setupPacmanPack" import { addExeExt, dirname, join } from "patha"
import { isArch } from "../env/isArch" import { addPath } from "../env/addEnv"
import { isUbuntu } from "../env/isUbuntu" import which from "which"
import { hasDnf } from "../env/hasDnf"
import { setupDnfPack } from "./setupDnfPack"
let python: string | undefined let python: string | undefined
let binDir: string | undefined let binDirs: string[] | undefined
let tried = false
/** A function that installs a package using pip */ /** A function that installs a package using pip */
export async function setupPipPack(name: string, version?: string): Promise<InstallationInfo> { export async function setupPipPack(name: string, version?: string): Promise<InstallationInfo> {
info(`Installing ${name} ${version ?? ""} via pip`) info(`Installing ${name} ${version ?? ""} via pip`)
// setup python and pip if needed
if (python === undefined) { if (python === undefined) {
if (which.sync("python3", { nothrow: true }) !== null) { python = await setupPythonAndPip()
python = "python3"
} else if (which.sync("python", { nothrow: true }) !== null && (await isBinUptoDate("python", "3.0.0"))) {
python = "python"
} else {
info("python3 was not found. Installing python")
await setupPython(getVersion("python", undefined), "", process.arch)
// try again
if (tried) {
throw new Error("Failed to install python")
}
tried = true
return setupPipPack(name, version)
}
if (process.platform === "win32") {
// downgrade pip on Windows
// https://github.com/pypa/pip/issues/10875#issuecomment-1030293005
execa.sync(python, ["-m", "pip", "install", "-U", "pip==21.3.1"], { stdio: "inherit" })
} else if (process.platform === "linux") {
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
if (isArch()) {
setupPacmanPack("python-pip")
} else if (hasDnf()) {
setupDnfPack("python3-pip")
} else if (isUbuntu()) {
await setupAptPack("python3-pip")
}
}
// install wheel (required for Conan, Meson, etc.)
execa.sync(python, ["-m", "pip", "install", "-U", "wheel"], { stdio: "inherit" })
} }
execa.sync(python, ["-m", "pip", "install", version !== undefined && version !== "" ? `${name}==${version}` : name], { execa.sync(python, ["-m", "pip", "install", version !== undefined && version !== "" ? `${name}==${version}` : name], {
stdio: "inherit", stdio: "inherit",
}) })
if (binDir === undefined) { if (binDirs === undefined) {
if (process.platform === "linux") { binDirs = await addPythonBaseExecPrefix(python)
binDir = "/home/runner/.local/bin/"
} else if (process.platform === "darwin") {
binDir = "/usr/local/bin/"
} else {
// windows or others
try {
binDir = join(
(await getExecOutput(`${python} -c "import sys;print(sys.base_exec_prefix);"`)).stdout.trim(),
"Scripts"
)
} catch {
binDir = join(
(await getExecOutput(`${python} -c "import sys;print(sys.base_exec_prefix);"`)).stdout.trim(),
"Scripts"
)
} }
}
info(`${binDir} to PATH`) const binDir = findBinDir(binDirs, name)
await addPath(binDir) await addPath(binDir)
}
return { binDir } return { binDir }
} }
function findBinDir(dirs: string[], name: string) {
const foundDir = dirs.find((dir) => existsSync(join(dir, addExeExt(name))))
if (foundDir !== undefined) {
return foundDir
}
const whichDir = which.sync(addExeExt(name), { nothrow: true })
if (whichDir !== null) {
return dirname(whichDir)
}
return dirs[dirs.length - 1]
}

3
src/utils/std/index.ts Normal file
View File

@ -0,0 +1,3 @@
export function unique(dirs: string[]) {
return [...new Set(dirs)]
}

View File

@ -14,7 +14,7 @@ export const DefaultVersions: Record<string, string> = {
meson: "0.63.3", // https://github.com/mesonbuild/meson/releases meson: "0.63.3", // https://github.com/mesonbuild/meson/releases
kcov: "40", // https://github.com/SimonKagstrom/kcov/releases kcov: "40", // https://github.com/SimonKagstrom/kcov/releases
task: "3.16.0", // https://github.com/go-task/task/releases task: "3.16.0", // https://github.com/go-task/task/releases
doxygen: isArch() ? "1.9.3-1" : "1.9.5", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/ doxygen: isArch() ? "1.9.5-1" : "1.9.5", // https://www.doxygen.nl/download.html // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=doxygen // https://formulae.brew.sh/formula/doxygen // https://archlinux.org/packages/extra/x86_64/doxygen/
gcc: "11", // https://github.com/brechtsanders/winlibs_mingw/releases and // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=gcc gcc: "11", // https://github.com/brechtsanders/winlibs_mingw/releases and // https://packages.ubuntu.com/search?suite=all&arch=any&searchon=names&keywords=gcc
} }