Skip to content

Commit 9553739

Browse files
authored
Exclude sub-project files from file and editor watchers (#4283)
* exclude sub project files from file and editor watchers * refactor * test and expand
1 parent 0098dbc commit 9553739

File tree

33 files changed

+435
-90
lines changed

33 files changed

+435
-90
lines changed

extension/src/data/index.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { InternalCommands } from '../commands/internal'
77
import { ExpShowOutput, PlotsOutputOrError } from '../cli/dvc/contract'
88
import { uniqueValues } from '../util/array'
99
import { DeferredDisposable } from '../class/deferred'
10-
import { isSameOrChild } from '../fileSystem'
10+
import { isPathInSubProject, isSameOrChild } from '../fileSystem'
1111

1212
export type ExperimentsOutput = {
1313
availableNbCommits: { [branch: string]: number }
@@ -29,6 +29,7 @@ export abstract class BaseData<
2929
protected readonly internalCommands: InternalCommands
3030
protected collectedFiles: string[] = []
3131

32+
private readonly relSubProjects: string[]
3233
private readonly staticFiles: string[]
3334

3435
private readonly updated: EventEmitter<T> = this.dispose.track(
@@ -39,6 +40,7 @@ export abstract class BaseData<
3940
dvcRoot: string,
4041
internalCommands: InternalCommands,
4142
updateProcesses: { name: string; process: () => Promise<unknown> }[],
43+
subProjects: string[],
4244
staticFiles: string[] = []
4345
) {
4446
super()
@@ -49,6 +51,9 @@ export abstract class BaseData<
4951
)
5052
this.internalCommands = internalCommands
5153
this.onDidUpdate = this.updated.event
54+
this.relSubProjects = subProjects.map(subProject =>
55+
relative(this.dvcRoot, subProject)
56+
)
5257
this.staticFiles = staticFiles
5358

5459
this.watchFiles()
@@ -78,20 +83,23 @@ export abstract class BaseData<
7883
return createFileSystemWatcher(
7984
disposable => this.dispose.track(disposable),
8085
getRelativePattern(this.dvcRoot, '**'),
81-
path => {
82-
const relPath = relative(this.dvcRoot, path)
83-
if (
84-
this.getWatchedFiles().some(
85-
watchedRelPath =>
86-
path.endsWith(watchedRelPath) ||
87-
isSameOrChild(relPath, watchedRelPath)
88-
)
89-
) {
90-
void this.managedUpdate(path)
91-
}
92-
}
86+
path => this.listener(path)
9387
)
9488
}
9589

90+
private listener(path: string) {
91+
const relPath = relative(this.dvcRoot, path)
92+
if (
93+
this.getWatchedFiles().some(
94+
watchedRelPath =>
95+
path.endsWith(watchedRelPath) ||
96+
isSameOrChild(relPath, watchedRelPath)
97+
) &&
98+
!isPathInSubProject(relPath, this.relSubProjects)
99+
) {
100+
void this.managedUpdate(path)
101+
}
102+
}
103+
96104
abstract managedUpdate(path?: string): Promise<void>
97105
}

extension/src/experiments/context.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { Event, EventEmitter, window } from 'vscode'
22
import { Disposable, Disposer } from '@hediet/std/disposable'
33
import { ContextKey, setContextValue } from '../vscode/context'
44
import { standardizePossiblePath } from '../fileSystem/path'
5+
import { isPathInProject, isPathInSubProject } from '../fileSystem'
56

