Skip to content

Commit 590cf28

Browse files
authored
chore: refactor common shell execution code (#181)
1 parent 6c21fe9 commit 590cf28

File tree

1 file changed

+50
-73
lines changed

1 file changed

+50
-73
lines changed

src/features/terminal/terminalActivationState.ts

Lines changed: 50 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ import {
77
TerminalShellExecutionStartEvent,
88
TerminalShellIntegration,
99
} from 'vscode';
10-
import { PythonEnvironment } from '../../api';
10+
import { PythonCommandRunConfiguration, PythonEnvironment } from '../../api';
1111
import { onDidEndTerminalShellExecution, onDidStartTerminalShellExecution } from '../../common/window.apis';
1212
import { traceError, traceInfo, traceVerbose } from '../../common/logging';
1313
import { isTaskTerminal } from './utils';
14-
import { createDeferred } from '../../common/utils/deferred';
1514
import { getActivationCommand, getDeactivationCommand } from '../common/activation';
1615
import { quoteArgs } from '../execution/execUtils';
1716

@@ -229,46 +228,14 @@ export class TerminalActivationImpl implements TerminalActivationInternal {
229228
if (activationCommands) {
230229
try {
231230
for (const command of activationCommands) {
232-
const execPromise = createDeferred<void>();
233-
const execution = shellIntegration.executeCommand(command.executable, command.args ?? []);
234-
const disposables: Disposable[] = [];
235-
let timer: NodeJS.Timeout | undefined = setTimeout(() => {
236-
execPromise.resolve();
237-
traceError(`Shell execution timed out: ${command.executable} ${command.args?.join(' ')}`);
238-
}, 2000);
239-
disposables.push(
240-
this.onTerminalShellExecutionEnd((e: TerminalShellExecutionEndEvent) => {
241-
if (e.execution === execution) {
242-
execPromise.resolve();
243-
if (timer) {
244-
clearTimeout(timer);
245-
timer = undefined;
246-
}
247-
}
248-
}),
249-
this.onTerminalShellExecutionStart((e: TerminalShellExecutionStartEvent) => {
250-
if (e.execution === execution) {
251-
traceVerbose(
252-
`Shell execution started: ${command.executable} ${command.args?.join(' ')}`,
253-
);
254-
}
255-
}),
256-
new Disposable(() => {
257-
if (timer) {
258-
clearTimeout(timer);
259-
timer = undefined;
260-
}
261-
}),
262-
);
263-
try {
264-
await execPromise.promise;
265-
} finally {
266-
disposables.forEach((d) => d.dispose());
267-
}
231+
await this.executeTerminalShellCommandInternal(shellIntegration, command);
268232
}
269-
} finally {
270233
this.activatedTerminals.set(terminal, environment);
234+
} catch {
235+
traceError('Failed to activate environment using shell integration');
271236
}
237+
} else {
238+
traceVerbose('No activation commands found for terminal.');
272239
}
273240
}
274241

@@ -281,43 +248,53 @@ export class TerminalActivationImpl implements TerminalActivationInternal {
281248
if (deactivationCommands) {
282249
try {
283250
for (const command of deactivationCommands) {
284-
const execPromise = createDeferred<void>();
285-
const execution = shellIntegration.executeCommand(command.executable, command.args ?? []);
286-
const disposables: Disposable[] = [];
287-
let timer: NodeJS.Timeout | undefined = setTimeout(() => {
288-
execPromise.resolve();
289-
traceError(`Shell execution timed out: ${command.executable} ${command.args?.join(' ')}`);
290-
}, 2000);
291-
disposables.push(
292-
this.onTerminalShellExecutionEnd((e: TerminalShellExecutionEndEvent) => {
293-
if (e.execution === execution) {
294-
execPromise.resolve();
295-
if (timer) {
296-
clearTimeout(timer);
297-
timer = undefined;
298-
}
299-
}
300-
}),
301-
this.onTerminalShellExecutionStart((e: TerminalShellExecutionStartEvent) => {
302-
if (e.execution === execution) {
303-
traceVerbose(
304-
`Shell execution started: ${command.executable} ${command.args?.join(' ')}`,
305-
);
306-
}
307-
}),
308-
new Disposable(() => {
309-
if (timer) {
310-
clearTimeout(timer);
311-
timer = undefined;
312-
}
313-
}),
314-
);
315-
316-
await execPromise.promise;
251+
await this.executeTerminalShellCommandInternal(shellIntegration, command);
317252
}
318-
} finally {
319253
this.activatedTerminals.delete(terminal);
254+
} catch {
255+
traceError('Failed to deactivate environment using shell integration');
320256
}
257+
} else {
258+
traceVerbose('No deactivation commands found for terminal.');
259+
}
260+
}
261+
262+
private async executeTerminalShellCommandInternal(
263+
shellIntegration: TerminalShellIntegration,
264+
command: PythonCommandRunConfiguration,
265+
): Promise<boolean> {
266+
const execution = shellIntegration.executeCommand(command.executable, command.args ?? []);
267+
const disposables: Disposable[] = [];
268+
269+
const promise = new Promise<void>((resolve) => {
270+
const timer = setTimeout(() => {
271+
traceError(`Shell execution timed out: ${command.executable} ${command.args?.join(' ')}`);
272+
resolve();
273+
}, 2000);
274+
275+
disposables.push(
276+
new Disposable(() => clearTimeout(timer)),
277+
this.onTerminalShellExecutionEnd((e: TerminalShellExecutionEndEvent) => {
278+
if (e.execution === execution) {
279+
resolve();
280+
}
281+
}),
282+
this.onTerminalShellExecutionStart((e: TerminalShellExecutionStartEvent) => {
283+
if (e.execution === execution) {
284+
traceVerbose(`Shell execution started: ${command.executable} ${command.args?.join(' ')}`);
285+
}
286+
}),
287+
);
288+
});
289+
290+
try {
291+
await promise;
292+
return true;
293+
} catch {
294+
traceError(`Failed to execute shell command: ${command.executable} ${command.args?.join(' ')}`);
295+
return false;
296+
} finally {
297+
disposables.forEach((d) => d.dispose());
321298
}
322299
}
323300
}

0 commit comments

Comments
 (0)