Path: blob/main/extensions/copilot/src/platform/filesystem/common/fileSystemService.ts
13401 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 type { FileStat, FileSystem, FileSystemWatcher, RelativePattern, Uri } from 'vscode';6import { LRUCache } from '../../../util/common/cache';7import { createServiceIdentifier } from '../../../util/common/services';8import { FileType } from './fileTypes';910export const IFileSystemService = createServiceIdentifier<IFileSystemService>('IFileSystemService');1112export interface IFileSystemService extends FileSystem {1314readonly _serviceBrand: undefined;1516stat(uri: Uri): Promise<FileStat>;17readDirectory(uri: Uri): Promise<[string, FileType][]>;18createDirectory(uri: Uri): Promise<void>;1920/**21* @param uri22* @param disableLimit Disable the {@link FS_READ_MAX_FILE_SIZE} limit and potentially crash the EH. USE THIS WITH CAUTION!23*/24readFile(uri: Uri, disableLimit?: boolean): Promise<Uint8Array>;25writeFile(uri: Uri, content: Uint8Array): Promise<void>;26delete(uri: Uri, options?: { recursive?: boolean; useTrash?: boolean }): Promise<void>;27rename(oldURI: Uri, newURI: Uri, options?: { overwrite?: boolean }): Promise<void>;28copy(source: Uri, destination: Uri, options?: { overwrite?: boolean }): Promise<void>;29isWritableFileSystem(scheme: string): boolean | undefined;3031createFileSystemWatcher(glob: string | RelativePattern): FileSystemWatcher;32}3334/**35* This is here to allow us to reuse the same readFile/JSON.parse across multiple invocations during simulations.36* This is disabled in production.37*/38export const fileSystemServiceReadAsJSON = new class {39private _cache: LRUCache<any> | null = null;4041enable(): void {42this._cache = new LRUCache<any>(10);43}4445public async readJSON<T>(fileSystemService: IFileSystemService, uri: Uri): Promise<T> {46if (!this._cache) {47return this._readJSON<T>(fileSystemService, uri);48}49const cachedValue = this._cache.get(uri.toString());50if (cachedValue !== undefined) {51return cachedValue;52}53const value = await this._readJSON<T>(fileSystemService, uri);54this._cache.put(uri.toString(), value);55return value;56}5758private async _readJSON<T>(fileSystemService: IFileSystemService, uri: Uri): Promise<T> {59const buffer = await fileSystemService.readFile(uri, true);60return JSON.parse(buffer.toString()) as T;61}62}();636465export const FS_READ_MAX_FILE_SIZE = 1024 * 1024 * 5; // 5 MB6667export async function assertReadFileSizeLimit(fileSystemService: IFileSystemService, uri: Uri, onlyWarn?: boolean) {68const stat = await fileSystemService.stat(uri);69if (stat.size > FS_READ_MAX_FILE_SIZE) {70if (!onlyWarn) {71const message = `[FileSystemService] ${uri.toString()} EXCEEDS max file size. FAILED to read ${Math.round(stat.size / (1024 * 1024))}MB > ${Math.round(FS_READ_MAX_FILE_SIZE / (1024 * 1024))}MB`;72throw new Error(message);73} else {74const message = `[FileSystemService] ${uri.toString()} is a LARGE file (${Math.round(stat.size / (1024 * 1024))}MB > ${Math.round(FS_READ_MAX_FILE_SIZE / (1024 * 1024))}MB)`;75console.warn(message);76}77}78}7980export async function createDirectoryIfNotExists(fileSystemService: IFileSystemService, uri: Uri): Promise<void> {81try {82const exists = await fileSystemService.stat(uri).then(() => true).catch(() => false);83if (exists) {84return;85}86await fileSystemService.createDirectory(uri);87} catch (err) {88// Possibly created by another asyn operation. Check again.89const exists = await fileSystemService.stat(uri).then(() => true).catch(() => false);90if (exists) {91return;92}93throw err;94}95}969798