diff --git a/src/common/fs/delete-file.global-override-for-injectable.ts b/src/common/fs/delete-file.global-override-for-injectable.ts deleted file mode 100644 index c03dca88dc..0000000000 --- a/src/common/fs/delete-file.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "../test-utils/get-global-override"; -import deleteFileInjectable from "./delete-file.injectable"; - -export default getGlobalOverride(deleteFileInjectable, () => async () => { - throw new Error("tried to delete file without override"); -}); diff --git a/src/common/fs/fs.injectable.ts b/src/common/fs/fs.injectable.ts index ab385e5871..668294a510 100644 --- a/src/common/fs/fs.injectable.ts +++ b/src/common/fs/fs.injectable.ts @@ -3,11 +3,49 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import type { ReadOptions } from "fs-extra"; import fse from "fs-extra"; +/** + * NOTE: Add corrisponding a corrisponding override of this injecable in `src/test-utils/override-fs-with-fakes.ts` + */ const fsInjectable = getInjectable({ id: "fs", - instantiate: () => fse, + instantiate: () => { + const { + promises: { + readFile, + writeFile, + readdir, + lstat, + rm, + }, + readFileSync, + readJson, + writeJson, + readJsonSync, + writeFileSync, + writeJsonSync, + pathExistsSync, + pathExists, + } = fse; + + return { + readFile, + readJson: readJson as (file: string, options?: ReadOptions | BufferEncoding) => Promise, + writeFile, + writeJson, + pathExists, + readdir, + readFileSync, + readJsonSync, + writeFileSync, + writeJsonSync, + pathExistsSync, + lstat, + rm, + }; + }, causesSideEffects: true, }); diff --git a/src/common/fs/delete-file.injectable.ts b/src/common/fs/path-exists-sync.injectable.ts similarity index 52% rename from src/common/fs/delete-file.injectable.ts rename to src/common/fs/path-exists-sync.injectable.ts index 57aba5b379..21bcb6d7d1 100644 --- a/src/common/fs/delete-file.injectable.ts +++ b/src/common/fs/path-exists-sync.injectable.ts @@ -5,11 +5,9 @@ import { getInjectable } from "@ogre-tools/injectable"; import fsInjectable from "./fs.injectable"; -export type DeleteFile = (filePath: string) => Promise; - -const deleteFileInjectable = getInjectable({ - id: "delete-file", - instantiate: (di): DeleteFile => di.inject(fsInjectable).unlink, +const pathExistsSyncInjectable = getInjectable({ + id: "path-exists-sync", + instantiate: (di) => di.inject(fsInjectable).pathExistsSync, }); -export default deleteFileInjectable; +export default pathExistsSyncInjectable; diff --git a/src/common/fs/read-directory.injectable.ts b/src/common/fs/read-directory.injectable.ts index 57632bd4d7..8ebeebe75a 100644 --- a/src/common/fs/read-directory.injectable.ts +++ b/src/common/fs/read-directory.injectable.ts @@ -14,18 +14,16 @@ export interface ReadDirectory { ( path: string, options?: - | { encoding: BufferEncoding | string | null; withFileTypes?: false | undefined } + | { encoding: BufferEncoding; withFileTypes?: false | undefined } | BufferEncoding - | string - | null, ): Promise; ( path: string, - options?: { encoding?: BufferEncoding | string | null | undefined; withFileTypes?: false | undefined }, + options?: { encoding?: BufferEncoding; withFileTypes?: false | undefined }, ): Promise; ( path: string, - options: { encoding?: BufferEncoding | string | null | undefined; withFileTypes: true }, + options: { encoding?: BufferEncoding; withFileTypes: true }, ): Promise; } diff --git a/src/common/fs/remove-path.global-override-for-injectable.ts b/src/common/fs/remove.global-override-for-injectable.ts similarity index 70% rename from src/common/fs/remove-path.global-override-for-injectable.ts rename to src/common/fs/remove.global-override-for-injectable.ts index 5b9720a837..4b92353344 100644 --- a/src/common/fs/remove-path.global-override-for-injectable.ts +++ b/src/common/fs/remove.global-override-for-injectable.ts @@ -4,8 +4,8 @@ */ import { getGlobalOverride } from "../test-utils/get-global-override"; -import removePathInjectable from "./remove-path.injectable"; +import removePathInjectable from "./remove.injectable"; export default getGlobalOverride(removePathInjectable, () => async () => { - throw new Error("tried to remove a path without override"); + throw new Error("tried to remove path without override"); }); diff --git a/src/common/fs/remove-path.injectable.ts b/src/common/fs/remove.injectable.ts similarity index 74% rename from src/common/fs/remove-path.injectable.ts rename to src/common/fs/remove.injectable.ts index 02c8da0e1e..de69e40727 100644 --- a/src/common/fs/remove-path.injectable.ts +++ b/src/common/fs/remove.injectable.ts @@ -5,11 +5,11 @@ import { getInjectable } from "@ogre-tools/injectable"; import fsInjectable from "./fs.injectable"; -export type RemovePath = (path: string) => Promise; +export type RemovePath = (filePath: string) => Promise; const removePathInjectable = getInjectable({ id: "remove-path", - instantiate: (di): RemovePath => di.inject(fsInjectable).remove, + instantiate: (di): RemovePath => di.inject(fsInjectable).rm, }); export default removePathInjectable; diff --git a/src/common/fs/write-file-sync.injectable.ts b/src/common/fs/write-file-sync.injectable.ts new file mode 100644 index 0000000000..3daccaf610 --- /dev/null +++ b/src/common/fs/write-file-sync.injectable.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import getDirnameOfPathInjectable from "../path/get-dirname.injectable"; +import fsInjectable from "./fs.injectable"; + +export type WriteFileSync = (filePath: string, contents: string) => void; + +const writeFileSyncInjectable = getInjectable({ + id: "write-file-sync", + instantiate: (di): WriteFileSync => { + const { + writeFileSync, + ensureDirSync, + } = di.inject(fsInjectable); + const getDirnameOfPath = di.inject(getDirnameOfPathInjectable); + + return (filePath, contents) => { + ensureDirSync(getDirnameOfPath(filePath), { + mode: 0o755, + }); + writeFileSync(filePath, contents); + }; + }, +}); + +export default writeFileSyncInjectable; diff --git a/src/extensions/extension-discovery/extension-discovery.injectable.ts b/src/extensions/extension-discovery/extension-discovery.injectable.ts index 09d0f3b0ae..9a653aeac2 100644 --- a/src/extensions/extension-discovery/extension-discovery.injectable.ts +++ b/src/extensions/extension-discovery/extension-discovery.injectable.ts @@ -27,7 +27,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable"; import getRelativePathInjectable from "../../common/path/get-relative-path.injectable"; import joinPathsInjectable from "../../common/path/join-paths.injectable"; -import removePathInjectable from "../../common/fs/remove-path.injectable"; +import removePathInjectable from "../../common/fs/remove.injectable"; import homeDirectoryPathInjectable from "../../common/os/home-directory-path.injectable"; const extensionDiscoveryInjectable = getInjectable({ diff --git a/src/extensions/extension-discovery/extension-discovery.test.ts b/src/extensions/extension-discovery/extension-discovery.test.ts index f3630addaf..e7e21be0f1 100644 --- a/src/extensions/extension-discovery/extension-discovery.test.ts +++ b/src/extensions/extension-discovery/extension-discovery.test.ts @@ -15,7 +15,7 @@ import readJsonFileInjectable from "../../common/fs/read-json-file.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import watchInjectable from "../../common/fs/watch/watch.injectable"; import extensionApiVersionInjectable from "../../common/vars/extension-api-version.injectable"; -import removePathInjectable from "../../common/fs/remove-path.injectable"; +import removePathInjectable from "../../common/fs/remove.injectable"; import type { JoinPaths } from "../../common/path/join-paths.injectable"; import joinPathsInjectable from "../../common/path/join-paths.injectable"; import homeDirectoryPathInjectable from "../../common/os/home-directory-path.injectable"; diff --git a/src/extensions/extension-discovery/extension-discovery.ts b/src/extensions/extension-discovery/extension-discovery.ts index c7781d78a6..4828ae54a0 100644 --- a/src/extensions/extension-discovery/extension-discovery.ts +++ b/src/extensions/extension-discovery/extension-discovery.ts @@ -30,7 +30,7 @@ import type { JoinPaths } from "../../common/path/join-paths.injectable"; import type { GetBasenameOfPath } from "../../common/path/get-basename.injectable"; import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"; import type { GetRelativePath } from "../../common/path/get-relative-path.injectable"; -import type { RemovePath } from "../../common/fs/remove-path.injectable"; +import type { RemovePath } from "../../common/fs/remove.injectable"; import type TypedEventEmitter from "typed-emitter"; interface Dependencies { diff --git a/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts b/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts index a2ede65ec0..b2ac54d5e4 100644 --- a/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts +++ b/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts @@ -6,7 +6,7 @@ import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event. import clusterFramesInjectable from "../../../../common/cluster-frames.injectable"; import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import directoryForLensLocalStorageInjectable from "../../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable"; -import deleteFileInjectable from "../../../../common/fs/delete-file.injectable"; +import removePathInjectable from "../../../../common/fs/remove.injectable"; import joinPathsInjectable from "../../../../common/path/join-paths.injectable"; import { noop } from "../../../../common/utils"; import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; @@ -20,7 +20,7 @@ const deleteClusterChannelListenerInjectable = getRequestChannelListenerInjectab const clusterFrames = di.inject(clusterFramesInjectable); const joinPaths = di.inject(joinPathsInjectable); const directoryForLensLocalStorage = di.inject(directoryForLensLocalStorageInjectable); - const deleteFile = di.inject(deleteFileInjectable); + const deleteFile = di.inject(removePathInjectable); return async (clusterId) => { emitAppEvent({ name: "cluster", action: "remove" }); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index 6a33093cb4..aa0e87cfac 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -25,8 +25,8 @@ import type { WriteFile } from "../../common/fs/write-file.injectable"; import writeFileInjectable from "../../common/fs/write-file.injectable"; import type { PathExists } from "../../common/fs/path-exists.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable"; -import type { DeleteFile } from "../../common/fs/delete-file.injectable"; -import deleteFileInjectable from "../../common/fs/delete-file.injectable"; +import type { RemovePath } from "../../common/fs/remove.injectable"; +import removePathInjectable from "../../common/fs/remove.injectable"; const clusterServerUrl = "https://192.168.64.3:8443"; @@ -36,7 +36,7 @@ describe("kubeconfig manager tests", () => { let di: DiContainer; let loggerMock: jest.Mocked; let readFileMock: AsyncFnMock; - let deleteFileMock: AsyncFnMock; + let deleteFileMock: AsyncFnMock; let writeFileMock: AsyncFnMock; let pathExistsMock: AsyncFnMock; let kubeConfManager: KubeconfigManager; @@ -58,7 +58,7 @@ describe("kubeconfig manager tests", () => { pathExistsMock = asyncFn(); di.override(pathExistsInjectable, () => pathExistsMock); deleteFileMock = asyncFn(); - di.override(deleteFileInjectable, () => deleteFileMock); + di.override(removePathInjectable, () => deleteFileMock); loggerMock = { warn: jest.fn(), diff --git a/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts b/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts index 41eb645d11..410bb23457 100644 --- a/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts +++ b/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts @@ -6,7 +6,6 @@ // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions -import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import getCustomKubeConfigDirectoryInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable"; import type { ClusterModel } from "../../../common/cluster-types"; @@ -20,24 +19,20 @@ interface Pre360ClusterModel extends ClusterModel { import { getInjectable } from "@ogre-tools/injectable"; import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; -import fsInjectable from "../../../common/fs/fs.injectable"; import readFileBufferSyncInjectable from "../../../common/fs/read-file-buffer-sync.injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable"; const v360Beta1ClusterStoreMigrationInjectable = getInjectable({ id: "v3.6.0-beta.1-cluster-store-migration", instantiate: (di) => { const userDataPath = di.inject(directoryForUserDataInjectable); - const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable); const getCustomKubeConfigDirectory = di.inject(getCustomKubeConfigDirectoryInjectable); const readFileSync = di.inject(readFileSyncInjectable); const readFileBufferSync = di.inject(readFileBufferSyncInjectable); const joinPaths = di.inject(joinPathsInjectable); const logger = di.inject(loggerInjectable); - const { - ensureDirSync, - writeFileSync, - } = di.inject(fsInjectable); + const writeFileSync = di.inject(writeFileSyncInjectable); return { version: "3.6.0-beta.1", @@ -45,8 +40,6 @@ const v360Beta1ClusterStoreMigrationInjectable = getInjectable({ const storedClusters = (store.get("clusters") ?? []) as Pre360ClusterModel[]; const migratedClusters: ClusterModel[] = []; - ensureDirSync(kubeConfigsPath); - logger.info("Number of clusters to migrate: ", storedClusters.length); for (const clusterModel of storedClusters) { @@ -61,7 +54,7 @@ const v360Beta1ClusterStoreMigrationInjectable = getInjectable({ } // take the embedded kubeconfig and dump it into a file - writeFileSync(absPath, clusterModel.kubeConfig, { encoding: "utf-8", mode: 0o600 }); + writeFileSync(absPath, clusterModel.kubeConfig); clusterModel.kubeConfigPath = absPath; clusterModel.contextName = loadConfigFromString(readFileSync(absPath)).config.getCurrentContext(); diff --git a/src/main/cluster/store-migrations/snap.injectable.ts b/src/main/cluster/store-migrations/snap.injectable.ts index d9a7bcd7a2..b99de8a49f 100644 --- a/src/main/cluster/store-migrations/snap.injectable.ts +++ b/src/main/cluster/store-migrations/snap.injectable.ts @@ -10,8 +10,8 @@ import applicationInformationInjectable from "../../../common/vars/application-i import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; import loggerInjectable from "../../../common/logger.injectable"; import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable"; -import fsInjectable from "../../../common/fs/fs.injectable"; import type { ClusterModel } from "../../../common/cluster-types"; +import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable"; const clusterStoreSnapMigrationInjectable = getInjectable({ id: "cluster-store-snap-migration", @@ -19,7 +19,7 @@ const clusterStoreSnapMigrationInjectable = getInjectable({ const { version } = di.inject(applicationInformationInjectable); const logger = di.inject(loggerInjectable); const isSnapPackage = di.inject(isSnapPackageInjectable); - const { existsSync } = di.inject(fsInjectable); + const pathExistsSync = di.inject(pathExistsSyncInjectable); return { version, // Run always after upgrade @@ -39,7 +39,7 @@ const clusterStoreSnapMigrationInjectable = getInjectable({ /** * replace snap version with 'current' in kubeconfig path */ - if (!existsSync(cluster.kubeConfigPath)) { + if (!pathExistsSync(cluster.kubeConfigPath)) { const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/"); cluster.kubeConfigPath = kubeconfigPath; diff --git a/src/main/helm/helm-service/update-helm-release.injectable.ts b/src/main/helm/helm-service/update-helm-release.injectable.ts index f428e7a782..274dae8cc4 100644 --- a/src/main/helm/helm-service/update-helm-release.injectable.ts +++ b/src/main/helm/helm-service/update-helm-release.injectable.ts @@ -8,7 +8,7 @@ import loggerInjectable from "../../../common/logger.injectable"; import tempy from "tempy"; import getHelmReleaseInjectable from "./get-helm-release.injectable"; import writeFileInjectable from "../../../common/fs/write-file.injectable"; -import removePathInjectable from "../../../common/fs/remove-path.injectable"; +import removePathInjectable from "../../../common/fs/remove.injectable"; import execHelmInjectable from "../exec-helm/exec-helm.injectable"; export interface UpdateChartArgs { diff --git a/src/main/kubeconfig-manager/create-kubeconfig-manager.injectable.ts b/src/main/kubeconfig-manager/create-kubeconfig-manager.injectable.ts index ed75943398..6bca7cb086 100644 --- a/src/main/kubeconfig-manager/create-kubeconfig-manager.injectable.ts +++ b/src/main/kubeconfig-manager/create-kubeconfig-manager.injectable.ts @@ -11,9 +11,9 @@ import loggerInjectable from "../../common/logger.injectable"; import lensProxyPortInjectable from "../lens-proxy/lens-proxy-port.injectable"; import joinPathsInjectable from "../../common/path/join-paths.injectable"; import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable"; -import deleteFileInjectable from "../../common/fs/delete-file.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import writeFileInjectable from "../../common/fs/write-file.injectable"; +import removePathInjectable from "../../common/fs/remove.injectable"; export interface KubeConfigManagerInstantiationParameter { cluster: Cluster; @@ -31,7 +31,7 @@ const createKubeconfigManagerInjectable = getInjectable({ lensProxyPort: di.inject(lensProxyPortInjectable), joinPaths: di.inject(joinPathsInjectable), getDirnameOfPath: di.inject(getDirnameOfPathInjectable), - deleteFile: di.inject(deleteFileInjectable), + removePath: di.inject(removePathInjectable), pathExists: di.inject(pathExistsInjectable), writeFile: di.inject(writeFileInjectable), }; diff --git a/src/main/kubeconfig-manager/kubeconfig-manager.ts b/src/main/kubeconfig-manager/kubeconfig-manager.ts index a51599169e..f73baf1782 100644 --- a/src/main/kubeconfig-manager/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager/kubeconfig-manager.ts @@ -13,7 +13,7 @@ import type { Logger } from "../../common/logger"; import type { JoinPaths } from "../../common/path/join-paths.injectable"; import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"; import type { PathExists } from "../../common/fs/path-exists.injectable"; -import type { DeleteFile } from "../../common/fs/delete-file.injectable"; +import type { RemovePath } from "../../common/fs/remove.injectable"; import type { WriteFile } from "../../common/fs/write-file.injectable"; export interface KubeconfigManagerDependencies { @@ -23,7 +23,7 @@ export interface KubeconfigManagerDependencies { joinPaths: JoinPaths; getDirnameOfPath: GetDirnameOfPath; pathExists: PathExists; - deleteFile: DeleteFile; + removePath: RemovePath; writeFile: WriteFile; } @@ -65,7 +65,7 @@ export class KubeconfigManager { this.dependencies.logger.info(`[KUBECONFIG-MANAGER]: Deleting temporary kubeconfig: ${this.tempFilePath}`); try { - await this.dependencies.deleteFile(this.tempFilePath); + await this.dependencies.removePath(this.tempFilePath); } catch (error) { if (isErrnoException(error) && error.code !== "ENOENT") { throw error; diff --git a/src/main/resource-applier/create-resource-applier.injectable.ts b/src/main/resource-applier/create-resource-applier.injectable.ts index 04e69d29d4..509dce086c 100644 --- a/src/main/resource-applier/create-resource-applier.injectable.ts +++ b/src/main/resource-applier/create-resource-applier.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable"; import type { Cluster } from "../../common/cluster/cluster"; -import deleteFileInjectable from "../../common/fs/delete-file.injectable"; +import removePathInjectable from "../../common/fs/remove.injectable"; import execFileInjectable from "../../common/fs/exec-file.injectable"; import writeFileInjectable from "../../common/fs/write-file.injectable"; import loggerInjectable from "../../common/logger.injectable"; @@ -19,7 +19,7 @@ const createResourceApplierInjectable = getInjectable({ id: "create-resource-applier", instantiate: (di): CreateResourceApplier => { const deps: ResourceApplierDependencies = { - deleteFile: di.inject(deleteFileInjectable), + deleteFile: di.inject(removePathInjectable), emitAppEvent: di.inject(emitAppEventInjectable), execFile: di.inject(execFileInjectable), joinPaths: di.inject(joinPathsInjectable), diff --git a/src/main/resource-applier/resource-applier.ts b/src/main/resource-applier/resource-applier.ts index 3384b1cbf2..a604781fce 100644 --- a/src/main/resource-applier/resource-applier.ts +++ b/src/main/resource-applier/resource-applier.ts @@ -11,7 +11,7 @@ import type { KubernetesObject } from "@kubernetes/client-node"; import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable"; import type { Logger } from "../../common/logger"; import type { WriteFile } from "../../common/fs/write-file.injectable"; -import type { DeleteFile } from "../../common/fs/delete-file.injectable"; +import type { RemovePath } from "../../common/fs/remove.injectable"; import type { ExecFile } from "../../common/fs/exec-file.injectable"; import type { JoinPaths } from "../../common/path/join-paths.injectable"; import type { AsyncResult } from "../../common/utils/async-result"; @@ -19,7 +19,7 @@ import type { AsyncResult } from "../../common/utils/async-result"; export interface ResourceApplierDependencies { emitAppEvent: EmitAppEvent; writeFile: WriteFile; - deleteFile: DeleteFile; + deleteFile: RemovePath; execFile: ExecFile; joinPaths: JoinPaths; readonly logger: Logger; diff --git a/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts b/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts index f02971d815..1367037c6d 100644 --- a/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts +++ b/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts @@ -15,8 +15,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token"; import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable"; -import fsInjectable from "../../../common/fs/fs.injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable"; const v503Beta1UserStoreMigrationInjectable = getInjectable({ id: "v5.0.3-beta.1-user-store-migration", @@ -29,7 +29,7 @@ const v503Beta1UserStoreMigrationInjectable = getInjectable({ const getDirnameOfPath = di.inject(getDirnameOfPathInjectable); const readJsonSync = di.inject(readJsonSyncInjectable); const homeDirectoryPath = di.inject(homeDirectoryPathInjectable); - const { existsSync } = di.inject(fsInjectable); + const pathExistsSync = di.inject(pathExistsSyncInjectable); return { version: "5.0.3-beta.1", @@ -63,7 +63,7 @@ const v503Beta1UserStoreMigrationInjectable = getInjectable({ continue; } - if (!existsSync(cluster.kubeConfigPath)) { + if (!pathExistsSync(cluster.kubeConfigPath)) { logger.info(`Skipping ${cluster.id} because kubeConfigPath no longer exists`); continue; } diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index 27db8da81a..eda87edddb 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -23,8 +23,8 @@ import installExtensionFromInputInjectable from "../install-extension-from-input import type { ExtensionInstallationStateStore } from "../../../../extensions/extension-installation-state-store/extension-installation-state-store"; import extensionInstallationStateStoreInjectable from "../../../../extensions/extension-installation-state-store/extension-installation-state-store.injectable"; import { observable, when } from "mobx"; -import type { DeleteFile } from "../../../../common/fs/delete-file.injectable"; -import deleteFileInjectable from "../../../../common/fs/delete-file.injectable"; +import type { RemovePath } from "../../../../common/fs/remove.injectable"; +import removePathInjectable from "../../../../common/fs/remove.injectable"; import type { DownloadJson } from "../../../../common/fetch/download-json.injectable"; import type { DownloadBinary } from "../../../../common/fetch/download-binary.injectable"; import downloadJsonInjectable from "../../../../common/fetch/download-json.injectable"; @@ -36,7 +36,7 @@ describe("Extensions", () => { let installExtensionFromInput: jest.MockedFunction; let extensionInstallationStateStore: ExtensionInstallationStateStore; let render: DiRender; - let deleteFileMock: jest.MockedFunction; + let deleteFileMock: jest.MockedFunction; let downloadJson: jest.MockedFunction; let downloadBinary: jest.MockedFunction; @@ -52,7 +52,7 @@ describe("Extensions", () => { di.override(installExtensionFromInputInjectable, () => installExtensionFromInput); deleteFileMock = jest.fn(); - di.override(deleteFileInjectable, () => deleteFileMock); + di.override(removePathInjectable, () => deleteFileMock); downloadJson = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); }); di.override(downloadJsonInjectable, () => downloadJson); diff --git a/src/renderer/components/test-utils/get-application-builder.tsx b/src/renderer/components/test-utils/get-application-builder.tsx index ee26baa163..f4c98e07ad 100644 --- a/src/renderer/components/test-utils/get-application-builder.tsx +++ b/src/renderer/components/test-utils/get-application-builder.tsx @@ -63,7 +63,7 @@ import type { FakeExtensionOptions } from "./get-extension-fake"; import { getExtensionFakeForMain, getExtensionFakeForRenderer } from "./get-extension-fake"; import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable"; import { Namespace } from "../../../common/k8s-api/endpoints"; -import { overrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes"; +import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes"; import applicationMenuItemCompositeInjectable from "../../../features/application-menu/main/application-menu-item-composite.injectable"; import { getCompositePaths } from "../../../common/utils/composite/get-composite-paths/get-composite-paths"; import { discoverFor } from "./discovery-of-html-elements"; @@ -173,9 +173,9 @@ export const getApplicationBuilder = () => { const beforeWindowStartCallbacks: Callback[] = []; const afterWindowStartCallbacks: Callback[] = []; - const fsState = new Map(); + const overrideFsWithFakes = getOverrideFsWithFakes(); - overrideFsWithFakes(mainDi, fsState); + overrideFsWithFakes(mainDi); let environment = environments.application; @@ -210,7 +210,7 @@ export const getApplicationBuilder = () => { const windowDi = getRendererDi({ doGeneralOverrides: true }); overrideForWindow(windowDi, windowId); - overrideFsWithFakes(windowDi, fsState); + overrideFsWithFakes(windowDi); runInAction(() => { windowDi.register(rendererExtensionsStateInjectable); diff --git a/src/renderer/getDiForUnitTesting.tsx b/src/renderer/getDiForUnitTesting.tsx index 84049c8df2..342b48a79b 100644 --- a/src/renderer/getDiForUnitTesting.tsx +++ b/src/renderer/getDiForUnitTesting.tsx @@ -9,7 +9,7 @@ import { createContainer, isInjectable } from "@ogre-tools/injectable"; import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import requestFromChannelInjectable from "./utils/channel/request-from-channel.injectable"; import loggerInjectable from "../common/logger.injectable"; -import { overrideFsWithFakes } from "../test-utils/override-fs-with-fakes"; +import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes"; import { createMemoryHistory } from "history"; import focusWindowInjectable from "./navigation/focus-window.injectable"; import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable"; @@ -140,7 +140,7 @@ export const getDiForUnitTesting = ( di.override(requestFromChannelInjectable, () => () => Promise.resolve(undefined as never)); - overrideFsWithFakes(di); + getOverrideFsWithFakes()(di); di.override(focusWindowInjectable, () => () => {}); diff --git a/src/test-utils/override-fs-with-fakes.ts b/src/test-utils/override-fs-with-fakes.ts index c594e20c8b..0150071564 100644 --- a/src/test-utils/override-fs-with-fakes.ts +++ b/src/test-utils/override-fs-with-fakes.ts @@ -3,50 +3,48 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { DiContainer } from "@ogre-tools/injectable"; -import readFileInjectable from "../common/fs/read-file.injectable"; -import writeJsonFileInjectable from "../common/fs/write-json-file.injectable"; -import readJsonFileInjectable from "../common/fs/read-json-file.injectable"; -import pathExistsInjectable from "../common/fs/path-exists.injectable"; -import deleteFileInjectable from "../common/fs/delete-file.injectable"; -import writeJsonSyncInjectable from "../common/fs/write-json-sync.injectable"; -import readJsonSyncInjectable from "../common/fs/read-json-sync.injectable"; +import fsInjectable from "../common/fs/fs.injectable"; +import { createFsFromVolume, Volume } from "memfs"; +import type { readJsonSync as readJsonSyncImpl, writeJsonSync as writeJsonSyncImpl } from "fs-extra"; -export const overrideFsWithFakes = (di: DiContainer, state = new Map()) => { - const readFile = readFileFor(state); +export const getOverrideFsWithFakes = () => { + const root = createFsFromVolume(Volume.fromJSON({})); - di.override(readFileInjectable, () => async (filePath) => readFile(filePath)); - di.override(writeJsonFileInjectable, () => ( - async (filePath, contents) => { - state.set(filePath, JSON.stringify(contents)); - } - )); - di.override(readJsonFileInjectable, () => ( - async (filePath: string) => JSON.parse(readFile(filePath)) - )); - di.override(writeJsonSyncInjectable, () => ( - (filePath, data) => state.set(filePath, JSON.stringify(data)) - )); - di.override(readJsonSyncInjectable, () => ( - (filePath) => JSON.parse(readFile(filePath)) - )); - di.override(pathExistsInjectable, () => ( - async (filePath: string) => state.has(filePath) - )); - di.override(deleteFileInjectable, () => async (filePath: string) => { - state.delete(filePath); - }); -}; - -const readFileFor = (state: Map) => (filePath: string) => { - const fileContent = state.get(filePath); - - if (!fileContent) { - const existingFilePaths = [...state.keys()].join('", "'); - - throw new Error( - `Tried to access file ${filePath} which does not exist. Existing file paths are: "${existingFilePaths}"`, - ); - } - - return fileContent; + const readJsonSync = ((file, opts) => { + const options = typeof opts === "string" + ? { + encoding: opts, + } + : opts; + const value = root.readFileSync(file, options as any) as string; + + return JSON.parse(value, options?.reviver); + }) as typeof readJsonSyncImpl; + const writeJsonSync = ((file, object, opts) => { + const options = typeof opts === "string" + ? { + encoding: opts, + } + : opts; + + root.writeFileSync(file, JSON.stringify(object, options?.replacer, options?.spaces), options as any); + }) as typeof writeJsonSyncImpl; + + return (di: DiContainer) => { + di.override(fsInjectable, () => ({ + pathExists: async (path) => root.existsSync(path), + pathExistsSync: root.existsSync, + readFile: root.promises.readFile as any, + readFileSync: root.readFileSync as any, + readJson: async (file, opts) => readJsonSync(file, opts), + readJsonSync, + writeFile: root.promises.writeFile as any, + writeFileSync: root.writeFileSync as any, + writeJson: async (file, obj, opts) => writeJsonSync(file, obj, opts as any), + writeJsonSync, + readdir: root.promises.readdir as any, + lstat: root.promises.lstat as any, + rm: root.promises.rm, + })); + }; };