refactor(ivy): add exclusive mode to `writeFile()` (#34722)
This commit adds an `exclusive` parameter to the `FileSystem.writeFile()` method. When this parameter is true, the method will fail with an `EEXIST` error if the file already exists on disk. PR Close #34722
This commit is contained in:
parent
ecbc25044c
commit
3a6cb6a5d2
|
@ -48,8 +48,8 @@ export class CachedFileSystem implements FileSystem {
|
|||
}
|
||||
}
|
||||
|
||||
writeFile(path: AbsoluteFsPath, data: string): void {
|
||||
this.delegate.writeFile(path, data);
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void {
|
||||
this.delegate.writeFile(path, data, exclusive);
|
||||
this.readFileCache.set(path, data);
|
||||
this.existsCache.set(path, true);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
|||
export class InvalidFileSystem implements FileSystem {
|
||||
exists(path: AbsoluteFsPath): boolean { throw makeError(); }
|
||||
readFile(path: AbsoluteFsPath): string { throw makeError(); }
|
||||
writeFile(path: AbsoluteFsPath, data: string): void { throw makeError(); }
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { throw makeError(); }
|
||||
removeFile(path: AbsoluteFsPath): void { throw makeError(); }
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); }
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); }
|
||||
|
|
|
@ -18,7 +18,9 @@ export class NodeJSFileSystem implements FileSystem {
|
|||
private _caseSensitive: boolean|undefined = undefined;
|
||||
exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); }
|
||||
readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); }
|
||||
writeFile(path: AbsoluteFsPath, data: string): void { fs.writeFileSync(path, data, 'utf8'); }
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
|
||||
fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined);
|
||||
}
|
||||
removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); }
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); }
|
||||
readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; }
|
||||
|
|
|
@ -37,7 +37,7 @@ export type PathSegment = BrandedPath<'PathSegment'>;
|
|||
export interface FileSystem {
|
||||
exists(path: AbsoluteFsPath): boolean;
|
||||
readFile(path: AbsoluteFsPath): string;
|
||||
writeFile(path: AbsoluteFsPath, data: string): void;
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void;
|
||||
removeFile(path: AbsoluteFsPath): void;
|
||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
|
||||
readdir(path: AbsoluteFsPath): PathSegment[];
|
||||
|
|
|
@ -94,7 +94,10 @@ describe('CachedFileSystem', () => {
|
|||
it('should call delegate', () => {
|
||||
const spy = spyOn(delegate, 'writeFile');
|
||||
fs.writeFile(abcPath, 'Some contents');
|
||||
expect(spy).toHaveBeenCalledWith(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', () => {
|
||||
|
|
|
@ -47,7 +47,10 @@ describe('NodeJSFileSystem', () => {
|
|||
it('should delegate to fs.writeFileSync()', () => {
|
||||
const spy = spyOn(realFs, 'writeFileSync');
|
||||
fs.writeFile(abcPath, 'Some contents');
|
||||
expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', 'utf8');
|
||||
expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', undefined);
|
||||
spy.calls.reset();
|
||||
fs.writeFile(abcPath, 'Some contents', /* exclusive */ true);
|
||||
expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', {flag: 'wx'});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -34,13 +34,17 @@ export abstract class MockFileSystem implements FileSystem {
|
|||
}
|
||||
}
|
||||
|
||||
writeFile(path: AbsoluteFsPath, data: string): void {
|
||||
writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void {
|
||||
const [folderPath, basename] = this.splitIntoFolderAndFile(path);
|
||||
const {entity} = this.findFromPath(folderPath);
|
||||
if (entity === null || !isFolder(entity)) {
|
||||
throw new MockFileSystemError(
|
||||
'ENOENT', path, `Unable to write file "${path}". The containing folder does not exist.`);
|
||||
}
|
||||
if (exclusive && entity[basename] !== undefined) {
|
||||
throw new MockFileSystemError(
|
||||
'EEXIST', path, `Unable to exclusively write file "${path}". The file already exists.`);
|
||||
}
|
||||
entity[basename] = data;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue