// 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<[string, FileType][]> { 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); } }