mirror of https://github.com/aminya/setup-cpp
feat: more robust pip installation and upgrade
This commit is contained in:
parent
7039a1a602
commit
0f6b349a1e
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
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
import { addPath } from "../utils/env/addEnv"
|
import { addPath } from "../utils/env/addEnv"
|
||||||
import { setupAptPack } from "../utils/setup/setupAptPack"
|
import { setupAptPack } from "../utils/setup/setupAptPack"
|
||||||
import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
|
import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
|
||||||
|
@ -41,6 +42,7 @@ export async function setupPythonViaSystem(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
_arch: string
|
_arch: string
|
||||||
): Promise<InstallationInfo> {
|
): Promise<InstallationInfo> {
|
||||||
|
let installInfo: InstallationInfo
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "win32": {
|
case "win32": {
|
||||||
if (setupDir) {
|
if (setupDir) {
|
||||||
|
@ -56,81 +58,123 @@ export async function setupPythonViaSystem(
|
||||||
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 addPath(pythonSetupDir)
|
await addPath(pythonSetupDir)
|
||||||
return { installDir: pythonSetupDir, binDir: pythonSetupDir }
|
installInfo = { installDir: pythonSetupDir, binDir: pythonSetupDir }
|
||||||
|
break
|
||||||
}
|
}
|
||||||
case "darwin": {
|
case "darwin": {
|
||||||
return setupBrewPack("python3", version)
|
installInfo = await setupBrewPack("python3", version)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
case "linux": {
|
case "linux": {
|
||||||
let installInfo: InstallationInfo
|
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
installInfo = await setupPacmanPack("python", version)
|
installInfo = await setupPacmanPack("python", version)
|
||||||
await setupPacmanPack("python-pip")
|
|
||||||
} else if (hasDnf()) {
|
} else if (hasDnf()) {
|
||||||
installInfo = setupDnfPack("python3", version)
|
installInfo = setupDnfPack("python3", version)
|
||||||
setupDnfPack("python3-pip")
|
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
installInfo = await setupAptPack([{ name: "python3", version }, { name: "python3-pip" }])
|
installInfo = await setupAptPack([{ name: "python3", version }])
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unsupported linux distributions")
|
throw new Error("Unsupported linux distributions")
|
||||||
}
|
}
|
||||||
return installInfo
|
break
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error("Unsupported platform")
|
throw new Error("Unsupported platform")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await findOrSetupPip((await findPython())!)
|
||||||
|
return installInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
let setupPythonAndPipTried = false
|
|
||||||
|
|
||||||
/// setup python and pip if needed
|
/// setup python and pip if needed
|
||||||
export async function setupPythonAndPip(): Promise<string> {
|
export async function findOrSetupPythonAndPip(): Promise<string> {
|
||||||
let foundPython: string
|
const foundPython = await findOrSetupPython()
|
||||||
|
const foundPip = await findOrSetupPip(foundPython)
|
||||||
// install python
|
if (foundPip === undefined) {
|
||||||
if (which.sync("python3", { nothrow: true }) !== null) {
|
throw new Error("pip was not installed correctly")
|
||||||
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
|
setupWheel(foundPython)
|
||||||
return setupPythonAndPip() // recurse
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(typeof foundPython === "string")
|
|
||||||
|
|
||||||
await setupPip(foundPython)
|
|
||||||
|
|
||||||
// install wheel (required for Conan, Meson, etc.)
|
|
||||||
execaSync(foundPython, ["-m", "pip", "install", "-U", "wheel"], { stdio: "inherit" })
|
|
||||||
|
|
||||||
return foundPython
|
return foundPython
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupPip(foundPython: string) {
|
let setupPythonTried = false
|
||||||
const mayBePip = unique(["pip3", "pip"])
|
|
||||||
|
|
||||||
for (const pip of mayBePip) {
|
async function findPython() {
|
||||||
if (which.sync(pip, { nothrow: true }) !== null) {
|
if (which.sync("python3", { nothrow: true }) !== null) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
return "python3"
|
||||||
if (await isBinUptoDate(pip, DefaultVersions.pip!)) {
|
} else if (which.sync("python", { nothrow: true }) !== null && (await isBinUptoDate("python", "3.0.0"))) {
|
||||||
return pip
|
return "python"
|
||||||
} else {
|
|
||||||
// upgrade pip
|
|
||||||
execaSync(foundPython, ["-m", "pip", "install", "-U", "--upgrade", "pip"], { stdio: "inherit" })
|
|
||||||
return setupPip(foundPython) // recurse to check if pip is on PATH and up-to-date
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function findOrSetupPython() {
|
||||||
|
const maybeFoundPython = await findPython()
|
||||||
|
if (maybeFoundPython !== undefined) {
|
||||||
|
return maybeFoundPython
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setupPythonTried) {
|
||||||
|
throw new Error("Failed to install python")
|
||||||
|
}
|
||||||
|
setupPythonTried = true
|
||||||
|
|
||||||
|
// install python
|
||||||
|
info("python3 was not found. Installing python")
|
||||||
|
await setupPython(getVersion("python", undefined), "", process.arch)
|
||||||
|
return findOrSetupPython() // recurse
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findOrSetupPip(foundPython: string) {
|
||||||
|
const maybePip = await findPip()
|
||||||
|
|
||||||
|
if (maybePip === undefined) {
|
||||||
// install pip if not installed
|
// install pip if not installed
|
||||||
|
info("pip was not found. Installing pip")
|
||||||
|
await setupPip(foundPython)
|
||||||
|
return findPip() // recurse to check if pip is on PATH and up-to-date
|
||||||
|
}
|
||||||
|
|
||||||
|
return maybePip
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findPip() {
|
||||||
|
for (const pip of ["pip3", "pip"]) {
|
||||||
|
if (
|
||||||
|
which.sync(pip, { nothrow: true }) !== null &&
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
(await isBinUptoDate(pip, DefaultVersions.pip!))
|
||||||
|
) {
|
||||||
|
return pip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupPip(foundPython: string) {
|
||||||
|
const upgraded = ensurePipUpgrade(foundPython)
|
||||||
|
if (!upgraded) {
|
||||||
|
await setupPipSystem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensurePipUpgrade(foundPython: string) {
|
||||||
|
try {
|
||||||
|
execaSync(foundPython, ["-m", "ensurepip", "-U", "--upgrade"], { stdio: "inherit" })
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
// ensure pip is disabled on Ubuntu
|
||||||
|
execaSync(foundPython, ["-m", "pip", "install", "--upgrade", "pip"], { stdio: "inherit" })
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
// pip module not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all methods failed
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupPipSystem() {
|
||||||
if (process.platform === "linux") {
|
if (process.platform === "linux") {
|
||||||
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
|
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
|
||||||
if (isArch()) {
|
if (isArch()) {
|
||||||
|
@ -140,11 +184,13 @@ async function setupPip(foundPython: string) {
|
||||||
} else if (isUbuntu()) {
|
} else if (isUbuntu()) {
|
||||||
await setupAptPack([{ name: "python3-pip" }])
|
await setupAptPack([{ name: "python3-pip" }])
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
throw new Error(`Could not find pip on ${process.platform}`)
|
throw new Error(`Could not install pip on ${process.platform}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupPip(foundPython) // recurse to check if pip is on PATH and up-to-date
|
/** Install wheel (required for Conan, Meson, etc.) */
|
||||||
|
function setupWheel(foundPython: string) {
|
||||||
|
execaSync(foundPython, ["-m", "pip", "install", "-U", "wheel"], { stdio: "inherit" })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addPythonBaseExecPrefix(python: string) {
|
export async function addPythonBaseExecPrefix(python: string) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { execaSync } from "execa"
|
||||||
import { pathExists } from "path-exists"
|
import { pathExists } from "path-exists"
|
||||||
import { addExeExt, dirname, join } from "patha"
|
import { addExeExt, dirname, join } from "patha"
|
||||||
import which from "which"
|
import which from "which"
|
||||||
import { addPythonBaseExecPrefix, setupPythonAndPip } from "../../python/python"
|
import { addPythonBaseExecPrefix, findOrSetupPythonAndPip } from "../../python/python"
|
||||||
import { addPath } from "../env/addEnv"
|
import { addPath } from "../env/addEnv"
|
||||||
import { InstallationInfo } from "./setupBin"
|
import { InstallationInfo } from "./setupBin"
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export async function setupPipPack(name: string, version?: string): Promise<Inst
|
||||||
info(`Installing ${name} ${version ?? ""} via pip`)
|
info(`Installing ${name} ${version ?? ""} via pip`)
|
||||||
|
|
||||||
if (python === undefined) {
|
if (python === undefined) {
|
||||||
python = await setupPythonAndPip()
|
python = await findOrSetupPythonAndPip()
|
||||||
}
|
}
|
||||||
|
|
||||||
execaSync(python, ["-m", "pip", "install", version !== undefined && version !== "" ? `${name}==${version}` : name], {
|
execaSync(python, ["-m", "pip", "install", version !== undefined && version !== "" ? `${name}==${version}` : name], {
|
||||||
|
|
Loading…
Reference in New Issue