refactor(compiler-cli): add `removeDir()` to `FileSystem` (#35079)

PR Close #35079
This commit is contained in:
Pete Bacon Darwin 2020-01-31 21:07:59 +00:00 committed by Misko Hevery
parent 16e15f50d2
commit 2e52fcf1eb
11 changed files with 59 additions and 0 deletions

View File

@ -32,6 +32,7 @@ ts_library(
"@npm//@bazel/typescript",
"@npm//@types/chokidar",
"@npm//@types/node",
"@npm//fs-extra",
"@npm//minimist",
"@npm//reflect-metadata",
"@npm//tsickle",

View File

@ -47,6 +47,7 @@ const requiredNodeModules = {
'tslib': resolveNpmTreeArtifact('npm/node_modules/tslib'),
'domino': resolveNpmTreeArtifact('npm/node_modules/domino'),
'xhr2': resolveNpmTreeArtifact('npm/node_modules/xhr2'),
'fs-extra': resolveNpmTreeArtifact('npm/node_modules/fs-extra'),
// Fine grained dependencies which are used by the integration test Angular modules, and
// need to be symlinked so that they can be resolved by NodeJS or NGC.

View File

@ -9,7 +9,9 @@ ts_library(
]),
deps = [
"//packages:types",
"@npm//@types/fs-extra",
"@npm//@types/node",
"@npm//fs-extra",
"@npm//typescript",
],
)

View File

@ -88,6 +88,17 @@ export class CachedFileSystem implements FileSystem {
}
}
removeDeep(path: AbsoluteFsPath): void {
this.delegate.removeDeep(path);
// Clear out all children of this directory from the exists cache.
for (const p of this.existsCache.keys()) {
if (p.startsWith(path)) {
this.existsCache.set(path, false);
}
}
}
lstat(path: AbsoluteFsPath): FileStats {
const stat = this.delegate.lstat(path);
// if the `path` does not exist then `lstat` will thrown an error.

View File

@ -30,6 +30,7 @@ export class InvalidFileSystem implements FileSystem {
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); }
ensureDir(path: AbsoluteFsPath): void { throw makeError(); }
removeDeep(path: AbsoluteFsPath): void { throw makeError(); }
isCaseSensitive(): boolean { throw makeError(); }
resolve(...paths: string[]): AbsoluteFsPath { throw makeError(); }
dirname<T extends PathString>(file: T): T { throw makeError(); }

View File

@ -7,6 +7,7 @@
*/
/// <reference types="node" />
import * as fs from 'fs';
import * as fsExtra from 'fs-extra';
import * as p from 'path';
import {absoluteFrom, relativeFrom} from './helpers';
import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './types';
@ -40,6 +41,7 @@ export class NodeJSFileSystem implements FileSystem {
this.safeMkdir(parents.pop() !);
}
}
removeDeep(path: AbsoluteFsPath): void { fsExtra.removeSync(path); }
isCaseSensitive(): boolean {
if (this._caseSensitive === undefined) {
this._caseSensitive = this.exists(togglePathCase(__filename));

View File

@ -49,6 +49,7 @@ export interface FileSystem {
copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void;
ensureDir(path: AbsoluteFsPath): void;
removeDeep(path: AbsoluteFsPath): void;
isCaseSensitive(): boolean;
isRoot(path: AbsoluteFsPath): boolean;
isRooted(path: string): boolean;

View File

@ -12,6 +12,7 @@ ts_library(
"//packages:types",
"//packages/compiler-cli/src/ngtsc/file_system",
"//packages/compiler-cli/src/ngtsc/file_system/testing",
"@npm//@types/fs-extra",
"@npm//typescript",
],
)

View File

@ -272,4 +272,23 @@ describe('CachedFileSystem', () => {
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, 'removeDeep');
const existsSpy = spyOn(delegate, 'exists').and.returnValue(true);
expect(fs.exists(abcPath)).toBe(true);
existsSpy.calls.reset();
fs.removeDeep(abcPath);
expect(fs.exists(abcPath)).toBeFalsy();
expect(existsSpy).not.toHaveBeenCalled();
});
});
});

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import * as realFs from 'fs';
import * as fsExtra from 'fs-extra';
import {absoluteFrom, dirname, relativeFrom, setFileSystem} from '../src/helpers';
import {NodeJSFileSystem} from '../src/node_js_file_system';
import {AbsoluteFsPath} from '../src/types';
@ -148,6 +149,14 @@ describe('NodeJSFileSystem', () => {
expect(mkdirCalls).toEqual([xPath, xyPath, xyzPath]);
});
describe('removeDeep()', () => {
it('should delegate to fsExtra.remove()', () => {
const spy = spyOn(fsExtra, 'removeSync');
fs.removeDeep(abcPath);
expect(spy).toHaveBeenCalledWith(abcPath);
});
});
it('should not fail if a directory (that did not exist before) does exist when trying to create it',
() => {
let abcPathExists = false;

View File

@ -131,6 +131,17 @@ export abstract class MockFileSystem implements FileSystem {
}
}
removeDeep(path: AbsoluteFsPath): void {
const [folderPath, basename] = this.splitIntoFolderAndFile(path);
const {entity} = this.findFromPath(folderPath);
if (entity === null || !isFolder(entity)) {
throw new MockFileSystemError(
'ENOENT', path,
`Unable to remove folder "${path}". The containing folder does not exist.`);
}
delete entity[basename];
}
isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === path; }
extname(path: AbsoluteFsPath|PathSegment): string {