From 351759906b0df0c2cee407e787cd9e31d95b0a01 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Fri, 17 Apr 2020 14:36:51 +0100 Subject: [PATCH] refactor(compiler): remove unused CachedFileSystem (#36687) This was only being used by ngcc but not any longer. PR Close #36687 --- .../src/ngtsc/file_system/index.ts | 1 - .../file_system/src/cached_file_system.ts | 179 --------- .../test/cached_file_system_spec.ts | 372 ------------------ 3 files changed, 552 deletions(-) delete mode 100644 packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts delete mode 100644 packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts diff --git a/packages/compiler-cli/src/ngtsc/file_system/index.ts b/packages/compiler-cli/src/ngtsc/file_system/index.ts index 2bf3079757..f706e913ae 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/index.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/index.ts @@ -5,7 +5,6 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -export {CachedFileSystem} from './src/cached_file_system'; export {NgtscCompilerHost} from './src/compiler_host'; export {absoluteFrom, absoluteFromSourceFile, basename, dirname, getFileSystem, isRoot, isRooted, join, relative, relativeFrom, resolve, setFileSystem} from './src/helpers'; export {LogicalFileSystem, LogicalProjectPath} from './src/logical'; diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts deleted file mode 100644 index 1f04bb2bab..0000000000 --- a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts +++ /dev/null @@ -1,179 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './types'; - - -/** - * A wrapper around `FileSystem` that caches hits to `exists()` and - * `readFile()` to improve performance. - * - * Be aware that any changes to the file system from outside of this - * class could break the cache, leaving it with stale values. - */ -export class CachedFileSystem implements FileSystem { - private existsCache = new Map(); - private readFileCache = new Map(); - - constructor(private delegate: FileSystem) {} - - exists(path: AbsoluteFsPath): boolean { - if (!this.existsCache.has(path)) { - this.existsCache.set(path, this.delegate.exists(path)); - } - return this.existsCache.get(path)!; - } - - invalidateCaches(path: AbsoluteFsPath) { - this.readFileCache.delete(path); - this.existsCache.delete(path); - } - - readFile(path: AbsoluteFsPath): string { - if (!this.readFileCache.has(path)) { - try { - if (this.lstat(path).isSymbolicLink()) { - // don't cache the value of a symbolic link - return this.delegate.readFile(path); - } - this.readFileCache.set(path, this.delegate.readFile(path)); - } catch (e) { - this.readFileCache.set(path, e); - } - } - const result = this.readFileCache.get(path); - if (typeof result === 'string') { - return result; - } else { - throw result; - } - } - - writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { - this.delegate.writeFile(path, data, exclusive); - this.readFileCache.set(path, data); - this.existsCache.set(path, true); - } - - removeFile(path: AbsoluteFsPath): void { - this.delegate.removeFile(path); - this.readFileCache.delete(path); - this.existsCache.set(path, false); - } - - symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { - this.delegate.symlink(target, path); - this.existsCache.set(path, true); - } - - copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { - this.delegate.copyFile(from, to); - this.existsCache.set(to, true); - } - - moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { - this.delegate.moveFile(from, to); - - this.existsCache.set(from, false); - this.existsCache.set(to, true); - - if (this.readFileCache.has(from)) { - this.readFileCache.set(to, this.readFileCache.get(from)); - this.readFileCache.delete(from); - } else { - this.readFileCache.delete(to); - } - } - - ensureDir(path: AbsoluteFsPath): void { - this.delegate.ensureDir(path); - while (!this.isRoot(path)) { - this.existsCache.set(path, true); - path = this.dirname(path); - } - } - - removeDeep(path: AbsoluteFsPath): void { - this.delegate.removeDeep(path); - - // Clear out this directory and all its children from the `exists` cache. - for (const p of this.existsCache.keys()) { - if (p.startsWith(path)) { - this.existsCache.set(p, false); - } - } - - // Clear out this directory and all its children from the `readFile` cache. - for (const p of this.readFileCache.keys()) { - if (p.startsWith(path)) { - this.readFileCache.delete(p); - } - } - } - - - lstat(path: AbsoluteFsPath): FileStats { - const stat = this.delegate.lstat(path); - // if the `path` does not exist then `lstat` will thrown an error. - this.existsCache.set(path, true); - return stat; - } - - stat(path: AbsoluteFsPath): FileStats { - const stat = this.delegate.stat(path); - // if the `path` does not exist then `stat` will thrown an error. - this.existsCache.set(path, true); - return stat; - } - - // The following methods simply call through to the delegate. - readdir(path: AbsoluteFsPath): PathSegment[] { - return this.delegate.readdir(path); - } - pwd(): AbsoluteFsPath { - return this.delegate.pwd(); - } - chdir(path: AbsoluteFsPath): void { - this.delegate.chdir(path); - } - extname(path: AbsoluteFsPath|PathSegment): string { - return this.delegate.extname(path); - } - isCaseSensitive(): boolean { - return this.delegate.isCaseSensitive(); - } - isRoot(path: AbsoluteFsPath): boolean { - return this.delegate.isRoot(path); - } - isRooted(path: string): boolean { - return this.delegate.isRooted(path); - } - resolve(...paths: string[]): AbsoluteFsPath { - return this.delegate.resolve(...paths); - } - dirname(file: T): T { - return this.delegate.dirname(file); - } - join(basePath: T, ...paths: string[]): T { - return this.delegate.join(basePath, ...paths); - } - relative(from: T, to: T): PathSegment { - return this.delegate.relative(from, to); - } - basename(filePath: string, extension?: string|undefined): PathSegment { - return this.delegate.basename(filePath, extension); - } - realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { - return this.delegate.realpath(filePath); - } - getDefaultLibLocation(): AbsoluteFsPath { - return this.delegate.getDefaultLibLocation(); - } - normalize(path: T): T { - return this.delegate.normalize(path); - } -} diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts deleted file mode 100644 index d8bc40dfd5..0000000000 --- a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts +++ /dev/null @@ -1,372 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import {CachedFileSystem} from '../src/cached_file_system'; -import {absoluteFrom, join, setFileSystem} from '../src/helpers'; -import {NodeJSFileSystem} from '../src/node_js_file_system'; -import {AbsoluteFsPath, FileSystem} from '../src/types'; - -describe('CachedFileSystem', () => { - let delegate: FileSystem; - let fs: CachedFileSystem; - let abcPath: AbsoluteFsPath; - let xyzPath: AbsoluteFsPath; - - beforeEach(() => { - delegate = new NodeJSFileSystem(); - fs = new CachedFileSystem(delegate); - // Set the file-system so that calls like `absoluteFrom()` - // and `PathSegment.fromFsPath()` work correctly. - setFileSystem(fs); - abcPath = absoluteFrom('/a/b/c'); - xyzPath = absoluteFrom('/x/y/z'); - }); - - describe('exists()', () => { - it('should call delegate if not in cache', () => { - const spy = spyOn(delegate, 'exists').and.returnValue(true); - expect(fs.exists(abcPath)).toBe(true); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should take from the cache if available', () => { - const spy = spyOn(delegate, 'exists').and.returnValue(true); - fs.exists(abcPath); // Call once to fill the cache - spy.calls.reset(); - - expect(fs.exists(abcPath)).toBe(true); - expect(spy).not.toHaveBeenCalled(); - }); - }); - - describe('readFile()', () => { - let lstatSpy: jasmine.Spy; - beforeEach(() => { - // For most of the tests the files are not symbolic links. - lstatSpy = spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); - }); - - it('should call delegate if not in cache', () => { - const spy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); - expect(fs.readFile(abcPath)).toBe('Some contents'); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should take from the cache if available', () => { - const spy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); - fs.readFile(abcPath); // Call once to fill the cache - spy.calls.reset(); - - expect(fs.readFile(abcPath)).toBe('Some contents'); - expect(spy).not.toHaveBeenCalled(); - }); - - it('should cache the exception if it originally threw', () => { - const spy = spyOn(delegate, 'readFile').and.throwError('Some error'); - expect(() => fs.readFile(abcPath)).toThrowError('Some error'); - spy.calls.reset(); - expect(() => fs.readFile(abcPath)).toThrowError('Some error'); - expect(spy).not.toHaveBeenCalled(); - }); - - it('should always call delegate (and not cache) if the path is a symbolic link', () => { - const readFileSpy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); - // Simulate a symlink by overriding `lstat` - lstatSpy.and.returnValue({isSymbolicLink: () => true}); - - // Read the symlink target file contents - expect(fs.readFile(abcPath)).toEqual('Some contents'); - expect(lstatSpy).toHaveBeenCalledWith(abcPath); - - // Now read it again and check that the cache was not hit - lstatSpy.calls.reset(); - readFileSpy.calls.reset(); - expect(fs.readFile(abcPath)).toEqual('Some contents'); - expect(lstatSpy).toHaveBeenCalledWith(abcPath); - }); - }); - - describe('invalidateCaches()', () => { - it('should call the delegate `readFile()` if the path for the cached file has been invalidated', - () => { - spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); - const spy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); - fs.readFile(abcPath); // Call once to fill the cache - spy.calls.reset(); - - expect(fs.readFile(abcPath)).toBe('Some contents'); - expect(spy).not.toHaveBeenCalled(); - - fs.invalidateCaches(abcPath); - - expect(fs.readFile(abcPath)).toBe('Some contents'); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should call the delegate `exists()` if the path for the cached file has been invalidated', - () => { - const spy = spyOn(delegate, 'exists').and.returnValue(true); - fs.exists(abcPath); // Call once to fill the cache - spy.calls.reset(); - - expect(fs.exists(abcPath)).toBe(true); - expect(spy).not.toHaveBeenCalled(); - - fs.invalidateCaches(abcPath); - - expect(fs.exists(abcPath)).toBe(true); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - }); - - describe('writeFile()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'writeFile'); - fs.writeFile(abcPath, 'Some contents'); - expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', undefined); - spy.calls.reset(); - fs.writeFile(abcPath, 'Some contents', /* exclusive */ true); - expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', true); - }); - - it('should update the exists and "readFile" caches', () => { - spyOn(delegate, 'writeFile'); - const existsSpy = spyOn(delegate, 'exists'); - const readFileSpy = spyOn(delegate, 'readFile'); - - fs.writeFile(abcPath, 'Some contents'); - expect(fs.readFile(abcPath)).toEqual('Some contents'); - expect(fs.exists(abcPath)).toBe(true); - expect(existsSpy).not.toHaveBeenCalled(); - expect(readFileSpy).not.toHaveBeenCalled(); - }); - }); - - describe('removeFile()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'removeFile'); - fs.removeFile(abcPath); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the exists cache', () => { - spyOn(delegate, 'removeFile'); - const existsSpy = spyOn(delegate, 'exists'); - - fs.removeFile(abcPath); - expect(fs.exists(abcPath)).toBe(false); - expect(existsSpy).not.toHaveBeenCalled(); - }); - }); - - describe('readdir()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'readdir'); - fs.readdir(abcPath); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - }); - - describe('lstat()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'lstat'); - fs.lstat(abcPath); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the "exists" cache', () => { - spyOn(delegate, 'lstat'); - const existsSpy = spyOn(delegate, 'exists'); - fs.lstat(abcPath); - expect(fs.exists(abcPath)).toBe(true); - expect(existsSpy).not.toHaveBeenCalled(); - }); - }); - - describe('stat()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'stat'); - fs.stat(abcPath); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the "exists" cache', () => { - spyOn(delegate, 'stat'); - const existsSpy = spyOn(delegate, 'exists'); - fs.stat(abcPath); - expect(fs.exists(abcPath)).toBe(true); - expect(existsSpy).not.toHaveBeenCalled(); - }); - }); - - describe('pwd()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'pwd'); - fs.pwd(); - expect(spy).toHaveBeenCalledWith(); - }); - }); - - describe('copyFile()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'copyFile'); - fs.copyFile(abcPath, xyzPath); - expect(spy).toHaveBeenCalledWith(abcPath, xyzPath); - }); - - it('should update the "exists" cache', () => { - spyOn(delegate, 'copyFile'); - const existsSpy = spyOn(delegate, 'exists').and.returnValue(false); - fs.copyFile(abcPath, xyzPath); - expect(fs.exists(xyzPath)).toEqual(true); - expect(existsSpy).not.toHaveBeenCalled(); - }); - }); - - describe('moveFile()', () => { - beforeEach(() => { - // `moveFile()` relies upon `readFile` which calls through to `lstat()`, so stub it out. - spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); - }); - - it('should call delegate', () => { - const spy = spyOn(delegate, 'moveFile'); - fs.moveFile(abcPath, xyzPath); - expect(spy).toHaveBeenCalledWith(abcPath, xyzPath); - }); - - it('should update the "exists" cache', () => { - spyOn(delegate, 'moveFile'); - const existsSpy = spyOn(delegate, 'exists'); - - fs.moveFile(abcPath, xyzPath); - - expect(fs.exists(abcPath)).toEqual(false); - expect(fs.exists(xyzPath)).toEqual(true); - expect(existsSpy).not.toHaveBeenCalled(); - }); - - it('should delete the `from` "readFile" cache', () => { - spyOn(delegate, 'moveFile'); - const readFileSpy = spyOn(delegate, 'readFile'); - - // Fill the abc "readFile" cache - readFileSpy.and.returnValue('abc content'); - fs.readFile(abcPath); - - // Move the file - fs.moveFile(abcPath, xyzPath); - - // Emulate an error now that the file has been moved. - readFileSpy.and.throwError('no file'); - - // Show that asking for the abc file does not read from the cache - expect(() => fs.readFile(abcPath)).toThrowError('no file'); - expect(readFileSpy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the `to` "readFile" cache (if `from` was cached)', () => { - spyOn(delegate, 'moveFile'); - const readFileSpy = spyOn(delegate, 'readFile'); - - // Fill the abc "readFile" cache - readFileSpy.and.returnValue('abc content'); - fs.readFile(abcPath); - readFileSpy.calls.reset(); - - // Move the file - fs.moveFile(abcPath, xyzPath); - - // Show that the cache was hit for the xyz file - expect(fs.readFile(xyzPath)).toEqual('abc content'); - expect(readFileSpy).not.toHaveBeenCalled(); - }); - - it('should delete the `to` "readFile" cache (if `from` was not cached)', () => { - spyOn(delegate, 'moveFile'); - const readFileSpy = spyOn(delegate, 'readFile'); - - // Fill the xyz "readFile" cache - readFileSpy.and.returnValue('xyz content'); - fs.readFile(xyzPath); - readFileSpy.calls.reset(); - - // Move the file - fs.moveFile(abcPath, xyzPath); - - // Show that the cache was not hit for the xyz file - readFileSpy.and.returnValue('abc content'); - expect(fs.readFile(xyzPath)).toBe('abc content'); - expect(readFileSpy).toHaveBeenCalledWith(xyzPath); - }); - }); - - describe('ensureDir()', () => { - it('should call delegate', () => { - const ensureDirSpy = spyOn(delegate, 'ensureDir'); - fs.ensureDir(abcPath); - expect(ensureDirSpy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the "exists" cache', () => { - spyOn(delegate, 'ensureDir'); - const existsSpy = spyOn(delegate, 'exists'); - fs.ensureDir(abcPath); - existsSpy.calls.reset(); - expect(fs.exists(abcPath)).toEqual(true); - expect(fs.exists(absoluteFrom('/a/b'))).toEqual(true); - expect(fs.exists(absoluteFrom('/a'))).toEqual(true); - expect(existsSpy).not.toHaveBeenCalled(); - }); - }); - - describe('removeDeep()', () => { - it('should call delegate', () => { - const spy = spyOn(delegate, 'removeDeep'); - fs.removeDeep(abcPath); - expect(spy).toHaveBeenCalledWith(abcPath); - }); - - it('should update the exists cache', () => { - spyOn(delegate, 'writeFile'); - spyOn(delegate, 'removeDeep'); - const existsSpy = spyOn(delegate, 'exists').and.returnValue(true); - expect(fs.exists(abcPath)).toBe(true); - existsSpy.calls.reset(); - - // Create a file inside `/a/b/c`. - const abcdPath = join(abcPath, 'd'); - fs.writeFile(abcdPath, 'content'); - expect(fs.exists(abcdPath)).toBe(true); - expect(existsSpy).not.toHaveBeenCalled(); - - // Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content). - fs.removeDeep(abcPath); - expect(fs.exists(abcPath)).toBeFalsy(); - expect(fs.exists(abcdPath)).toBeFalsy(); - expect(existsSpy).not.toHaveBeenCalled(); - }); - - it('should update the readFile cache', () => { - spyOn(delegate, 'writeFile'); - spyOn(delegate, 'removeDeep'); - spyOn(delegate, 'lstat').and.throwError('ENOENT: no such file or directory'); - const readFileSpy = spyOn(delegate, 'readFile'); - - // Create a file inside `/a/b/c`. - const abcdPath = join(abcPath, 'd'); - fs.writeFile(abcdPath, 'content from cache'); - expect(fs.readFile(abcdPath)).toBe('content from cache'); - expect(readFileSpy).not.toHaveBeenCalled(); - - // Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content). - fs.removeDeep(abcPath); - expect(() => fs.readFile(abcdPath)).toThrowError('ENOENT: no such file or directory'); - expect(() => fs.readFile(abcPath)).toThrowError('ENOENT: no such file or directory'); - }); - }); -});