11import { Disposable , EventEmitter , Uri , Event } from "vscode" ;
22import {
3- BundleConfigs ,
4- DatabricksConfigs ,
5- isBundleConfig ,
6- isOverrideableConfig ,
3+ BundleConfig ,
4+ DATABRICKS_CONFIG_KEYS ,
5+ DatabricksConfigSource ,
6+ DatabricksConfig ,
7+ isBundleConfigKey ,
8+ isOverrideableConfigKey ,
79} from "./types" ;
810import { ConfigOverrideReaderWriter } from "./ConfigOverrideReaderWriter" ;
911import { BundleConfigReaderWriter } from "./BundleConfigReaderWriter" ;
@@ -13,61 +15,82 @@ import {CachedValue} from "../locking/CachedValue";
1315import { StateStorage } from "../vscode-objs/StateStorage" ;
1416
1517function isDirectToBundleConfig (
16- key : keyof BundleConfigs ,
17- mode ?: BundleConfigs [ "mode" ]
18+ key : keyof BundleConfig ,
19+ mode ?: BundleConfig [ "mode" ]
1820) {
19- const directToBundleConfigs : ( keyof BundleConfigs ) [ ] = [ ] ;
21+ const directToBundleConfigs : ( keyof BundleConfig ) [ ] = [ ] ;
2022 if ( mode !== undefined ) {
2123 // filter by mode
2224 }
2325 return directToBundleConfigs . includes ( key ) ;
2426}
2527
26- const defaults : DatabricksConfigs = {
28+ const defaults : DatabricksConfig = {
2729 mode : "dev" ,
2830} ;
31+
2932/**
3033 * In memory view of the databricks configs loaded from overrides and bundle.
3134 */
3235export class ConfigModel implements Disposable {
3336 private disposables : Disposable [ ] = [ ] ;
3437
3538 private readonly configsMutex = new Mutex ( ) ;
36- private readonly configCache = new CachedValue < DatabricksConfigs > (
37- async ( oldValue ) => {
38- if ( this . target === undefined ) {
39- return { } ;
40- }
41- const overrides = await this . overrideReaderWriter . readAll (
42- this . target
43- ) ;
44- const bundleConfigs = await this . bundleConfigReaderWriter . readAll (
45- this . target
46- ) ;
47- const newValue : DatabricksConfigs = {
48- ...bundleConfigs ,
49- ...overrides ,
50- } ;
51-
52- for ( const key of < ( keyof DatabricksConfigs ) [ ] > (
53- Object . keys ( newValue )
54- ) ) {
55- if (
56- oldValue === null ||
57- JSON . stringify ( oldValue [ key ] ) !==
58- JSON . stringify ( newValue [ key ] )
59- ) {
60- this . changeEmitters . get ( key ) ?. emitter . fire ( ) ;
61- this . onDidChangeAnyEmitter . fire ( ) ;
62- }
39+ private readonly configCache = new CachedValue < {
40+ config : DatabricksConfig ;
41+ source : DatabricksConfigSource ;
42+ } > ( async ( oldValue ) => {
43+ if ( this . target === undefined ) {
44+ return { config : { } , source : { } } ;
45+ }
46+ const overrides = await this . overrideReaderWriter . readAll ( this . target ) ;
47+ const bundleConfigs = await this . bundleConfigReaderWriter . readAll (
48+ this . target
49+ ) ;
50+ const newValue : DatabricksConfig = {
51+ ...bundleConfigs ,
52+ ...overrides ,
53+ } ;
54+
55+ const source : DatabricksConfigSource = { } ;
56+
57+ /* By default undefined values are considered to have come from bundle.
58+ This is because when override for a key is undefined, it means that the key
59+ is not overridden and we want to get the value from bundle.
60+ */
61+ DATABRICKS_CONFIG_KEYS . forEach ( ( key ) => {
62+ source [ key ] =
63+ overrides !== undefined && key in overrides
64+ ? "override"
65+ : "bundle" ;
66+ } ) ;
67+
68+ let didAnyConfigChange = false ;
69+ for ( const key of DATABRICKS_CONFIG_KEYS ) {
70+ if (
71+ // Old value is null, but new value has the key
72+ ( oldValue === null && newValue [ key ] !== undefined ) ||
73+ // Old value is not null, and old and new values for the key are different
74+ ( oldValue !== null &&
75+ JSON . stringify ( oldValue . config [ key ] ) !==
76+ JSON . stringify ( newValue [ key ] ) )
77+ ) {
78+ this . changeEmitters . get ( key ) ?. emitter . fire ( ) ;
79+ didAnyConfigChange = true ;
6380 }
81+ }
6482
65- return newValue ;
83+ if ( didAnyConfigChange ) {
84+ this . onDidChangeAnyEmitter . fire ( ) ;
6685 }
67- ) ;
86+ return {
87+ config : newValue ,
88+ source : source ,
89+ } ;
90+ } ) ;
6891
6992 private readonly changeEmitters = new Map <
70- keyof DatabricksConfigs | "target" ,
93+ keyof DatabricksConfig | "target" ,
7194 {
7295 emitter : EventEmitter < void > ;
7396 onDidEmit : Event < void > ;
@@ -102,7 +125,7 @@ export class ConfigModel implements Disposable {
102125 await this . readTarget ( ) ;
103126 }
104127
105- public onDidChange < T extends keyof DatabricksConfigs | "target" > (
128+ public onDidChange < T extends keyof DatabricksConfig | "target" > (
106129 key : T ,
107130 fn : ( ) => any ,
108131 thisArgs ?: any
@@ -164,33 +187,59 @@ export class ConfigModel implements Disposable {
164187 this . onDidChangeAnyEmitter . fire ( ) ;
165188 }
166189
167- public async get < T extends keyof DatabricksConfigs > (
190+ public async get < T extends keyof DatabricksConfig > (
191+ key : T
192+ ) : Promise < DatabricksConfig [ T ] | undefined > {
193+ return ( await this . configCache . value ) . config [ key ] ?? defaults [ key ] ;
194+ }
195+
196+ /**
197+ * Return config value along with source of the config.
198+ * Refer to {@link DatabricksConfigSource} for possible values.
199+ */
200+ public async getS < T extends keyof DatabricksConfig > (
168201 key : T
169- ) : Promise < DatabricksConfigs [ T ] | undefined > {
170- return ( await this . configCache . value ) [ key ] ?? defaults [ key ] ;
202+ ) : Promise <
203+ | {
204+ config : DatabricksConfig [ T ] ;
205+ source : DatabricksConfigSource [ T ] | "default" ;
206+ }
207+ | undefined
208+ > {
209+ const { config : fullConfig , source : fullSource } = await this . configCache
210+ . value ;
211+ const config = fullConfig [ key ] ?? defaults [ key ] ;
212+ const source =
213+ fullConfig [ key ] !== undefined ? fullSource [ key ] : "default" ;
214+ return config
215+ ? {
216+ config,
217+ source,
218+ }
219+ : undefined ;
171220 }
172221
173222 @Mutex . synchronise ( "configsMutex" )
174- public async set < T extends keyof DatabricksConfigs > (
223+ public async set < T extends keyof DatabricksConfig > (
175224 key : T ,
176- value ?: DatabricksConfigs [ T ] ,
225+ value ?: DatabricksConfig [ T ] ,
177226 handleInteractiveWrite ?: ( file : Uri | undefined ) => any
178227 ) : Promise < void > {
179228 // We work with 1 set of configs throughout the function.
180229 // No changes to the cache can happen when the global mutex is held.
181230 // The assumption is that user doesn't change the target mode in the middle of
182231 // writing a new config.
183- const { mode} = { ...( await this . configCache . value ) } ;
232+ const { mode} = { ...( await this . configCache . value ) . config } ;
184233
185234 if ( this . target === undefined ) {
186235 throw new Error (
187236 `Can't set configuration '${ key } ' without selecting a target`
188237 ) ;
189238 }
190- if ( isOverrideableConfig ( key ) ) {
239+ if ( isOverrideableConfigKey ( key ) ) {
191240 return this . overrideReaderWriter . write ( key , this . target , value ) ;
192241 }
193- if ( isBundleConfig ( key ) ) {
242+ if ( isBundleConfigKey ( key ) ) {
194243 const isInteractive = handleInteractiveWrite !== undefined ;
195244
196245 // write to bundle if not interactive and the config can be safely written to bundle
0 commit comments