提交 7683db24 编写于 作者: B Benjamin Pasero

Create File overwrites existing files without warning (fixes #33899)

上级 b0c06343
......@@ -93,7 +93,7 @@ export interface IFileService {
*
* The optional parameter content can be used as value to fill into the new file.
*/
createFile(resource: URI, content?: string): TPromise<IFileStat>;
createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise<IFileStat>;
/**
* Creates a new folder with the given path. The returned promise
......@@ -491,6 +491,15 @@ export interface IResolveFileOptions {
resolveSingleChildDescendants?: boolean;
}
export interface ICreateFileOptions {
/**
* Overwrite the file to create if it already exists on disk. Otherwise
* an error will be thrown (FILE_MODIFIED_SINCE).
*/
overwrite?: boolean;
}
export interface IImportResult {
stat: IFileStat;
isNew: boolean;
......
......@@ -12,7 +12,7 @@ import encoding = require('vs/base/node/encoding');
import errors = require('vs/base/common/errors');
import uri from 'vs/base/common/uri';
import { toResource } from 'vs/workbench/common/editor';
import { FileOperation, FileOperationEvent, IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IResolveFileResult, IContent, IStreamContent, IImportResult, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent } from 'vs/platform/files/common/files';
import { FileOperation, FileOperationEvent, IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IResolveFileResult, IContent, IStreamContent, IImportResult, IResolveContentOptions, IUpdateContentOptions, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files';
import { FileService as NodeFileService, IFileServiceOptions, IEncodingOverride } from 'vs/workbench/services/files/node/fileService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
......@@ -224,8 +224,8 @@ export class FileService implements IFileService {
return this.raw.copyFile(source, target, overwrite);
}
public createFile(resource: uri, content?: string): TPromise<IFileStat> {
return this.raw.createFile(resource, content);
public createFile(resource: uri, content?: string, options?: ICreateFileOptions): TPromise<IFileStat> {
return this.raw.createFile(resource, content, options);
}
public createFolder(resource: uri): TPromise<IFileStat> {
......
......@@ -11,7 +11,7 @@ import os = require('os');
import crypto = require('crypto');
import assert = require('assert');
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, IFilesConfiguration } from 'vs/platform/files/common/files';
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, IFilesConfiguration, ICreateFileOptions } from 'vs/platform/files/common/files';
import { isEqualOrParent } from 'vs/base/common/paths';
import { ResourceMap } from 'vs/base/common/map';
import arrays = require('vs/base/common/arrays');
......@@ -220,7 +220,7 @@ export class FileService implements IFileService {
// Guard early against attempts to resolve an invalid file path
if (resource.scheme !== 'file' || !resource.fsPath) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(
nls.localize('fileInvalidPath', "Invalid file resource ({0})", resource.toString()),
nls.localize('fileInvalidPath', "Invalid file resource ({0})", resource.toString(true)),
FileOperationResult.FILE_INVALID_PATH
));
}
......@@ -292,7 +292,7 @@ export class FileService implements IFileService {
// Return if file not found
if (!exists) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(
nls.localize('fileNotFoundError', "File not found ({0})", resource.toString()),
nls.localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
FileOperationResult.FILE_NOT_FOUND
));
}
......@@ -381,15 +381,33 @@ export class FileService implements IFileService {
});
}
public createFile(resource: uri, content: string = ''): TPromise<IFileStat> {
public createFile(resource: uri, content: string = '', options: ICreateFileOptions = Object.create(null)): TPromise<IFileStat> {
const absolutePath = this.toAbsolutePath(resource);
// Create file
return this.updateContent(resource, content).then(result => {
let checkFilePromise: TPromise<boolean>;
if (options.overwrite) {
checkFilePromise = TPromise.as(false);
} else {
checkFilePromise = pfs.exists(absolutePath);
}
// Events
this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, result));
// Check file exists
return checkFilePromise.then(exists => {
if (exists && !options.overwrite) {
return TPromise.wrapError<IFileStat>(new FileOperationError(
nls.localize('fileExists', "File to create already exits ({0})", resource.toString(true)),
FileOperationResult.FILE_MODIFIED_SINCE
));
}
return result;
// Create file
return this.updateContent(resource, content).then(result => {
// Events
this._onAfterOperation.fire(new FileOperationEvent(resource, FileOperation.CREATE, result));
return result;
});
});
}
......
......@@ -71,6 +71,45 @@ suite('FileService', () => {
}, error => onError(error, done));
});
test('createFile (does not overwrite by default)', function (done: () => void) {
const contents = 'Hello World';
const resource = uri.file(path.join(testDir, 'test.txt'));
fs.writeFileSync(resource.fsPath, ''); // create file
service.createFile(resource, contents).done(null, error => {
assert.ok(error);
done();
});
});
test('createFile (allows to overwrite existing)', function (done: () => void) {
let event: FileOperationEvent;
const toDispose = service.onAfterOperation(e => {
event = e;
});
const contents = 'Hello World';
const resource = uri.file(path.join(testDir, 'test.txt'));
fs.writeFileSync(resource.fsPath, ''); // create file
service.createFile(resource, contents, { overwrite: true }).done(s => {
assert.equal(s.name, 'test.txt');
assert.equal(fs.existsSync(s.resource.fsPath), true);
assert.equal(fs.readFileSync(s.resource.fsPath), contents);
assert.ok(event);
assert.equal(event.resource.fsPath, resource.fsPath);
assert.equal(event.operation, FileOperation.CREATE);
assert.equal(event.target.resource.fsPath, resource.fsPath);
toDispose.dispose();
done();
}, error => onError(error, done));
});
test('createFolder', function (done: () => void) {
let event: FileOperationEvent;
const toDispose = service.onAfterOperation(e => {
......
......@@ -34,7 +34,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEditorGroupService, GroupArrangement, GroupOrientation, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService';
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
import { FileOperationEvent, IFileService, IResolveContentOptions, FileOperationError, IFileStat, IResolveFileResult, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent } from 'vs/platform/files/common/files';
import { FileOperationEvent, IFileService, IResolveContentOptions, FileOperationError, IFileStat, IResolveFileResult, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent, ICreateFileOptions } from 'vs/platform/files/common/files';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
......@@ -749,7 +749,7 @@ export class TestFileService implements IFileService {
return TPromise.as(null);
}
createFile(resource: URI, content?: string): TPromise<IFileStat> {
createFile(resource: URI, content?: string, options?: ICreateFileOptions): TPromise<IFileStat> {
return TPromise.as(null);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册