1- import { Disposable , EventEmitter , Uri , workspace } from "vscode" ;
1+ import {
2+ Disposable ,
3+ EventEmitter ,
4+ RelativePattern ,
5+ Uri ,
6+ workspace ,
7+ } from "vscode" ;
28import { BundleFileSet , getAbsoluteGlobPath } from "./BundleFileSet" ;
39import path from "path" ;
410import { WorkspaceFolderManager } from "../vscode-objs/WorkspaceFolderManager" ;
11+ import { Mutex } from "../locking" ;
512
613export class BundleWatcher implements Disposable {
714 private disposables : Disposable [ ] = [ ] ;
@@ -19,15 +26,24 @@ export class BundleWatcher implements Disposable {
1926 public readonly onDidDelete = this . _onDidDelete . event ;
2027
2128 private initCleanup : Disposable ;
29+ // Watchers for include files that resolve outside the active project root.
30+ // Tracked separately so they can be rebuilt when the include list changes
31+ // without tearing down the main in-tree watcher.
32+ private externalWatchersCleanup : Disposable | undefined ;
33+ // Serializes refreshExternalWatchers() so overlapping invocations (e.g. a
34+ // burst of root-file changes) don't leak watchers or create duplicates.
35+ private readonly externalWatchersMutex = new Mutex ( ) ;
2236 constructor (
2337 private readonly bundleFileSet : BundleFileSet ,
2438 private readonly workspaceFolderManager : WorkspaceFolderManager
2539 ) {
2640 this . initCleanup = this . init ( ) ;
41+ void this . refreshExternalWatchers ( ) ;
2742 this . disposables . push (
2843 this . workspaceFolderManager . onDidChangeActiveProjectFolder ( ( ) => {
2944 this . initCleanup . dispose ( ) ;
3045 this . initCleanup = this . init ( ) ;
46+ void this . refreshExternalWatchers ( ) ;
3147 this . bundleFileSet . bundleDataCache . invalidate ( ) ;
3248 } )
3349 ) ;
@@ -61,6 +77,51 @@ export class BundleWatcher implements Disposable {
6177 } ;
6278 }
6379
80+ /**
81+ * (Re)create watchers for include files that live outside the active
82+ * project root. The default recursive watcher created in init() only
83+ * observes files under the project root, so parent-folder includes
84+ * (e.g. "../../shared/databricks-shared.yml") need dedicated watchers
85+ * to keep the bundle cache and downstream models in sync.
86+ */
87+ private async refreshExternalWatchers ( ) {
88+ return this . externalWatchersMutex . synchronise ( async ( ) => {
89+ this . externalWatchersCleanup ?. dispose ( ) ;
90+ this . externalWatchersCleanup = undefined ;
91+
92+ const targets =
93+ await this . bundleFileSet . getExternalIncludeWatchTargets ( ) ;
94+ if ( targets . length === 0 ) {
95+ return ;
96+ }
97+
98+ const disposables : Disposable [ ] = [ ] ;
99+ for ( const { baseUri, pattern} of targets ) {
100+ const watcher = workspace . createFileSystemWatcher (
101+ new RelativePattern ( baseUri , pattern )
102+ ) ;
103+ disposables . push (
104+ watcher ,
105+ watcher . onDidCreate ( ( e ) => {
106+ this . yamlFileChangeHandler ( e , "CREATE" ) ;
107+ } ) ,
108+ watcher . onDidChange ( ( e ) => {
109+ this . yamlFileChangeHandler ( e , "CHANGE" ) ;
110+ } ) ,
111+ watcher . onDidDelete ( ( e ) => {
112+ this . yamlFileChangeHandler ( e , "DELETE" ) ;
113+ } )
114+ ) ;
115+ }
116+
117+ this . externalWatchersCleanup = {
118+ dispose : ( ) => {
119+ disposables . forEach ( ( i ) => i . dispose ( ) ) ;
120+ } ,
121+ } ;
122+ } ) ;
123+ }
124+
64125 private async yamlFileChangeHandler (
65126 e : Uri ,
66127 type : "CREATE" | "CHANGE" | "DELETE"
@@ -74,6 +135,9 @@ export class BundleWatcher implements Disposable {
74135 // to provide additional granularity, we also fire an event when the root bundle file changes
75136 if ( this . bundleFileSet . isRootBundleFile ( e ) ) {
76137 this . _onDidChangeRootFile . fire ( ) ;
138+ // The include list lives in the root file, so its set of external
139+ // include locations may have changed. Rebuild those watchers.
140+ void this . refreshExternalWatchers ( ) ;
77141 }
78142 switch ( type ) {
79143 case "CREATE" :
@@ -88,5 +152,6 @@ export class BundleWatcher implements Disposable {
88152 dispose ( ) {
89153 this . disposables . forEach ( ( i ) => i . dispose ( ) ) ;
90154 this . initCleanup . dispose ( ) ;
155+ this . externalWatchersCleanup ?. dispose ( ) ;
91156 }
92157}
0 commit comments