Path: blob/main/extensions/copilot/src/platform/filesystem/node/fileSystemServiceImpl.ts
13400 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as fs from 'fs';6import type { FileStat, FileSystemWatcher, RelativePattern, Uri } from 'vscode';7import { Event } from '../../../util/vs/base/common/event';8import { dirname, isEqual } from '../../../util/vs/base/common/resources';9import { URI } from '../../../util/vs/base/common/uri';10import { IWorkspaceService } from '../../workspace/common/workspaceService';11import { assertReadFileSizeLimit, IFileSystemService } from '../common/fileSystemService';12import { FileType } from '../common/fileTypes';1314export class NodeFileSystemService implements IFileSystemService {1516declare readonly _serviceBrand: undefined;171819async stat(uri: URI): Promise<FileStat> {20const stat = await fs.promises.stat(uri.fsPath);21return {22type: stat.isFile() ? FileType.File : FileType.Directory,23ctime: stat.ctimeMs,24mtime: stat.mtimeMs,25size: stat.size26};27}2829async readDirectory(uri: URI): Promise<[string, FileType][]> {30assetIsFileUri(uri);31const readDir = await fs.promises.readdir(uri.fsPath, { withFileTypes: true });32const result: [string, FileType][] = [];33for (const file of readDir) {34result.push([file.name, file.isFile() ? FileType.File : FileType.Directory]);35}36return result;37}3839async createDirectory(uri: URI): Promise<void> {40assetIsFileUri(uri);41return fs.promises.mkdir(uri.fsPath);42}4344async readFile(uri: URI, disableLimit?: boolean): Promise<Uint8Array> {45assetIsFileUri(uri);46await assertReadFileSizeLimit(this, uri, disableLimit);47return fs.promises.readFile(uri.fsPath);48}4950async writeFile(uri: URI, content: Uint8Array): Promise<void> {51assetIsFileUri(uri);52await fs.promises.mkdir(dirname(uri).fsPath, { recursive: true });53return fs.promises.writeFile(uri.fsPath, content);54}5556async delete(uri: URI, options?: { recursive?: boolean; useTrash?: boolean }): Promise<void> {57assetIsFileUri(uri);58return fs.promises.rm(uri.fsPath, { recursive: options?.recursive ?? false });59}6061async rename(oldURI: URI, newURI: URI, options?: { overwrite?: boolean }): Promise<void> {62assetIsFileUri(oldURI);63assetIsFileUri(newURI);64// Check if new path exists if overwrite is not set return65if (!options?.overwrite && fs.existsSync(newURI.fsPath)) {66return;67}6869return fs.promises.rename(oldURI.fsPath, newURI.fsPath);70}7172async copy(source: URI, destination: URI, options?: { overwrite?: boolean }): Promise<void> {73assetIsFileUri(source);74assetIsFileUri(destination);75// Calculate copy contants based on overwrite option76const copyConstant = options?.overwrite ? fs.constants.COPYFILE_FICLONE : fs.constants.COPYFILE_EXCL;77return fs.promises.copyFile(source.fsPath, destination.fsPath, copyConstant);78}7980isWritableFileSystem(scheme: string): boolean | undefined {81return true;82}8384createFileSystemWatcher(_glob: string | RelativePattern): FileSystemWatcher {85return new class implements FileSystemWatcher {86ignoreCreateEvents = false;87ignoreChangeEvents = false;88ignoreDeleteEvents = false;89onDidCreate = Event.None;90onDidChange = Event.None;91onDidDelete = Event.None;92dispose() {93// noop94}95};96}97}9899/**100* A helper utility to read a file from the open text buffer if applicable otherwise from the filesystem.101* This can be useful when you want to get the contents that are shown in the editor if a file is open, otherwise delegate to disk102* @param fileSystemService The filesystem service103* @param workspaceService The workspace service104* @param uri The uri to read105* @param maxBytesToRead An optional max bytes to read from the file system. If open, the entire document is always read.106* @returns A promise that resolves to the file content or the file buffer107*/108export async function readFileFromTextBufferOrFS(fileSystemService: IFileSystemService, workspaceService: IWorkspaceService, uri: Uri, maxBytesToRead?: number): Promise<string | Uint8Array> {109// First check open text documents110const file = workspaceService.textDocuments.find(d => isEqual(d.uri, uri));111if (file) {112return file.getText();113}114try {115assetIsFileUri(uri);116if (maxBytesToRead !== undefined) {117const fileHandle = await fs.promises.open(uri.fsPath, 'r');118try {119const buffer = Buffer.alloc(maxBytesToRead);120const { bytesRead } = await fileHandle.read(buffer, 0, maxBytesToRead, 0);121return buffer.subarray(0, bytesRead);122} finally {123await fileHandle.close();124}125}126return fileSystemService.readFile(uri);127} catch {128const buffer = await fileSystemService.readFile(uri);129if (maxBytesToRead) {130return buffer.subarray(0, maxBytesToRead);131}132return buffer;133}134}135136137function assetIsFileUri(uri: URI) {138if (uri.scheme !== 'file') {139throw new Error(`URI must be of file scheme, received ${uri.scheme}`);140}141}142143144