@@ -12,15 +12,16 @@ import { promisify } from "util";
12
12
13
13
export class PowerShellProcess {
14
14
// This is used to warn the user that the extension is taking longer than expected to startup.
15
- // After the 15th try we've hit 30 seconds and should warn.
16
- private static warnUserThreshold = 15 ;
15
+ private static warnUserThreshold = 30 ;
17
16
18
17
public onExited : vscode . Event < void > ;
19
18
private onExitedEmitter = new vscode . EventEmitter < void > ( ) ;
20
19
21
20
private consoleTerminal ?: vscode . Terminal ;
22
21
private consoleCloseSubscription ?: vscode . Disposable ;
23
22
23
+ private pid ?: number ;
24
+
24
25
constructor (
25
26
public exePath : string ,
26
27
private bundledModulesPath : string ,
@@ -33,7 +34,7 @@ export class PowerShellProcess {
33
34
this . onExited = this . onExitedEmitter . event ;
34
35
}
35
36
36
- public async start ( logFileName : string ) : Promise < IEditorServicesSessionDetails > {
37
+ public async start ( logFileName : string , cancellationToken : vscode . CancellationToken ) : Promise < IEditorServicesSessionDetails | undefined > {
37
38
const editorServicesLogPath = this . logger . getLogFilePath ( logFileName ) ;
38
39
39
40
const psesModulePath =
@@ -95,7 +96,7 @@ export class PowerShellProcess {
95
96
this . logger . writeVerbose ( `Starting process: ${ this . exePath } ${ powerShellArgs . slice ( 0 , - 2 ) . join ( " " ) } -Command ${ startEditorServices } ` ) ;
96
97
97
98
// Make sure no old session file exists
98
- await PowerShellProcess . deleteSessionFile ( this . sessionFilePath ) ;
99
+ await this . deleteSessionFile ( this . sessionFilePath ) ;
99
100
100
101
// Launch PowerShell in the integrated terminal
101
102
const terminalOptions : vscode . TerminalOptions = {
@@ -113,23 +114,17 @@ export class PowerShellProcess {
113
114
// subscription should happen before we create the terminal so if it
114
115
// fails immediately, the event fires.
115
116
this . consoleCloseSubscription = vscode . window . onDidCloseTerminal ( ( terminal ) => this . onTerminalClose ( terminal ) ) ;
116
-
117
117
this . consoleTerminal = vscode . window . createTerminal ( terminalOptions ) ;
118
-
119
- const pwshName = path . basename ( this . exePath ) ;
120
- this . logger . write ( `${ pwshName } started.` ) ;
121
-
122
- // Log that the PowerShell terminal process has been started
123
- const pid = await this . getPid ( ) ;
124
- this . logTerminalPid ( pid ?? 0 , pwshName ) ;
118
+ this . pid = await this . getPid ( ) ;
119
+ this . logger . write ( `PowerShell process started with PID: ${ this . pid } ` ) ;
125
120
126
121
if ( this . sessionSettings . integratedConsole . showOnStartup
127
122
&& ! this . sessionSettings . integratedConsole . startInBackground ) {
128
123
// We still need to run this to set the active terminal to the extension terminal.
129
124
this . consoleTerminal . show ( true ) ;
130
125
}
131
126
132
- return await this . waitForSessionFile ( ) ;
127
+ return await this . waitForSessionFile ( cancellationToken ) ;
133
128
}
134
129
135
130
// This function should only be used after a failure has occurred because it is slow!
@@ -141,25 +136,23 @@ export class PowerShellProcess {
141
136
142
137
// Returns the process Id of the consoleTerminal
143
138
public async getPid ( ) : Promise < number | undefined > {
144
- if ( ! this . consoleTerminal ) { return undefined ; }
145
- return await this . consoleTerminal . processId ;
139
+ return await this . consoleTerminal ?. processId ;
146
140
}
147
141
148
142
public showTerminal ( preserveFocus ?: boolean ) : void {
149
143
this . consoleTerminal ?. show ( preserveFocus ) ;
150
144
}
151
145
152
- public async dispose ( ) : Promise < void > {
153
- // Clean up the session file
154
- this . logger . write ( "Disposing PowerShell Extension Terminal..." ) ;
146
+ public dispose ( ) : void {
147
+ this . logger . writeVerbose ( `Disposing PowerShell process with PID: ${ this . pid } ` ) ;
148
+
149
+ void this . deleteSessionFile ( this . sessionFilePath ) ;
155
150
156
151
this . consoleTerminal ?. dispose ( ) ;
157
152
this . consoleTerminal = undefined ;
158
153
159
154
this . consoleCloseSubscription ?. dispose ( ) ;
160
155
this . consoleCloseSubscription = undefined ;
161
-
162
- await PowerShellProcess . deleteSessionFile ( this . sessionFilePath ) ;
163
156
}
164
157
165
158
public sendKeyPress ( ) : void {
@@ -170,10 +163,6 @@ export class PowerShellProcess {
170
163
this . consoleTerminal ?. sendText ( "p" , false ) ;
171
164
}
172
165
173
- private logTerminalPid ( pid : number , exeName : string ) : void {
174
- this . logger . write ( `${ exeName } PID: ${ pid } ` ) ;
175
- }
176
-
177
166
private isLoginShell ( pwshPath : string ) : boolean {
178
167
try {
179
168
// We can't know what version of PowerShell we have without running it
@@ -184,64 +173,63 @@ export class PowerShellProcess {
184
173
} catch {
185
174
return false ;
186
175
}
187
-
188
176
return true ;
189
177
}
190
178
191
- private static async readSessionFile ( sessionFilePath : vscode . Uri ) : Promise < IEditorServicesSessionDetails > {
179
+ private async readSessionFile ( sessionFilePath : vscode . Uri ) : Promise < IEditorServicesSessionDetails > {
192
180
const fileContents = await vscode . workspace . fs . readFile ( sessionFilePath ) ;
193
181
return JSON . parse ( fileContents . toString ( ) ) ;
194
182
}
195
183
196
- private static async deleteSessionFile ( sessionFilePath : vscode . Uri ) : Promise < void > {
184
+ private async deleteSessionFile ( sessionFilePath : vscode . Uri ) : Promise < void > {
197
185
try {
198
186
await vscode . workspace . fs . delete ( sessionFilePath ) ;
199
187
} catch {
200
188
// We don't care about any reasons for it to fail.
201
189
}
202
190
}
203
191
204
- private async waitForSessionFile ( ) : Promise < IEditorServicesSessionDetails > {
205
- // Determine how many tries by dividing by 2000 thus checking every 2 seconds.
206
- const numOfTries = this . sessionSettings . developer . waitForSessionFileTimeoutSeconds / 2 ;
192
+ private async waitForSessionFile ( cancellationToken : vscode . CancellationToken ) : Promise < IEditorServicesSessionDetails | undefined > {
193
+ const numOfTries = this . sessionSettings . developer . waitForSessionFileTimeoutSeconds ;
207
194
const warnAt = numOfTries - PowerShellProcess . warnUserThreshold ;
208
195
209
- // Check every 2 seconds
210
- this . logger . write ( " Waiting for session file..." ) ;
196
+ // Check every second.
197
+ this . logger . writeVerbose ( ` Waiting for session file: ${ this . sessionFilePath } ` ) ;
211
198
for ( let i = numOfTries ; i > 0 ; i -- ) {
199
+ if ( cancellationToken . isCancellationRequested ) {
200
+ this . logger . writeWarning ( "Canceled while waiting for session file." ) ;
201
+ return undefined ;
202
+ }
203
+
212
204
if ( this . consoleTerminal === undefined ) {
213
- const err = "PowerShell Extension Terminal didn't start!" ;
214
- this . logger . write ( err ) ;
215
- throw new Error ( err ) ;
205
+ this . logger . writeError ( "Extension Terminal is undefined." ) ;
206
+ return undefined ;
216
207
}
217
208
218
209
if ( await utils . checkIfFileExists ( this . sessionFilePath ) ) {
219
- this . logger . write ( "Session file found!" ) ;
220
- const sessionDetails = await PowerShellProcess . readSessionFile ( this . sessionFilePath ) ;
221
- await PowerShellProcess . deleteSessionFile ( this . sessionFilePath ) ;
222
- return sessionDetails ;
210
+ this . logger . writeVerbose ( "Session file found." ) ;
211
+ return await this . readSessionFile ( this . sessionFilePath ) ;
223
212
}
224
213
225
214
if ( warnAt === i ) {
226
215
void this . logger . writeAndShowWarning ( "Loading the PowerShell extension is taking longer than expected. If you're using privilege enforcement software, this can affect start up performance." ) ;
227
216
}
228
217
229
- // Wait a bit and try again
230
- await utils . sleep ( 2000 ) ;
218
+ // Wait a bit and try again.
219
+ await utils . sleep ( 1000 ) ;
231
220
}
232
221
233
- const err = "Timed out waiting for session file to appear!" ;
234
- this . logger . write ( err ) ;
235
- throw new Error ( err ) ;
222
+ this . logger . writeError ( "Timed out waiting for session file!" ) ;
223
+ return undefined ;
236
224
}
237
225
238
226
private onTerminalClose ( terminal : vscode . Terminal ) : void {
239
227
if ( terminal !== this . consoleTerminal ) {
240
228
return ;
241
229
}
242
230
243
- this . logger . write ( " PowerShell process terminated or Extension Terminal was closed!" ) ;
231
+ this . logger . writeWarning ( ` PowerShell process terminated or Extension Terminal was closed, PID: ${ this . pid } ` ) ;
244
232
this . onExitedEmitter . fire ( ) ;
245
- void this . dispose ( ) ;
233
+ this . dispose ( ) ;
246
234
}
247
235
}
0 commit comments