1
+ /* eslint-disable require-atomic-updates */
1
2
import { addPath } from "../utils/env/addEnv"
2
3
import { setupAptPack } from "../utils/setup/setupAptPack"
3
4
import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
@@ -41,6 +42,7 @@ export async function setupPythonViaSystem(
41
42
// eslint-disable-next-line @typescript-eslint/no-unused-vars
42
43
_arch : string
43
44
) : Promise < InstallationInfo > {
45
+ let installInfo : InstallationInfo
44
46
switch ( process . platform ) {
45
47
case "win32" : {
46
48
if ( setupDir ) {
@@ -56,81 +58,123 @@ export async function setupPythonViaSystem(
56
58
const pythonSetupDir = dirname ( pythonBinPath )
57
59
/** The directory which the tool is installed to */
58
60
await addPath ( pythonSetupDir )
59
- return { installDir : pythonSetupDir , binDir : pythonSetupDir }
61
+ installInfo = { installDir : pythonSetupDir , binDir : pythonSetupDir }
62
+ break
60
63
}
61
64
case "darwin" : {
62
- return setupBrewPack ( "python3" , version )
65
+ installInfo = await setupBrewPack ( "python3" , version )
66
+ break
63
67
}
64
68
case "linux" : {
65
- let installInfo : InstallationInfo
66
69
if ( isArch ( ) ) {
67
70
installInfo = await setupPacmanPack ( "python" , version )
68
- await setupPacmanPack ( "python-pip" )
69
71
} else if ( hasDnf ( ) ) {
70
72
installInfo = setupDnfPack ( "python3" , version )
71
- setupDnfPack ( "python3-pip" )
72
73
} else if ( isUbuntu ( ) ) {
73
- installInfo = await setupAptPack ( [ { name : "python3" , version } , { name : "python3-pip" } ] )
74
+ installInfo = await setupAptPack ( [ { name : "python3" , version } ] )
74
75
} else {
75
76
throw new Error ( "Unsupported linux distributions" )
76
77
}
77
- return installInfo
78
+ break
78
79
}
79
80
default : {
80
81
throw new Error ( "Unsupported platform" )
81
82
}
82
83
}
84
+ await findOrSetupPip ( ( await findPython ( ) ) ! )
85
+ return installInfo
83
86
}
84
87
85
- let setupPythonAndPipTried = false
86
-
87
88
/// setup python and pip if needed
88
- export async function setupPythonAndPip ( ) : Promise < string > {
89
- let foundPython : string
89
+ export async function findOrSetupPythonAndPip ( ) : Promise < string > {
90
+ const foundPython = await findOrSetupPython ( )
91
+ const foundPip = await findOrSetupPip ( foundPython )
92
+ if ( foundPip === undefined ) {
93
+ throw new Error ( "pip was not installed correctly" )
94
+ }
95
+ setupWheel ( foundPython )
96
+ return foundPython
97
+ }
90
98
91
- // install python
99
+ let setupPythonTried = false
100
+
101
+ async function findPython ( ) {
92
102
if ( which . sync ( "python3" , { nothrow : true } ) !== null ) {
93
- foundPython = "python3"
103
+ return "python3"
94
104
} else if ( which . sync ( "python" , { nothrow : true } ) !== null && ( await isBinUptoDate ( "python" , "3.0.0" ) ) ) {
95
- foundPython = "python"
96
- } else {
97
- info ( "python3 was not found. Installing python" )
98
- await setupPython ( getVersion ( "python" , undefined ) , "" , process . arch )
99
- // try again
100
- if ( setupPythonAndPipTried ) {
101
- throw new Error ( "Failed to install python" )
102
- }
103
- setupPythonAndPipTried = true
104
- return setupPythonAndPip ( ) // recurse
105
+ return "python"
106
+ }
107
+ return undefined
108
+ }
109
+
110
+ async function findOrSetupPython ( ) {
111
+ const maybeFoundPython = await findPython ( )
112
+ if ( maybeFoundPython !== undefined ) {
113
+ return maybeFoundPython
105
114
}
106
115
107
- assert ( typeof foundPython === "string" )
116
+ if ( setupPythonTried ) {
117
+ throw new Error ( "Failed to install python" )
118
+ }
119
+ setupPythonTried = true
108
120
109
- await setupPip ( foundPython )
121
+ // install python
122
+ info ( "python3 was not found. Installing python" )
123
+ await setupPython ( getVersion ( "python" , undefined ) , "" , process . arch )
124
+ return findOrSetupPython ( ) // recurse
125
+ }
110
126
111
- // install wheel (required for Conan, Meson, etc.)
112
- execaSync ( foundPython , [ "-m" , "pip" , "install" , "-U" , "wheel" ] , { stdio : "inherit" } )
127
+ async function findOrSetupPip ( foundPython : string ) {
128
+ const maybePip = await findPip ( )
113
129
114
- return foundPython
130
+ if ( maybePip === undefined ) {
131
+ // install pip if not installed
132
+ info ( "pip was not found. Installing pip" )
133
+ await setupPip ( foundPython )
134
+ return findPip ( ) // recurse to check if pip is on PATH and up-to-date
135
+ }
136
+
137
+ return maybePip
138
+ }
139
+
140
+ async function findPip ( ) {
141
+ for ( const pip of [ "pip3" , "pip" ] ) {
142
+ if (
143
+ which . sync ( pip , { nothrow : true } ) !== null &&
144
+ // eslint-disable-next-line no-await-in-loop
145
+ ( await isBinUptoDate ( pip , DefaultVersions . pip ! ) )
146
+ ) {
147
+ return pip
148
+ }
149
+ }
150
+ return undefined
115
151
}
116
152
117
153
async function setupPip ( foundPython : string ) {
118
- const mayBePip = unique ( [ "pip3" , "pip" ] )
154
+ const upgraded = ensurePipUpgrade ( foundPython )
155
+ if ( ! upgraded ) {
156
+ await setupPipSystem ( )
157
+ }
158
+ }
119
159
120
- for ( const pip of mayBePip ) {
121
- if ( which . sync ( pip , { nothrow : true } ) !== null ) {
122
- // eslint-disable-next-line no-await-in-loop
123
- if ( await isBinUptoDate ( pip , DefaultVersions . pip ! ) ) {
124
- return pip
125
- } else {
126
- // upgrade pip
127
- execaSync ( foundPython , [ "-m" , "pip" , "install" , "-U" , "--upgrade" , "pip" ] , { stdio : "inherit" } )
128
- return setupPip ( foundPython ) // recurse to check if pip is on PATH and up-to-date
129
- }
160
+ function ensurePipUpgrade ( foundPython : string ) {
161
+ try {
162
+ execaSync ( foundPython , [ "-m" , "ensurepip" , "-U" , "--upgrade" ] , { stdio : "inherit" } )
163
+ return true
164
+ } catch {
165
+ try {
166
+ // ensure pip is disabled on Ubuntu
167
+ execaSync ( foundPython , [ "-m" , "pip" , "install" , "--upgrade" , "pip" ] , { stdio : "inherit" } )
168
+ return true
169
+ } catch {
170
+ // pip module not found
130
171
}
131
172
}
173
+ // all methods failed
174
+ return false
175
+ }
132
176
133
- // install pip if not installed
177
+ async function setupPipSystem ( ) {
134
178
if ( process . platform === "linux" ) {
135
179
// ensure that pip is installed on Linux (happens when python is found but pip not installed)
136
180
if ( isArch ( ) ) {
@@ -140,11 +184,13 @@ async function setupPip(foundPython: string) {
140
184
} else if ( isUbuntu ( ) ) {
141
185
await setupAptPack ( [ { name : "python3-pip" } ] )
142
186
}
143
- } else {
144
- throw new Error ( `Could not find pip on ${ process . platform } ` )
145
187
}
188
+ throw new Error ( `Could not install pip on ${ process . platform } ` )
189
+ }
146
190
147
- return setupPip ( foundPython ) // recurse to check if pip is on PATH and up-to-date
191
+ /** Install wheel (required for Conan, Meson, etc.) */
192
+ function setupWheel ( foundPython : string ) {
193
+ execaSync ( foundPython , [ "-m" , "pip" , "install" , "-U" , "wheel" ] , { stdio : "inherit" } )
148
194
}
149
195
150
196
export async function addPythonBaseExecPrefix ( python : string ) {
0 commit comments