@@ -6,7 +6,7 @@ import { inject, injectable } from 'inversify';
6
6
import { DiagnosticSeverity , l10n } from 'vscode' ;
7
7
import '../../../common/extensions' ;
8
8
import * as path from 'path' ;
9
- import { IDisposableRegistry , IInterpreterPathService , Resource } from '../../../common/types' ;
9
+ import { IConfigurationService , IDisposableRegistry , IInterpreterPathService , Resource } from '../../../common/types' ;
10
10
import { IInterpreterService } from '../../../interpreter/contracts' ;
11
11
import { IServiceContainer } from '../../../ioc/types' ;
12
12
import { BaseDiagnostic , BaseDiagnosticsService } from '../base' ;
@@ -28,10 +28,11 @@ import { EventName } from '../../../telemetry/constants';
28
28
import { IExtensionSingleActivationService } from '../../../activation/types' ;
29
29
import { cache } from '../../../common/utils/decorators' ;
30
30
import { noop } from '../../../common/utils/misc' ;
31
- import { IPythonExecutionFactory } from '../../../common/process/types' ;
32
31
import { getOSType , OSType } from '../../../common/utils/platform' ;
33
32
import { IFileSystem } from '../../../common/platform/types' ;
34
33
import { traceError } from '../../../logging' ;
34
+ import { getExecutable } from '../../../common/process/internal/python' ;
35
+ import { shellExec } from '../../../common/process/rawProcessApis' ;
35
36
36
37
const messages = {
37
38
[ DiagnosticCodes . NoPythonInterpretersDiagnostic ] : l10n . t (
@@ -41,7 +42,7 @@ const messages = {
41
42
'An Invalid Python interpreter is selected{0}, please try changing it to enable features such as IntelliSense, linting, and debugging. See output for more details regarding why the interpreter is invalid.' ,
42
43
) ,
43
44
[ DiagnosticCodes . InvalidComspecDiagnostic ] : l10n . t (
44
- "The environment variable 'Comspec' seems to be set to an invalid value. Please correct it to carry valid path to Command Prompt to enable features such as IntelliSense, linting, and debugging. See instructions which might help." ,
45
+ 'We detected an issue with one of your environment variables that breaks features such as IntelliSense, linting and debugging. Try setting the "ComSpec" to a valid Command Prompt path in your system to fix it.' ,
45
46
) ,
46
47
} ;
47
48
@@ -112,20 +113,16 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
112
113
) ;
113
114
}
114
115
115
- // eslint-disable-next-line class-methods-use-this
116
- public async diagnose ( _resource : Resource ) : Promise < IDiagnostic [ ] > {
117
- return [ ] ;
116
+ public async diagnose ( resource : Resource ) : Promise < IDiagnostic [ ] > {
117
+ return this . diagnoseDefaultShell ( resource ) ;
118
118
}
119
119
120
120
public async _manualDiagnose ( resource : Resource ) : Promise < IDiagnostic [ ] > {
121
121
const workspaceService = this . serviceContainer . get < IWorkspaceService > ( IWorkspaceService ) ;
122
122
const interpreterService = this . serviceContainer . get < IInterpreterService > ( IInterpreterService ) ;
123
- const currentInterpreter = await interpreterService . getActiveInterpreter ( resource ) ;
124
- if ( ! currentInterpreter ) {
125
- const diagnostics = await this . diagnoseDefaultShell ( resource ) ;
126
- if ( diagnostics . length ) {
127
- return diagnostics ;
128
- }
123
+ const diagnostics = await this . diagnoseDefaultShell ( resource ) ;
124
+ if ( diagnostics . length ) {
125
+ return diagnostics ;
129
126
}
130
127
const hasInterpreters = await interpreterService . hasInterpreters ( ) ;
131
128
const interpreterPathService = this . serviceContainer . get < IInterpreterPathService > ( IInterpreterPathService ) ;
@@ -142,6 +139,7 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
142
139
] ;
143
140
}
144
141
142
+ const currentInterpreter = await interpreterService . getActiveInterpreter ( resource ) ;
145
143
if ( ! currentInterpreter ) {
146
144
return [
147
145
new InvalidPythonInterpreterDiagnostic (
@@ -189,7 +187,7 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
189
187
if ( diagnostic . code === DiagnosticCodes . InvalidComspecDiagnostic ) {
190
188
return [
191
189
{
192
- prompt : Common . instructions ,
190
+ prompt : Common . seeInstructions ,
193
191
command : commandFactory . createCommand ( diagnostic , {
194
192
type : 'launch' ,
195
193
options : 'https://aka.ms/AAk3djo' ,
@@ -222,12 +220,16 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
222
220
if ( getOSType ( ) !== OSType . Windows ) {
223
221
return [ ] ;
224
222
}
225
- const executionFactory = this . serviceContainer . get < IPythonExecutionFactory > ( IPythonExecutionFactory ) ;
226
- const executionService = await executionFactory . create ( { resource } ) ;
223
+ const interpreterService = this . serviceContainer . get < IInterpreterService > ( IInterpreterService ) ;
224
+ const currentInterpreter = await interpreterService . getActiveInterpreter ( resource ) ;
225
+ if ( currentInterpreter ) {
226
+ return [ ] ;
227
+ }
227
228
try {
228
- await executionService . getExecutablePath ( { throwOnError : true } ) ;
229
+ await this . shellExecPython ( ) ;
229
230
} catch ( ex ) {
230
- if ( ( ex as Error ) . message ?. includes ( '4058' ) ) {
231
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
232
+ if ( ( ex as any ) . errno === - 4058 ) {
231
233
// ENOENT (-4058) error is thrown by Node when the default shell is invalid.
232
234
if ( await this . isComspecInvalid ( ) ) {
233
235
traceError ( 'ComSpec is set to an invalid value' , process . env . ComSpec ) ;
@@ -241,7 +243,22 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService
241
243
private async isComspecInvalid ( ) {
242
244
const comSpec = process . env . ComSpec ?? '' ;
243
245
const fs = this . serviceContainer . get < IFileSystem > ( IFileSystem ) ;
244
- return fs . fileExists ( comSpec ) ;
246
+ return fs . fileExists ( comSpec ) . then ( ( exists ) => ! exists ) ;
247
+ }
248
+
249
+ @cache ( - 1 , true )
250
+ // eslint-disable-next-line class-methods-use-this
251
+ private async shellExecPython ( ) {
252
+ const configurationService = this . serviceContainer . get < IConfigurationService > ( IConfigurationService ) ;
253
+ const { pythonPath } = configurationService . getSettings ( ) ;
254
+ const [ args ] = getExecutable ( ) ;
255
+ const argv = [ pythonPath , ...args ] ;
256
+ // Concat these together to make a set of quoted strings
257
+ const quoted = argv . reduce (
258
+ ( p , c ) => ( p ? `${ p } ${ c . toCommandArgumentForPythonExt ( ) } ` : `${ c . toCommandArgumentForPythonExt ( ) } ` ) ,
259
+ '' ,
260
+ ) ;
261
+ return shellExec ( quoted , { timeout : 15000 } ) ;
245
262
}
246
263
}
247
264
0 commit comments