1+ /* eslint-disable require-atomic-updates */
12import { addPath } from "../utils/env/addEnv"
23import { setupAptPack } from "../utils/setup/setupAptPack"
34import { setupPacmanPack } from "../utils/setup/setupPacmanPack"
@@ -41,6 +42,7 @@ export async function setupPythonViaSystem(
4142 // eslint-disable-next-line @typescript-eslint/no-unused-vars
4243 _arch : string
4344) : Promise < InstallationInfo > {
45+ let installInfo : InstallationInfo
4446 switch ( process . platform ) {
4547 case "win32" : {
4648 if ( setupDir ) {
@@ -56,81 +58,123 @@ export async function setupPythonViaSystem(
5658 const pythonSetupDir = dirname ( pythonBinPath )
5759 /** The directory which the tool is installed to */
5860 await addPath ( pythonSetupDir )
59- return { installDir : pythonSetupDir , binDir : pythonSetupDir }
61+ installInfo = { installDir : pythonSetupDir , binDir : pythonSetupDir }
62+ break
6063 }
6164 case "darwin" : {
62- return setupBrewPack ( "python3" , version )
65+ installInfo = await setupBrewPack ( "python3" , version )
66+ break
6367 }
6468 case "linux" : {
65- let installInfo : InstallationInfo
6669 if ( isArch ( ) ) {
6770 installInfo = await setupPacmanPack ( "python" , version )
68- await setupPacmanPack ( "python-pip" )
6971 } else if ( hasDnf ( ) ) {
7072 installInfo = setupDnfPack ( "python3" , version )
71- setupDnfPack ( "python3-pip" )
7273 } else if ( isUbuntu ( ) ) {
73- installInfo = await setupAptPack ( [ { name : "python3" , version } , { name : "python3-pip" } ] )
74+ installInfo = await setupAptPack ( [ { name : "python3" , version } ] )
7475 } else {
7576 throw new Error ( "Unsupported linux distributions" )
7677 }
77- return installInfo
78+ break
7879 }
7980 default : {
8081 throw new Error ( "Unsupported platform" )
8182 }
8283 }
84+ await findOrSetupPip ( ( await findPython ( ) ) ! )
85+ return installInfo
8386}
8487
85- let setupPythonAndPipTried = false
86-
8788/// 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+ }
9098
91- // install python
99+ let setupPythonTried = false
100+
101+ async function findPython ( ) {
92102 if ( which . sync ( "python3" , { nothrow : true } ) !== null ) {
93- foundPython = "python3"
103+ return "python3"
94104 } 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
105114 }
106115
107- assert ( typeof foundPython === "string" )
116+ if ( setupPythonTried ) {
117+ throw new Error ( "Failed to install python" )
118+ }
119+ setupPythonTried = true
108120
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+ }
110126
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 ( )
113129
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
115151}
116152
117153async function setupPip ( foundPython : string ) {
118- const mayBePip = unique ( [ "pip3" , "pip" ] )
154+ const upgraded = ensurePipUpgrade ( foundPython )
155+ if ( ! upgraded ) {
156+ await setupPipSystem ( )
157+ }
158+ }
119159
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
130171 }
131172 }
173+ // all methods failed
174+ return false
175+ }
132176
133- // install pip if not installed
177+ async function setupPipSystem ( ) {
134178 if ( process . platform === "linux" ) {
135179 // ensure that pip is installed on Linux (happens when python is found but pip not installed)
136180 if ( isArch ( ) ) {
@@ -140,11 +184,13 @@ async function setupPip(foundPython: string) {
140184 } else if ( isUbuntu ( ) ) {
141185 await setupAptPack ( [ { name : "python3-pip" } ] )
142186 }
143- } else {
144- throw new Error ( `Could not find pip on ${ process . platform } ` )
145187 }
188+ throw new Error ( `Could not install pip on ${ process . platform } ` )
189+ }
146190
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" } )
148194}
149195
150196export async function addPythonBaseExecPrefix ( python : string ) {
0 commit comments