Skip to content

Commit 831df5a

Browse files
authored
Listen for extensions being installed/unistalled to avoid race condition when both this extension and ms-python.python are installed during startup (#1839)
1 parent 88b5ad2 commit 831df5a

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

extension/src/config.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { Disposable } from '@hediet/std/disposable'
12
import { EventEmitter, Event, workspace } from 'vscode'
23
import {
34
getOnDidChangePythonExecutionDetails,
45
getPythonBinPath
56
} from './extensions/python'
67
import { ConfigKey, getConfigValue } from './vscode/config'
78
import { DeferredDisposable } from './class/deferred'
9+
import { getOnDidChangeExtensions } from './vscode/extensions'
810

911
export class Config extends DeferredDisposable {
1012
public readonly onDidChangeExecutionDetails: Event<void>
@@ -15,15 +17,20 @@ export class Config extends DeferredDisposable {
1517

1618
private readonly executionDetailsChanged: EventEmitter<void>
1719

18-
constructor() {
20+
private pythonExecutionDetailsListener?: Disposable
21+
private readonly onDidChangeExtensionsEvent: Event<void>
22+
23+
constructor(onDidChangeExtensionsEvent = getOnDidChangeExtensions()) {
1924
super()
2025

2126
this.executionDetailsChanged = this.dispose.track(new EventEmitter())
2227
this.onDidChangeExecutionDetails = this.executionDetailsChanged.event
28+
this.onDidChangeExtensionsEvent = onDidChangeExtensionsEvent
2329

2430
this.setPythonBinPath()
2531

2632
this.onDidChangePythonExecutionDetails()
33+
this.onDidChangeExtensions()
2734

2835
this.onDidConfigurationChange()
2936
}
@@ -46,15 +53,25 @@ export class Config extends DeferredDisposable {
4653
}
4754

4855
private async onDidChangePythonExecutionDetails() {
56+
this.pythonExecutionDetailsListener?.dispose()
4957
const onDidChangePythonExecutionDetails =
5058
await getOnDidChangePythonExecutionDetails()
51-
this.dispose.track(
59+
this.pythonExecutionDetailsListener = this.dispose.track(
5260
onDidChangePythonExecutionDetails?.(() => {
5361
this.setPythonAndNotifyIfChanged()
5462
})
5563
)
5664
}
5765

66+
private onDidChangeExtensions() {
67+
this.dispose.track(
68+
this.onDidChangeExtensionsEvent(() => {
69+
this.onDidChangePythonExecutionDetails()
70+
this.setPythonAndNotifyIfChanged()
71+
})
72+
)
73+
}
74+
5875
private onDidConfigurationChange() {
5976
this.dispose.track(
6077
workspace.onDidChangeConfiguration(e => {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { join } from 'path'
2+
import { afterEach, beforeEach, describe, it, suite } from 'mocha'
3+
import { expect } from 'chai'
4+
import { stub, restore } from 'sinon'
5+
import { EventEmitter } from 'vscode'
6+
import { Disposable } from '../../extension'
7+
import { Config } from '../../config'
8+
import * as Extensions from '../../vscode/extensions'
9+
import * as Python from '../../extensions/python'
10+
11+
suite('Config Test Suite', () => {
12+
const disposable = Disposable.fn()
13+
14+
beforeEach(() => {
15+
restore()
16+
})
17+
18+
afterEach(() => {
19+
disposable.dispose()
20+
})
21+
22+
describe('Config', () => {
23+
it('should re-fetch the python extension API (and execution details) if any extensions are enabled/disabled or installed/uninstalled', async () => {
24+
const mockGetExtensionAPI = stub(Extensions, 'getExtensionAPI').resolves(
25+
undefined
26+
)
27+
28+
const extensionsChanged = disposable.track(new EventEmitter<void>())
29+
30+
const config = disposable.track(new Config(extensionsChanged.event))
31+
expect(mockGetExtensionAPI).to.be.calledTwice
32+
expect(config.pythonBinPath).to.be.undefined
33+
34+
const pythonBinPath = join('some', 'magic', 'python', 'path')
35+
36+
const executionDetailsUpdated = new Promise(resolve =>
37+
disposable.track(
38+
config.onDidChangeExecutionDetails(() => {
39+
resolve(undefined)
40+
})
41+
)
42+
)
43+
44+
stub(Python, 'getPythonBinPath').resolves(pythonBinPath)
45+
extensionsChanged.fire()
46+
47+
await executionDetailsUpdated
48+
expect(config.pythonBinPath).to.equal(pythonBinPath)
49+
})
50+
})
51+
})

extension/src/vscode/extensions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ export const isInstalled = (id: string): boolean =>
4141

4242
export const showExtension = (id: string) =>
4343
commands.executeCommand('workbench.extensions.search', `@id:${id}`)
44+
45+
export const getOnDidChangeExtensions = () => extensions.onDidChange

0 commit comments

Comments
 (0)