// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import * as fsextra from 'fs-extra';
import * as path from 'path';
import { FileStat, FileType, Uri } from 'vscode';
import { convertStat } from '../client/common/platform/fileSystem';
import { createDeferred } from '../client/common/utils/async';
/* eslint-disable class-methods-use-this */
// This is necessary for unit tests and functional tests, since they
// do not run under VS Code so they do not have access to the actual
// "vscode" namespace.
export class FakeVSCodeFileSystemAPI {
public async readFile(uri: Uri): Promise {
return fsextra.readFile(uri.fsPath);
}
public async writeFile(uri: Uri, content: Uint8Array): Promise {
return fsextra.writeFile(uri.fsPath, Buffer.from(content));
}
public async delete(uri: Uri): Promise {
return (
fsextra
// Make sure the file exists before deleting.
.stat(uri.fsPath)
.then(() => fsextra.remove(uri.fsPath))
);
}
public async stat(uri: Uri): Promise {
const filename = uri.fsPath;
let filetype = FileType.Unknown;
let stat = await fsextra.lstat(filename);
if (stat.isSymbolicLink()) {
filetype = FileType.SymbolicLink;
stat = await fsextra.stat(filename);
}
if (stat.isFile()) {
filetype |= FileType.File;
} else if (stat.isDirectory()) {
filetype |= FileType.Directory;
}
return convertStat(stat, filetype);
}
public async readDirectory(uri: Uri): Promise {
const names: string[] = await fsextra.readdir(uri.fsPath);
const promises = names.map((name) => {
const filename = path.join(uri.fsPath, name);
return (
fsextra
// Get the lstat info and deal with symlinks if necessary.
.lstat(filename)
.then(async (stat) => {
let filetype = FileType.Unknown;
if (stat.isFile()) {
filetype = FileType.File;
} else if (stat.isDirectory()) {
filetype = FileType.Directory;
} else if (stat.isSymbolicLink()) {
filetype = FileType.SymbolicLink;
stat = await fsextra.stat(filename);
if (stat.isFile()) {
filetype |= FileType.File;
} else if (stat.isDirectory()) {
filetype |= FileType.Directory;
}
}
return [name, filetype] as [string, FileType];
})
.catch(() => [name, FileType.Unknown] as [string, FileType])
);
});
return Promise.all(promises);
}
public async createDirectory(uri: Uri): Promise {
return fsextra.mkdirp(uri.fsPath);
}
public async copy(src: Uri, dest: Uri): Promise {
const deferred = createDeferred();
const rs = fsextra
// Set an error handler on the stream.
.createReadStream(src.fsPath)
.on('error', (err) => {
deferred.reject(err);
});
const ws = fsextra
.createWriteStream(dest.fsPath)
// Set an error & close handler on the stream.
.on('error', (err) => {
deferred.reject(err);
})
.on('close', () => {
deferred.resolve();
});
rs.pipe(ws);
return deferred.promise;
}
public async rename(src: Uri, dest: Uri): Promise {
return fsextra.rename(src.fsPath, dest.fsPath);
}
}