@@ -9,6 +9,7 @@ import { ConfigurationChangeEvent, ConfigurationTarget, Event, EventEmitter, Uri
9
9
import { IWorkspaceService } from './application/types' ;
10
10
import { PythonSettings } from './configSettings' ;
11
11
import { isTestExecution } from './constants' ;
12
+ import { FileSystemPaths } from './platform/fs-paths' ;
12
13
import {
13
14
IDisposable ,
14
15
IDisposableRegistry ,
@@ -21,6 +22,9 @@ import {
21
22
Resource
22
23
} from './types' ;
23
24
25
+ export const workspaceKeysForWhichTheCopyIsDone_Key = 'workspaceKeysForWhichTheCopyIsDone_Key' ;
26
+ export const workspaceFolderKeysForWhichTheCopyIsDone_Key = 'workspaceFolderKeysForWhichTheCopyIsDone_Key' ;
27
+ export const isGlobalSettingCopiedKey = 'isGlobalSettingCopiedKey' ;
24
28
export const defaultInterpreterPathSetting : keyof IPythonSettings = 'defaultInterpreterPath' ;
25
29
const CI_PYTHON_PATH = getCIPythonPath ( ) ;
26
30
@@ -32,13 +36,18 @@ export function getCIPythonPath(): string {
32
36
}
33
37
@injectable ( )
34
38
export class InterpreterPathService implements IInterpreterPathService {
39
+ public get onDidChange ( ) : Event < InterpreterConfigurationScope > {
40
+ return this . _didChangeInterpreterEmitter . event ;
41
+ }
35
42
public _didChangeInterpreterEmitter = new EventEmitter < InterpreterConfigurationScope > ( ) ;
43
+ private fileSystemPaths : FileSystemPaths ;
36
44
constructor (
37
45
@inject ( IPersistentStateFactory ) private readonly persistentStateFactory : IPersistentStateFactory ,
38
46
@inject ( IWorkspaceService ) private readonly workspaceService : IWorkspaceService ,
39
47
@inject ( IDisposableRegistry ) disposables : IDisposable [ ]
40
48
) {
41
49
disposables . push ( this . workspaceService . onDidChangeConfiguration ( this . onDidChangeConfiguration . bind ( this ) ) ) ;
50
+ this . fileSystemPaths = FileSystemPaths . withDefaults ( ) ;
42
51
}
43
52
44
53
public async onDidChangeConfiguration ( event : ConfigurationChangeEvent ) {
@@ -88,8 +97,11 @@ export class InterpreterPathService implements IInterpreterPathService {
88
97
resource = PythonSettings . getSettingsUriAndTarget ( resource , this . workspaceService ) . uri ;
89
98
if ( configTarget === ConfigurationTarget . Global ) {
90
99
const pythonConfig = this . workspaceService . getConfiguration ( 'python' ) ;
91
- await pythonConfig . update ( 'defaultInterpreterPath' , pythonPath , true ) ;
92
- this . _didChangeInterpreterEmitter . fire ( { uri : undefined , configTarget } ) ;
100
+ const globalValue = pythonConfig . inspect < string > ( 'defaultInterpreterPath' ) ! . globalValue ;
101
+ if ( globalValue !== pythonPath ) {
102
+ await pythonConfig . update ( 'defaultInterpreterPath' , pythonPath , true ) ;
103
+ this . _didChangeInterpreterEmitter . fire ( { uri : undefined , configTarget } ) ;
104
+ }
93
105
return ;
94
106
}
95
107
if ( ! resource ) {
@@ -100,12 +112,10 @@ export class InterpreterPathService implements IInterpreterPathService {
100
112
settingKey ,
101
113
undefined
102
114
) ;
103
- await persistentSetting . updateValue ( pythonPath ) ;
104
- this . _didChangeInterpreterEmitter . fire ( { uri : resource , configTarget } ) ;
105
- }
106
-
107
- public get onDidChange ( ) : Event < InterpreterConfigurationScope > {
108
- return this . _didChangeInterpreterEmitter . event ;
115
+ if ( persistentSetting . value !== pythonPath ) {
116
+ await persistentSetting . updateValue ( pythonPath ) ;
117
+ this . _didChangeInterpreterEmitter . fire ( { uri : resource , configTarget } ) ;
118
+ }
109
119
}
110
120
111
121
public getSettingKey (
@@ -118,10 +128,74 @@ export class InterpreterPathService implements IInterpreterPathService {
118
128
settingKey = `WORKSPACE_FOLDER_INTERPRETER_PATH_${ folderKey } ` ;
119
129
} else {
120
130
settingKey = this . workspaceService . workspaceFile
121
- ? `WORKSPACE_INTERPRETER_PATH_${ this . workspaceService . workspaceFile . fsPath } `
131
+ ? `WORKSPACE_INTERPRETER_PATH_${ this . fileSystemPaths . normCase (
132
+ this . workspaceService . workspaceFile . fsPath
133
+ ) } `
122
134
: // Only a single folder is opened, use fsPath of the folder as key
123
135
`WORKSPACE_FOLDER_INTERPRETER_PATH_${ folderKey } ` ;
124
136
}
125
137
return settingKey ;
126
138
}
139
+
140
+ public async copyOldInterpreterStorageValuesToNew ( resource : Resource ) : Promise < void > {
141
+ resource = PythonSettings . getSettingsUriAndTarget ( resource , this . workspaceService ) . uri ;
142
+ const oldSettings = this . workspaceService . getConfiguration ( 'python' , resource ) . inspect < string > ( 'pythonPath' ) ! ;
143
+ await Promise . all ( [
144
+ this . _copyWorkspaceFolderValueToNewStorage ( resource , oldSettings . workspaceFolderValue ) ,
145
+ this . _copyWorkspaceValueToNewStorage ( resource , oldSettings . workspaceValue ) ,
146
+ this . _moveGlobalSettingValueToNewStorage ( oldSettings . globalValue )
147
+ ] ) ;
148
+ }
149
+
150
+ public async _copyWorkspaceFolderValueToNewStorage ( resource : Resource , value : string | undefined ) : Promise < void > {
151
+ // Copy workspace folder setting into the new storage if it hasn't been copied already
152
+ const workspaceFolderKey = this . workspaceService . getWorkspaceFolderIdentifier ( resource ) ;
153
+ const flaggedWorkspaceFolderKeysStorage = this . persistentStateFactory . createGlobalPersistentState < string [ ] > (
154
+ workspaceFolderKeysForWhichTheCopyIsDone_Key ,
155
+ [ ]
156
+ ) ;
157
+ const flaggedWorkspaceFolderKeys = flaggedWorkspaceFolderKeysStorage . value ;
158
+ const shouldUpdateWorkspaceFolderSetting = ! flaggedWorkspaceFolderKeys . includes ( workspaceFolderKey ) ;
159
+ if ( shouldUpdateWorkspaceFolderSetting ) {
160
+ await this . update ( resource , ConfigurationTarget . WorkspaceFolder , value ) ;
161
+ await flaggedWorkspaceFolderKeysStorage . updateValue ( [ workspaceFolderKey , ...flaggedWorkspaceFolderKeys ] ) ;
162
+ }
163
+ }
164
+
165
+ public async _copyWorkspaceValueToNewStorage ( resource : Resource , value : string | undefined ) : Promise < void > {
166
+ // Copy workspace setting into the new storage if it hasn't been copied already
167
+ const workspaceKey = this . workspaceService . workspaceFile
168
+ ? this . fileSystemPaths . normCase ( this . workspaceService . workspaceFile . fsPath )
169
+ : undefined ;
170
+ if ( ! workspaceKey ) {
171
+ return ;
172
+ }
173
+ const flaggedWorkspaceKeysStorage = this . persistentStateFactory . createGlobalPersistentState < string [ ] > (
174
+ workspaceKeysForWhichTheCopyIsDone_Key ,
175
+ [ ]
176
+ ) ;
177
+ const flaggedWorkspaceKeys = flaggedWorkspaceKeysStorage . value ;
178
+ const shouldUpdateWorkspaceSetting = ! flaggedWorkspaceKeys . includes ( workspaceKey ) ;
179
+ if ( shouldUpdateWorkspaceSetting ) {
180
+ await this . update ( resource , ConfigurationTarget . Workspace , value ) ;
181
+ await flaggedWorkspaceKeysStorage . updateValue ( [ workspaceKey , ...flaggedWorkspaceKeys ] ) ;
182
+ }
183
+ }
184
+
185
+ public async _moveGlobalSettingValueToNewStorage ( value : string | undefined ) {
186
+ // Move global setting into the new storage if it hasn't been moved already
187
+ const isGlobalSettingCopiedStorage = this . persistentStateFactory . createGlobalPersistentState < boolean > (
188
+ isGlobalSettingCopiedKey ,
189
+ false
190
+ ) ;
191
+ const shouldUpdateGlobalSetting = ! isGlobalSettingCopiedStorage . value ;
192
+ if ( shouldUpdateGlobalSetting ) {
193
+ await this . update ( undefined , ConfigurationTarget . Global , value ) ;
194
+ // Make sure to delete the original setting after copying it
195
+ await this . workspaceService
196
+ . getConfiguration ( 'python' )
197
+ . update ( 'pythonPath' , undefined , ConfigurationTarget . Global ) ;
198
+ await isGlobalSettingCopiedStorage . updateValue ( true ) ;
199
+ }
200
+ }
127
201
}
0 commit comments