From 65afe3c64a3a3b30e770838986d24588ebe14101 Mon Sep 17 00:00:00 2001 From: Juho Heikka Date: Fri, 17 Feb 2023 16:40:33 +0200 Subject: [PATCH] Fix ensure hashed directory for extension Earlier open lens versions stored extension_data directory based on path of extension's package.json. This causes problems because extensions have moved to new location. This ensures backward compatibility that extension will get the same directory than before the change. Signed-off-by: Juho Heikka --- .../utils/find-key-contains.injectable.ts | 27 ++++++++ .../common/utils/find-key-contains.test.ts | 50 ++++++++++++++ ...shed-directory-for-extension.injectable.ts | 8 +++ ...ure-hashed-directory-for-extension.test.ts | 67 +++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 packages/core/src/common/utils/find-key-contains.injectable.ts create mode 100644 packages/core/src/common/utils/find-key-contains.test.ts create mode 100644 packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.test.ts diff --git a/packages/core/src/common/utils/find-key-contains.injectable.ts b/packages/core/src/common/utils/find-key-contains.injectable.ts new file mode 100644 index 0000000000..3a38c663b7 --- /dev/null +++ b/packages/core/src/common/utils/find-key-contains.injectable.ts @@ -0,0 +1,27 @@ +/** + * 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"; + +export type FindKeyContains = (map: Map, text: string) => T | undefined; + +const findKeyContainsInjectable = getInjectable({ + id: "find-key-contains", + + instantiate: (): FindKeyContains => { + return (map: Map, text: string) => { + const entries = map.entries(); + + for (const [key, value] of entries) { + if (key.includes(text)) { + return value; + } + } + + return undefined; + }; + }, +}); + +export default findKeyContainsInjectable; diff --git a/packages/core/src/common/utils/find-key-contains.test.ts b/packages/core/src/common/utils/find-key-contains.test.ts new file mode 100644 index 0000000000..088c8511b1 --- /dev/null +++ b/packages/core/src/common/utils/find-key-contains.test.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting"; +import type { FindKeyContains } from "./find-key-contains.injectable"; +import findKeyContainsInjectable from "./find-key-contains.injectable"; + +describe("find-key-contains", () => { + let map: Map; + + let findKeyContains: FindKeyContains; + + beforeEach(() => { + const di = getDiForUnitTesting({ doGeneralOverrides: true }); + + findKeyContains = di.inject(findKeyContainsInjectable); + }); + + describe("map with entries", () => { + beforeEach(() => { + map = new Map(); + map.set("some-key", "some-value"); + }); + + it("given key starts with key, returns value", () => { + expect(findKeyContains(map, "some")).toEqual("some-value"); + }); + + it("given key ends with key, returns value", () => { + expect(findKeyContains(map, "key")).toEqual("some-value"); + }); + + it("given key is in middle of key, returns value", () => { + map.set("some-long-key", "some-value-for-long-key"); + + expect(findKeyContains(map, "long")).toEqual("some-value-for-long-key"); + }); + + it("given key does not include text, returns undefined", () => { + expect(findKeyContains(map, "not")).toEqual(undefined); + }); + }); + + describe("map with no entries", () => { + it("it returns undefined", () => { + expect(findKeyContains(map, "some-text")).toEqual(undefined); + }); + }); +}); diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable.ts index 6b696f663d..31f8a8147d 100644 --- a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable.ts +++ b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable.ts @@ -12,6 +12,7 @@ import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable"; import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable"; import getHashInjectable from "./get-hash.injectable"; +import findKeyContainsInjectable from "../../../common/utils/find-key-contains.injectable"; export type EnsureHashedDirectoryForExtension = (extensionName: string, registeredExtensions: ObservableMap) => Promise; @@ -24,8 +25,15 @@ const ensureHashedDirectoryForExtensionInjectable = getInjectable({ const directoryForExtensionData = di.inject(directoryForExtensionDataInjectable); const ensureDirectory = di.inject(ensureDirInjectable); const getHash = di.inject(getHashInjectable); + const findKeyContains = di.inject(findKeyContainsInjectable); return async (extensionName, registeredExtensions) => { + const legacyDirPath = findKeyContains(registeredExtensions, extensionName); + + if (legacyDirPath) { + return legacyDirPath; + } + const dirPath = await getOrInsertWithAsync(registeredExtensions, extensionName, async () => { const salt = (await randomBytes(32)).toString("hex"); const hashedName = getHash(`${extensionName}/${salt}`); diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.test.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.test.ts new file mode 100644 index 0000000000..4c09565732 --- /dev/null +++ b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.test.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { ObservableMap } from "mobx"; +import { observable, runInAction } from "mobx"; +import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting"; +import type { EnsureHashedDirectoryForExtension } from "./ensure-hashed-directory-for-extension.injectable"; +import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable"; +import ensureDirInjectable from "../../../common/fs/ensure-dir.injectable"; +import directoryForExtensionDataInjectable from "./directory-for-extension-data.injectable"; + +describe("ensure-hashed-directory-for-extension", () => { + let ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension; + let ensureDirMock: jest.Mock; + let registeredExtensions: ObservableMap; + + beforeEach(() => { + const di = getDiForUnitTesting({ doGeneralOverrides: true }); + + ensureDirMock = jest.fn(); + + di.override(ensureDirInjectable, () => ensureDirMock); + di.override(directoryForExtensionDataInjectable, () => "some-directory-for-extension-data"); + + ensureHashedDirectoryForExtension = di.inject( + ensureHashedDirectoryForExtensionInjectable, + ); + + registeredExtensions = observable.map(); + }); + + it("given registered extension exists, returns existing directory", async () => { + runInAction(() => { + registeredExtensions.set("some-extension-name", "some-directory"); + }); + + const actual = await ensureHashedDirectoryForExtension( + "some-extension-name", + registeredExtensions, + ); + + expect(actual).toBe("some-directory"); + }); + + it("given registered extension does not exist, returns random directory", async () => { + const actual = await ensureHashedDirectoryForExtension( + "some-extension-name", + registeredExtensions, + ); + + expect(actual).not.toBe("some-directory"); + }); + + it("given extension directory was saved based on extension's package.json path, returns existing directory", async () => { + runInAction(() => { + registeredExtensions.set("/Users/some-user/Library/Application Support/Lens/node_modules/some-extension-name/package.json", "some-directory"); + }); + const actual = await ensureHashedDirectoryForExtension( + "some-extension-name", + registeredExtensions, + ); + + expect(actual).toBe("some-directory"); + }); + +});