67
const setContextOnDidChangeParamsFiles = (
78
setActiveEditorContext: (paramsFileActive: boolean) => void,
89
onDidChangeColumns: Event<void>,
9-
getParamsFiles: () => Set<string>
10+
getParamsFiles: () => Set<string>,
11+
subProjects: string[]
1012
): Disposable =>
1113
onDidChangeColumns(() => {
1214
const path = standardizePossiblePath(
@@ -16,7 +18,10 @@ const setContextOnDidChangeParamsFiles = (
1618
return
1719
}
1820

19-
if (!getParamsFiles().has(path) && !path.endsWith('dvc.yaml')) {
21+
if (
22+
(!getParamsFiles().has(path) && !path.endsWith('dvc.yaml')) ||
23+
isPathInSubProject(path, subProjects)
24+
) {
2025
return
2126
}
2227
setActiveEditorContext(true)
@@ -25,7 +30,8 @@ const setContextOnDidChangeParamsFiles = (
2530
const setContextOnDidChangeActiveEditor = (
2631
setActiveEditorContext: (paramsFileActive: boolean) => void,
2732
dvcRoot: string,
28-
getParamsFiles: () => Set<string>
33+
getParamsFiles: () => Set<string>,
34+
subProjects: string[]
2935
): Disposable =>
3036
window.onDidChangeActiveTextEditor(event => {
3137
const path = standardizePossiblePath(event?.document.fileName)
@@ -34,7 +40,7 @@ const setContextOnDidChangeActiveEditor = (
3440
return
3541
}
3642

37-
if (!path.includes(dvcRoot)) {
43+
if (!isPathInProject(path, dvcRoot, subProjects)) {
3844
return
3945
}
4046

@@ -49,7 +55,8 @@ export const setContextForEditorTitleIcons = (
4955
disposer: (() => void) & Disposer,
5056
getParamsFiles: () => Set<string>,
5157
experimentsFileFocused: EventEmitter<string | undefined>,
52-
onDidChangeColumns: Event<void>
58+
onDidChangeColumns: Event<void>,
59+
subProjects: string[]
5360
): void => {
5461
const setActiveEditorContext = (experimentsFileActive: boolean) => {
5562
void setContextValue(
@@ -64,15 +71,17 @@ export const setContextForEditorTitleIcons = (
6471
setContextOnDidChangeParamsFiles(
6572
setActiveEditorContext,
6673
onDidChangeColumns,
67-
getParamsFiles
74+
getParamsFiles,
75+
subProjects
6876
)
6977
)
7078

7179
disposer.track(
7280
setContextOnDidChangeActiveEditor(
7381
setActiveEditorContext,
7482
dvcRoot,
75-
getParamsFiles
83+
getParamsFiles,
84+
subProjects
7685
)
7786
)
7887
}

extension/src/experiments/data/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ export class ExperimentsData extends BaseData<ExperimentsOutput> {
2020
constructor(
2121
dvcRoot: string,
2222
internalCommands: InternalCommands,
23-
experiments: ExperimentsModel
23+
experiments: ExperimentsModel,
24+
subProjects: string[]
2425
) {
2526
super(
2627
dvcRoot,
2728
internalCommands,
2829
[{ name: 'update', process: () => this.update() }],
30+
subProjects,
2931
['dvc.lock', 'dvc.yaml', 'params.yaml', DOT_DVC]
3032
)
3133

extension/src/experiments/index.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export class Experiments extends BaseRepository<TableData> {
111111
selectBranches: (
112112
branchesSelected: string[]
113113
) => Promise<string[] | undefined>,
114+
subProjects: string[],
114115
data?: ExperimentsData
115116
) {
116117
super(dvcRoot, resourceLocator.beaker)
@@ -143,7 +144,13 @@ export class Experiments extends BaseRepository<TableData> {
143144
)
144145

145146
this.data = this.dispose.track(
146-
data || new ExperimentsData(dvcRoot, internalCommands, this.experiments)
147+
data ||
148+
new ExperimentsData(
149+
dvcRoot,
150+
internalCommands,
151+
this.experiments,
152+
subProjects
153+
)
147154
)
148155

149156
this.dispose.track(this.data.onDidUpdate(data => this.setState(data)))
@@ -158,7 +165,7 @@ export class Experiments extends BaseRepository<TableData> {
158165

159166
this.webviewMessages = this.createWebviewMessageHandler()
160167
this.setupInitialData()
161-
this.watchActiveEditor()
168+
this.watchActiveEditor(subProjects)
162169
}
163170

164171
public update() {
@@ -600,13 +607,14 @@ export class Experiments extends BaseRepository<TableData> {
600607
)
601608
}
602609

603-
private watchActiveEditor() {
610+
private watchActiveEditor(subProjects: string[]) {
604611
setContextForEditorTitleIcons(
605612
this.dvcRoot,
606613
this.dispose,
607614
() => this.columns.getParamsFiles(),
608615
this.experimentsFileFocused,
609-
this.onDidChangeColumns
616+
this.onDidChangeColumns,
617+
subProjects
610618
)
611619
}
612620

extension/src/experiments/workspace.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
273273

274274
public createRepository(
275275
dvcRoot: string,
276+
subProjects: string[],
276277
pipeline: WorkspacePipeline,
277278
resourceLocator: ResourceLocator
278279
) {
@@ -283,7 +284,8 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
283284
pipeline.getRepository(dvcRoot),
284285
resourceLocator,
285286
this.workspaceState,
286-
(branchesSelected: string[]) => this.selectBranches(branchesSelected)
287+
(branchesSelected: string[]) => this.selectBranches(branchesSelected),
288+
subProjects
287289
)
288290
)
289291

extension/src/extension.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,26 @@ class Extension extends Disposable {
277277
public async initialize() {
278278
this.resetMembers()
279279

280+
const dvcRoots = this.getRoots()
281+
const subProjects = this.getSubProjects()
282+
280283
await Promise.all([
281-
this.repositories.create(this.getRoots()),
282-
this.repositoriesTree.initialize(this.getRoots()),
283-
this.pipelines.create(this.getRoots())
284+
this.repositories.create(dvcRoots, subProjects),
285+
this.repositoriesTree.initialize(dvcRoots),
286+
this.pipelines.create(dvcRoots, subProjects)
284287
])
285288
this.experiments.create(
286-
this.getRoots(),
289+
dvcRoots,
290+
subProjects,
287291
this.pipelines,
288292
this.resourceLocator
289293
)
290-
this.plots.create(this.getRoots(), this.resourceLocator, this.experiments)
294+
this.plots.create(
295+
dvcRoots,
296+
subProjects,
297+
this.resourceLocator,
298+
this.experiments
299+
)
291300

292301
return Promise.all([
293302
this.experiments.isReady(),
@@ -308,6 +317,10 @@ class Extension extends Disposable {
308317
private getRoots() {
309318
return this.setup.getRoots()
310319
}
320+
321+
private getSubProjects() {
322+
return this.setup.getSubProjects()
323+
}
311324
}
312325

313326
let extension: undefined | Extension

extension/src/fileSystem/index.test.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
getModifiedTime,
1717
findOrCreateDvcYamlFile,
1818
writeJson,
19-
writeCsv
19+
writeCsv,
20+
isPathInProject
2021
} from '.'
2122
import { dvcDemoPath } from '../test/util'
2223
import { DOT_DVC } from '../cli/dvc/constants'
@@ -408,3 +409,52 @@ describe('findOrCreateDvcYamlFile', () => {
408409
)
409410
})
410411
})
412+
413+
describe('isPathInProject', () => {
414+
it('should return true if the path is in the project', () => {
415+
const path = join(dvcDemoPath, 'dvc.yaml')
416+
const dvcRoot = dvcDemoPath
417+
const subProjects: string[] = []
418+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(true)
419+
})
420+
421+
it('should return false if the path is not in the project', () => {
422+
const path = resolve(dvcDemoPath, '..', 'dvc.yaml')
423+
const dvcRoot = dvcDemoPath
424+
const subProjects: string[] = []
425+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(false)
426+
})
427+
428+
it('should return false if the path is the project', () => {
429+
const path = dvcDemoPath
430+
const dvcRoot = dvcDemoPath
431+
const subProjects: string[] = []
432+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(false)
433+
})
434+
435+
it('should return false if the path is in the project but also in a sub-project', () => {
436+
const path = join(dvcDemoPath, 'nested1', 'dvc.yaml')
437+
const dvcRoot = dvcDemoPath
438+
const subProjects: string[] = [join(dvcDemoPath, 'nested1')]
439+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(false)
440+
})
441+
442+
it('should return false if the path is in the project but also in one of many sub-projects', () => {
443+
const path = join(dvcDemoPath, 'nested2', 'dvc.yaml')
444+
const dvcRoot = dvcDemoPath
445+
const subProjects: string[] = [
446+
join(dvcDemoPath, 'nested1'),
447+
join(dvcDemoPath, 'nested2'),
448+
join(dvcDemoPath, 'nested3'),
449+
join(dvcDemoPath, 'nested4')
450+
]
451+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(false)
452+
})
453+
454+
it('should return true if the path is in the project but not in a sub-project', () => {
455+
const path = join(dvcDemoPath, 'nested1', 'dvc.yaml')
456+
const dvcRoot = dvcDemoPath
457+
const subProjects: string[] = [join(dvcDemoPath, 'nested2')]
458+
expect(isPathInProject(path, dvcRoot, subProjects)).toBe(true)
459+
})
460+
})

extension/src/fileSystem/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,20 @@ export const isSameOrChild = (root: string, path: string) => {
126126
return !rel.startsWith('..')
127127
}
128128

129+
export const isPathInSubProject = (
130+
path: string,
131+
subProjects: string[]
132+
): boolean => subProjects.some(dvcRoot => path.startsWith(dvcRoot))
133+
134+
export const isPathInProject = (
135+
path: string | undefined,
136+
dvcRoot: string,
137+
subProjects: string[]
138+
): boolean =>
139+
!!path?.startsWith(dvcRoot) &&
140+
path !== dvcRoot &&
141+
!isPathInSubProject(path, subProjects)
142+
129143
export type Out =
130144
| string
131145
| Record<string, { checkpoint?: boolean; cache?: boolean }>

0 commit comments

Comments
 (0)