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 {
|
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void {
|
||||||
this.delegate.writeFile(path, data);
|
this.delegate.writeFile(path, data, exclusive);
|
||||||
this.readFileCache.set(path, data);
|
this.readFileCache.set(path, data);
|
||||||
this.existsCache.set(path, true);
|
this.existsCache.set(path, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './
|
||||||
export class InvalidFileSystem implements FileSystem {
|
export class InvalidFileSystem implements FileSystem {
|
||||||
exists(path: AbsoluteFsPath): boolean { throw makeError(); }
|
exists(path: AbsoluteFsPath): boolean { throw makeError(); }
|
||||||
readFile(path: AbsoluteFsPath): string { 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(); }
|
removeFile(path: AbsoluteFsPath): void { throw makeError(); }
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); }
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); }
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); }
|
readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); }
|
||||||
|
|
|
@ -18,7 +18,9 @@ export class NodeJSFileSystem implements FileSystem {
|
||||||
private _caseSensitive: boolean|undefined = undefined;
|
private _caseSensitive: boolean|undefined = undefined;
|
||||||
exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); }
|
exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); }
|
||||||
readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); }
|
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); }
|
removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); }
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); }
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); }
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; }
|
readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; }
|
||||||
|
|
|
@ -37,7 +37,7 @@ export type PathSegment = BrandedPath<'PathSegment'>;
|
||||||
export interface FileSystem {
|
export interface FileSystem {
|
||||||
exists(path: AbsoluteFsPath): boolean;
|
exists(path: AbsoluteFsPath): boolean;
|
||||||
readFile(path: AbsoluteFsPath): string;
|
readFile(path: AbsoluteFsPath): string;
|
||||||
writeFile(path: AbsoluteFsPath, data: string): void;
|
writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void;
|
||||||
removeFile(path: AbsoluteFsPath): void;
|
removeFile(path: AbsoluteFsPath): void;
|
||||||
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
|
symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void;
|
||||||
readdir(path: AbsoluteFsPath): PathSegment[];
|
readdir(path: AbsoluteFsPath): PathSegment[];
|
||||||
|
|
|
@ -94,7 +94,10 @@ describe('CachedFileSystem', () => {
|
||||||
it('should call delegate', () => {
|
it('should call delegate', () => {
|
||||||
const spy = spyOn(delegate, 'writeFile');
|
const spy = spyOn(delegate, 'writeFile');
|
||||||
fs.writeFile(abcPath, 'Some contents');
|
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', () => {
|
it('should update the exists and "readFile" caches', () => {
|
||||||
|
|
|
@ -47,7 +47,10 @@ describe('NodeJSFileSystem', () => {
|
||||||
it('should delegate to fs.writeFileSync()', () => {
|
it('should delegate to fs.writeFileSync()', () => {
|
||||||
const spy = spyOn(realFs, 'writeFileSync');
|
const spy = spyOn(realFs, 'writeFileSync');
|
||||||
fs.writeFile(abcPath, 'Some contents');
|
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 [folderPath, basename] = this.splitIntoFolderAndFile(path);
|
||||||
const {entity} = this.findFromPath(folderPath);
|
const {entity} = this.findFromPath(folderPath);
|
||||||
if (entity === null || !isFolder(entity)) {
|
if (entity === null || !isFolder(entity)) {
|
||||||
throw new MockFileSystemError(
|
throw new MockFileSystemError(
|
||||||
'ENOENT', path, `Unable to write file "${path}". The containing folder does not exist.`);
|
'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;
|
entity[basename] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue