@@ -4,16 +4,12 @@ import {
44 Event ,
55 window ,
66 Disposable ,
7- workspace ,
8- RelativePattern ,
97 Terminal ,
108 commands ,
9+ OutputChannel ,
1110} from "vscode" ;
1211import { StateStorage } from "../vscode-objs/StateStorage" ;
1312import { IExtensionApi as MsPythonExtensionApi } from "./MsPythonExtensionApi" ;
14- import * as os from "node:os" ;
15- import * as path from "node:path" ;
16- import { mkdtemp , readFile } from "fs/promises" ;
1713import { Mutex } from "../locking" ;
1814import * as childProcess from "node:child_process" ;
1915import { promisify } from "node:util" ;
@@ -88,40 +84,24 @@ export class MsPythonExtensionWrapper implements Disposable {
8884 ) ;
8985 }
9086
91- private async executeInTerminalE ( command : string ) {
92- const dir = await mkdtemp ( path . join ( os . tmpdir ( ) , "databricks-vscode-" ) ) ;
93- const filePath = path . join ( dir , "python-terminal-output.txt" ) ;
94-
95- const disposables : Disposable [ ] = [ ] ;
96- const exitCodePromise = new Promise < number | undefined > ( ( resolve ) => {
97- const fsWatcher = workspace . createFileSystemWatcher (
98- new RelativePattern ( dir , path . basename ( filePath ) )
99- ) ;
100- const handleFileChange = async ( ) => {
101- try {
102- const fileData = await readFile ( filePath , "utf-8" ) ;
103- resolve ( parseInt ( fileData ) ) ;
104- } catch ( e : unknown ) {
105- resolve ( undefined ) ;
87+ async runWithOutput (
88+ command : string ,
89+ args : string [ ] ,
90+ outputChannel ?: OutputChannel
91+ ) {
92+ const cp = childProcess . execFile ( command , args ) ;
93+ cp . stdout ?. on ( "data" , ( data ) => outputChannel ?. append ( data ) ) ;
94+ cp . stderr ?. on ( "data" , ( data ) => outputChannel ?. append ( data ) ) ;
95+ return new Promise < void > ( ( resolve , reject ) => {
96+ cp . on ( "exit" , ( code ) => {
97+ if ( code === 0 ) {
98+ resolve ( ) ;
99+ } else {
100+ reject ( new Error ( `Command exited with code ${ code } ` ) ) ;
106101 }
107- } ;
108- disposables . push (
109- fsWatcher ,
110- fsWatcher . onDidCreate ( handleFileChange ) ,
111- fsWatcher . onDidChange ( handleFileChange )
112- ) ;
102+ } ) ;
103+ cp . on ( "error" , reject ) ;
113104 } ) ;
114-
115- try {
116- await this . terminalMutex . wait ( ) ;
117- this . terminal . show ( ) ;
118- this . terminal . sendText ( `${ command } ; echo $? > ${ filePath } ` ) ;
119- const exitCode = await exitCodePromise ;
120- return exitCode ;
121- } finally {
122- disposables . forEach ( ( i ) => i . dispose ( ) ) ;
123- this . terminalMutex . signal ( ) ;
124- }
125105 }
126106
127107 async getLatestPackageVersion ( name : string ) {
@@ -190,41 +170,50 @@ export class MsPythonExtensionWrapper implements Disposable {
190170 ) ;
191171 }
192172
193- async installPackageInEnvironment ( name : string , version ?: string | RegExp ) {
173+ async installPackageInEnvironment (
174+ name : string ,
175+ version ?: string | RegExp ,
176+ outputChannel ?: OutputChannel
177+ ) {
194178 const executable = await this . getPythonExecutable ( ) ;
195179 if ( ! executable ) {
196180 throw Error ( "No python executable found" ) ;
197181 }
198182 if ( version === "latest" ) {
199183 version = await this . getLatestPackageVersion ( name ) ;
200184 }
201- const execCommand = `' ${ executable } ' -m pip install ' ${ name } ${
202- version ? `== ${ version } ` : ""
203- } ' --disable-pip-version-check --no-python-version-warning` ;
204-
205- const exitCode = await this . executeInTerminalE ( execCommand ) ;
206- if ( exitCode ) {
207- throw new Error (
208- `Error while installing ${ name } package in the current python environment.`
209- ) ;
210- }
185+ const args = [
186+ "-m" ,
187+ "pip" ,
188+ "install" ,
189+ ` ${ name } ${ version ? `== ${ version } ` : "" } ` ,
190+ "--disable-pip-version-check" ,
191+ "--no-python-version-warning" ,
192+ ] ;
193+ outputChannel ?. appendLine ( `Running: ${ executable } ${ args . join ( " " ) } ` ) ;
194+ await this . runWithOutput ( executable , args , outputChannel ) ;
211195 }
212196
213- async uninstallPackageFromEnvironment ( name : string ) {
197+ async uninstallPackageFromEnvironment (
198+ name : string ,
199+ outputChannel ?: OutputChannel
200+ ) {
214201 const exists = await this . findPackageInEnvironment ( name ) ;
215202 const executable = await this . getPythonExecutable ( ) ;
216-
217203 if ( ! exists || ! executable ) {
218204 return ;
219205 }
220-
221- const execCommand = `'${ executable } ' -m pip uninstall '${ name } ' --disable-pip-version-check --no-python-version-warning -y` ;
222- const exitCode = await this . executeInTerminalE ( execCommand ) ;
223- if ( exitCode ) {
224- throw new Error (
225- `Error while un-installing ${ name } package from the current python environment.`
226- ) ;
227- }
206+ const args = [
207+ "-m" ,
208+ "pip" ,
209+ "uninstall" ,
210+ name ,
211+ "--disable-pip-version-check" ,
212+ "--no-python-version-warning" ,
213+ "-y" ,
214+ ] ;
215+ outputChannel ?. appendLine ( `Running: ${ executable } ${ args . join ( " " ) } ` ) ;
216+ await this . runWithOutput ( executable , args , outputChannel ) ;
228217 }
229218
230219 async selectPythonInterpreter ( ) {
0 commit comments