-
Notifications
You must be signed in to change notification settings - Fork 2
/
python.js
149 lines (125 loc) · 5.03 KB
/
python.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os from "os"
import path from "path"
import assert from "assert"
import core from "@actions/core"
import Tool from "./tool.js"
export default class Python extends Tool {
static tool = "python"
static envVar = "PYENV_ROOT"
static envPaths = ["bin", "shims", "plugins/pyenv-virtualenv/shims"]
static installer = "pyenv"
constructor() {
super(Python.tool)
}
async setup(desiredVersion) {
const [checkVersion, isVersionOverridden] = this.getVersion(
desiredVersion,
".python-version",
)
if (!(await this.haveVersion(checkVersion))) {
if (checkVersion) {
// Ensure pip exists as well, but don't error if it breaks
await this.installPip().catch(() => {})
}
return checkVersion
}
// Check if pyenv exists and can be run, and capture the version info while
// we're at it
await this.findInstaller()
// Ensure we have the latest pyenv and python versions available
await this.updatePyenv()
// Set downstream environment variable for future steps in this Job
if (isVersionOverridden) {
core.exportVariable("PYENV_VERSION", checkVersion)
}
// using -s option to skip the install and become a no-op if the
// version requested to be installed is already installed according to pyenv.
let installCommand = `pyenv install -s`
// pyenv install does not pick up the environment variable PYENV_VERSION
// unlike tfenv, so we specify it here as an argument explicitly, if it's set
if (isVersionOverridden) installCommand += ` ${checkVersion}`
await this.subprocessShell(installCommand).catch(
this.logAndExit(`failed to install python version ${checkVersion}`),
)
// Sanity check the python command works, and output its version
await this.validateVersion(checkVersion)
// Sanity check the pip command works, and output its version
await this.version("pip --version")
// If we got this far, we have successfully configured python.
core.setOutput(Python.tool, checkVersion)
this.info("python success!")
return checkVersion
}
/**
* Update pyenv via the 'pyenv update' plugin command, if it's available.
*/
async updatePyenv() {
// Extract PYENV_VERSION to stop it complaining
// eslint-disable-next-line no-unused-vars
const { PYENV_VERSION, ...env } = process.env
const cmd = `${this.installer} update`
await this.subprocessShell(cmd, {
// Run outside the repo root so we don't pick up defined version files
cwd: process.env.RUNNER_TEMP,
env: { ...env, ...this.getEnv() },
}).catch((err) => {
this.warning(
`Failed to update pyenv, latest versions may not be supported`,
)
if (err.stderr) {
this.debug(err.stderr)
}
})
}
async setEnv() {
core.exportVariable("PYENV_VIRTUALENV_INIT", 1)
return super.setEnv()
}
/**
* Download and configures pyenv.
*
* @param {string} root - Directory to install pyenv into (PYENV_ROOT).
* @return {string} The value of PYENV_ROOT.
*/
async install(root) {
assert(root, "root is required")
const gh = `https://${process.env.GITHUB_SERVER || "github.com"}/pyenv`
const url = `${gh}/pyenv/archive/refs/heads/master.tar.gz`
root = await this.downloadTool(url, { dest: root, strip: 1 })
this.info(`Downloaded pyenv to ${root}`)
return root
}
/**
* Ensures pip is installed.
*/
async installPip() {
// Check for an existing version using whatever environment has been set
const pipVersion = await this.version("pip --version", {
soft: true,
env: { ...process.env },
}).catch(() => {})
if (pipVersion) {
this.debug(`pip is already installed (${pipVersion})`)
return
}
this.info("Installing pip")
const url = "https://bootstrap.pypa.io/get-pip.py"
const download = await this.downloadTool(url)
await this.subprocessShell(`python ${download}`, {
env: { ...process.env },
})
// get-pip.py will install to $HOME/.local/bin for a system install, so
// we add it to the PATH or things break
core.addPath(path.join(os.homedir(), ".local/bin"))
// Just run `pyenv rehash` always and ignore errors because we might be
// in a setup-python environment that doesn't have it
this.info("Rehashing pyenv shims")
await this.subprocessShell("pyenv rehash", {
env: { ...process.env },
}).catch(() => {})
// Sanity check the pip command works, and output its version
await this.version("pip --version", { env: { ...process.env } })
}
}
// Register the subclass in our tool list
Python.register()