From 969c2e4ed344a115de711cd087539e9aa2b3c795 Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Wed, 18 Sep 2024 10:26:32 -0600 Subject: [PATCH] chore: forceignore caching --- src/resolve/forceIgnore.ts | 25 +++++++++++++++++++++---- src/resolve/sourceComponent.ts | 2 +- src/resolve/treeContainers.ts | 8 +++++++- test/resolve/forceIgnore.test.ts | 8 ++------ 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/resolve/forceIgnore.ts b/src/resolve/forceIgnore.ts index baa99bbde8..b154301677 100644 --- a/src/resolve/forceIgnore.ts +++ b/src/resolve/forceIgnore.ts @@ -18,6 +18,7 @@ export class ForceIgnore { private readonly parser?: Ignore; private readonly forceIgnoreDirectory?: string; private DEFAULT_IGNORE = ['**/*.dup', '**/.*', '**/package2-descriptor.json', '**/package2-manifest.json']; + private isPathIgnored = new Map(); public constructor(forceIgnorePath = '') { try { @@ -64,19 +65,35 @@ export class ForceIgnore { public denies(fsPath: SourcePath): boolean { if (!this.parser || !this.forceIgnoreDirectory) return false; + // we've already figured out if this path is ignored or not, just get it from the cache + if (this.isPathIgnored.has(fsPath)) return this.isPathIgnored.get(fsPath)!; + + let result: boolean; try { - return this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath)); + result = this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath)); } catch (e) { - return false; + result = false; } + + this.isPathIgnored.set(fsPath, result); + + return result; } public accepts(fsPath: SourcePath): boolean { if (!this.parser || !this.forceIgnoreDirectory) return true; + // we've already figured out if this path is ignored or not, just get it from the cache + // the cache is set for 'denies' so for accept, negate the result + if (this.isPathIgnored.has(fsPath)) return !this.isPathIgnored.get(fsPath); + + let result: boolean; try { - return !this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath)); + result = !this.parser.ignores(relative(this.forceIgnoreDirectory, fsPath)); } catch (e) { - return true; + result = true; } + // since the cache has the 'denies' result, negate the result here + this.isPathIgnored.set(fsPath, !result); + return result; } } diff --git a/src/resolve/sourceComponent.ts b/src/resolve/sourceComponent.ts index c4e059e338..7abb3e8a3c 100644 --- a/src/resolve/sourceComponent.ts +++ b/src/resolve/sourceComponent.ts @@ -287,7 +287,7 @@ export class SourceComponent implements MetadataComponent { } private parse(contents: string): T { - const parsed = parser.parse(String(contents)) as T; + const parsed = parser.parse(contents) as T; const [firstElement] = Object.keys(parsed); if (firstElement === this.type.name) { return parsed; diff --git a/src/resolve/treeContainers.ts b/src/resolve/treeContainers.ts index 6462acd217..eacefa46d6 100644 --- a/src/resolve/treeContainers.ts +++ b/src/resolve/treeContainers.ts @@ -25,6 +25,7 @@ const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sd * Extend this base class to implement a custom container. */ export abstract class TreeContainer { + protected fileContentMap: Map = new Map(); /** * Searches for a metadata component file in a container directory. * @@ -110,7 +111,12 @@ export class NodeFSTreeContainer extends TreeContainer { } public readFileSync(fsPath: SourcePath): Buffer { - return readFileSync(fsPath); + if (this.fileContentMap.has(fsPath)) { + return this.fileContentMap.get(fsPath)!; + } else { + this.fileContentMap.set(fsPath, readFileSync(fsPath)); + return this.fileContentMap.get(fsPath)!; + } } public stream(fsPath: SourcePath): Readable { diff --git a/test/resolve/forceIgnore.test.ts b/test/resolve/forceIgnore.test.ts index 007ffbd246..c341e6ddd7 100644 --- a/test/resolve/forceIgnore.test.ts +++ b/test/resolve/forceIgnore.test.ts @@ -71,10 +71,6 @@ describe('ForceIgnore', () => { expect(fi.accepts(join('force-app', 'main', 'default', 'classes'))).to.be.true; }); - /** - * TODO: Rework when approach to default patterns changes. We should be able - * to generally test the defaults system. - */ describe('Defaults with new parser', () => { let forceIgnore: ForceIgnore; const root = join('some', 'path'); @@ -84,8 +80,8 @@ describe('ForceIgnore', () => { forceIgnore = new ForceIgnore(); }); - // the example's index here is specific to the rules order in ForceIgnore.DEFAULT_IGNORE - const forceIgnoreExamples = ['abc.dup', '.xyz', 'package2-descriptor.json', 'package2-manifest.json']; + // these examples test the default behaviors - check the cache behavior with the duplicate 'abc.dup' + const forceIgnoreExamples = ['abc.dup', 'abc.dup', '.xyz', 'package2-descriptor.json', 'package2-manifest.json']; forceIgnoreExamples.map((ignore) => { it(`Should ignore files starting with a ${ignore}`, () => { const testPath = join(root, ignore);