From a12aa8a04f12bd6b3df65f5dbd1d02f88171ad54 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 25 Aug 2020 09:42:30 -0400 Subject: [PATCH] add cluster icon migration code (#673) Signed-off-by: Sebastian Malton --- package.json | 2 + src/common/cluster-store.ts | 8 +- src/common/cluster-store_test.ts | 27 +++++-- src/migrations/cluster-store/2.7.0-beta.0.ts | 2 +- src/migrations/cluster-store/3.6.0-beta.1.ts | 71 +++++++++++++----- .../components/cluster-icon-setting.tsx | 2 +- test-data/cluster-store-migration-icon.png | Bin 0 -> 29988 bytes yarn.lock | 65 +++++++++++++++- 8 files changed, 143 insertions(+), 34 deletions(-) create mode 100644 test-data/cluster-store-migration-icon.png diff --git a/package.json b/package.json index 72e1405b4d..54e4038c77 100644 --- a/package.json +++ b/package.json @@ -175,6 +175,7 @@ "crypto-js": "^4.0.0", "electron-updater": "^4.3.1", "electron-window-state": "^5.0.3", + "file-type": "^14.7.1", "filenamify": "^4.1.0", "fs-extra": "^9.0.1", "handlebars": "^4.7.6", @@ -184,6 +185,7 @@ "jsonpath": "^1.0.2", "lodash": "^4.17.15", "mac-ca": "^1.0.4", + "make-synchronous": "^0.1.1", "marked": "^1.1.0", "md5-file": "^5.0.0", "mobx": "^5.15.5", diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index ad25f43f26..6e9930f5ad 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -1,6 +1,5 @@ import type { WorkspaceId } from "./workspace-store"; -import path from "path"; -import { app, ipcRenderer, remote } from "electron"; +import { ipcRenderer } from "electron"; import { unlink } from "fs-extra"; import { action, computed, observable, toJS } from "mobx"; import { BaseStore } from "./base-store"; @@ -50,11 +49,6 @@ export interface ClusterPreferences { } export class ClusterStore extends BaseStore { - static get iconsDir() { - // TODO: remove remote cheat - return path.join((app || remote.app).getPath("userData"), "icons"); - } - private constructor() { super({ configName: "lens-cluster-store", diff --git a/src/common/cluster-store_test.ts b/src/common/cluster-store_test.ts index 3fc3e0b60e..6e5b99dbaf 100644 --- a/src/common/cluster-store_test.ts +++ b/src/common/cluster-store_test.ts @@ -6,6 +6,10 @@ import { ClusterStore } from "./cluster-store"; import { workspaceStore } from "./workspace-store"; import { saveConfigToAppFiles } from "./kube-helpers"; +const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png") + +console.log("") // fix bug + let clusterStore: ClusterStore; describe("empty config", () => { @@ -236,12 +240,13 @@ describe("pre 2.6.0 config with a cluster icon", () => { }, cluster1: { kubeConfig: "foo", - icon: "icon path", + icon: "icon_path", preferences: { terminalCWD: "/tmp" } }, - }) + }), + "icon_path": testDataIcon, } } mockFs(mockOpts); @@ -257,7 +262,7 @@ describe("pre 2.6.0 config with a cluster icon", () => { const storedClusterData = clusterStore.clustersList[0]; expect(storedClusterData.hasOwnProperty('icon')).toBe(false); expect(storedClusterData.preferences.hasOwnProperty('icon')).toBe(true); - expect(storedClusterData.preferences.icon).toBe("icon path"); + expect(storedClusterData.preferences.icon.startsWith("data:image/jpeg;base64,")).toBe(true); }) }) @@ -274,7 +279,6 @@ describe("for a pre 2.7.0-beta.0 config without a workspace", () => { }, cluster1: { kubeConfig: "foo", - icon: "icon path", preferences: { terminalCWD: "/tmp" } @@ -305,16 +309,20 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { 'lens-cluster-store.json': JSON.stringify({ __internal__: { migrations: { - version: "2.7.0" + version: "3.5.0" } }, clusters: [ { id: 'cluster1', - kubeConfig: 'kubeconfig content' + kubeConfig: 'kubeconfig content', + preferences: { + icon: "store://icon_path", + } } ] - }) + }), + "icon_path": testDataIcon, } }; mockFs(mockOpts); @@ -330,4 +338,9 @@ describe("pre 3.6.0-beta.1 config with an existing cluster", () => { const config = clusterStore.clustersList[0].kubeConfigPath; expect(fs.readFileSync(config, "utf8")).toBe("kubeconfig content"); }) + + it("migrates to modern format with icon not in file", async () => { + const { icon } = clusterStore.clustersList[0].preferences; + expect(icon.startsWith("data:image/jpeg;base64, ")).toBe(true); + }) }) \ No newline at end of file diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 22c4e6bba9..3e0ae9337f 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -6,7 +6,7 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if(clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue const cluster = value[1]; cluster.workspace = "default" store.set(clusterKey, cluster) diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index adc354d9ef..db39cb741d 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,34 +1,71 @@ // 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 path from "path" import { app, remote } from "electron" import { migration } from "../migration-wrapper"; -import { ensureDirSync } from "fs-extra" +import fse from "fs-extra" import { ClusterModel } from "../../common/cluster-store"; import { loadConfig, saveConfigToAppFiles } from "../../common/kube-helpers"; +import makeSynchronous from "make-synchronous" + +const AsyncFunction = Object.getPrototypeOf(async function () { return }).constructor; +const getFileTypeFnString = `return require("file-type").fromBuffer(fileData)`; +const getFileType = new AsyncFunction("fileData", getFileTypeFnString); export default migration({ version: "3.6.0-beta.1", run(store, printLog) { - const migratedClusters: ClusterModel[] = [] - const storedClusters: ClusterModel[] = store.get("clusters"); - const kubeConfigBase = path.join((app || remote.app).getPath("userData"), "kubeconfigs") + const userDataPath = (app || remote.app).getPath("userData") + const kubeConfigBase = path.join(userDataPath, "kubeconfigs") + const storedClusters: ClusterModel[] = store.get("clusters") || []; - if (!storedClusters) return; - ensureDirSync(kubeConfigBase); + if (!storedClusters.length) return; + fse.ensureDirSync(kubeConfigBase); printLog("Number of clusters to migrate: ", storedClusters.length) - for (const cluster of storedClusters) { - try { - // take the embedded kubeconfig and dump it into a file - cluster.kubeConfigPath = saveConfigToAppFiles(cluster.id, cluster.kubeConfig) - cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext(); - delete cluster.kubeConfig; - migratedClusters.push(cluster) - } catch (error) { - printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}"`, error) - } - } + const migratedClusters = storedClusters + .map(cluster => { + /** + * migrate kubeconfig + */ + try { + // take the embedded kubeconfig and dump it into a file + cluster.kubeConfigPath = saveConfigToAppFiles(cluster.id, cluster.kubeConfig) + cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext(); + delete cluster.kubeConfig; + + } catch (error) { + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error) + return undefined; + } + + /** + * migrate cluster icon + */ + try { + if (cluster.preferences?.icon) { + printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`) + const iconPath = cluster.preferences.icon.replace("store://", "") + const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); + const { mime = "" } = makeSynchronous(getFileType)(fileData); + + if (!mime) { + printLog(`mime type not detected for ${cluster.preferences.clusterName}'s icon: ${iconPath}`) + } + + cluster.preferences.icon = `data:${mime};base64, ${fileData.toString('base64')}`; + } else { + delete cluster.preferences?.icon; + } + } catch (error) { + printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error) + delete cluster.preferences.icon; + } + + return cluster; + }) + .filter(c => c); // "overwrite" the cluster configs if (migratedClusters.length > 0) { diff --git a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx index 20b4e6d6d5..04b7ef1fc6 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx @@ -28,7 +28,7 @@ export class ClusterIconSetting extends React.Component { try { if (file) { const buf = Buffer.from(await file.arrayBuffer()); - cluster.preferences.icon = `data:image/jpeg;base64, ${buf.toString('base64')}`; + cluster.preferences.icon = `data:${file.type};base64, ${buf.toString('base64')}`; } else { // this has to be done as a seperate branch (and not always) because `cluster` // is observable and triggers an update loop. diff --git a/test-data/cluster-store-migration-icon.png b/test-data/cluster-store-migration-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..623a0fea775940b03fdad9cdee23d8734251d2fa GIT binary patch literal 29988 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 literal 0 HcmV?d00001 diff --git a/yarn.lock b/yarn.lock index d00e634c95..9e75e68c2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1588,6 +1588,11 @@ dependencies: defer-to-connect "^1.0.1" +"@tokenizer/token@^0.1.0", "@tokenizer/token@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.1.1.tgz#f0d92c12f87079ddfd1b29f614758b9696bc29e3" + integrity sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w== + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -5196,6 +5201,16 @@ file-loader@^6.0.0: loader-utils "^2.0.0" schema-utils "^2.6.5" +file-type@^14.7.1: + version "14.7.1" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-14.7.1.tgz#f748732b3e70478bff530e1cf0ec2fe33608b1bb" + integrity sha512-sXAMgFk67fQLcetXustxfKX+PZgHIUFn96Xld9uH8aXPdX3xOp0/jg9OdouVTvQrf7mrn+wAa4jN/y9fUOOiRA== + dependencies: + readable-web-to-node-stream "^2.0.0" + strtok3 "^6.0.3" + token-types "^2.0.0" + typedarray-to-buffer "^3.1.5" + file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -6074,7 +6089,7 @@ identity-obj-proxy@^3.0.0: dependencies: harmony-reflect "^1.4.6" -ieee754@^1.1.4: +ieee754@^1.1.13, ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== @@ -7632,6 +7647,14 @@ make-plural@^6.2.1: resolved "https://registry.yarnpkg.com/make-plural/-/make-plural-6.2.1.tgz#2790af1d05fb2fc35a111ce759ffdb0aca1339a3" integrity sha512-AmkruwJ9EjvyTv6AM8MBMK3TAeOJvhgTv5YQXzF0EP2qawhpvMjDpHvsdOIIT0Vn+BB0+IogmYZ1z+Ulm/m0Fg== +make-synchronous@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/make-synchronous/-/make-synchronous-0.1.1.tgz#0169f6ec769c3cf8948d66790da262740c1209e7" + integrity sha512-Y4SxxqhaoyMDokJQ0AZz0E+bLhRkOSR7Z/IQoTKPdS6HYi3aobal2kMHoHHoqBadPWjf07P4K1FQLXOx3wf9Yw== + dependencies: + subsume "^3.0.0" + type-fest "^0.16.0" + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -8943,6 +8966,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +peek-readable@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-3.1.0.tgz#250b08b7de09db8573d7fd8ea475215bbff14348" + integrity sha512-KGuODSTV6hcgdZvDrIDBUkN0utcAVj1LL7FfGbM0viKTtCHmtZcuEJ+lGqsp0fTFkGqesdtemV2yUSMeyy3ddA== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -9536,6 +9564,11 @@ readable-stream@^3.1.1, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-web-to-node-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-2.0.0.tgz#751e632f466552ac0d5c440cc01470352f93c4b7" + integrity sha512-+oZJurc4hXpaaqsN68GoZGQAQIA3qr09Or4fqEsargABnbe5Aau8hFn6ISVleT3cpY/0n/8drn7huyyEvTbghA== + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -10655,6 +10688,15 @@ strip-outer@^1.0.1: dependencies: escape-string-regexp "^1.0.2" +strtok3@^6.0.3: + version "6.0.4" + resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-6.0.4.tgz#ede0d20fde5aa9fda56417c3558eaafccc724694" + integrity sha512-rqWMKwsbN9APU47bQTMEYTPcwdpKDtmf1jVhHzNW2cL1WqAxaM9iBb9t5P2fj+RV2YsErUWgQzHD5JwV0uCTEQ== + dependencies: + "@tokenizer/token" "^0.1.1" + "@types/debug" "^4.1.5" + peek-readable "^3.1.0" + style-loader@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.2.1.tgz#c5cbbfbf1170d076cfdd86e0109c5bba114baa1a" @@ -10663,6 +10705,14 @@ style-loader@^1.2.1: loader-utils "^2.0.0" schema-utils "^2.6.6" +subsume@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/subsume/-/subsume-3.0.0.tgz#22c92730f441ad72ee9af4bdad42dc4ff830cfaf" + integrity sha512-6n/UfV8UWKwJNO8OAOiKntwEMihuBeeoJfzpL542C+OuvT4iWG9SwjrXkOmsxjb4SteHUsos9SvrdqZ9+ICwTQ== + dependencies: + escape-string-regexp "^2.0.0" + unique-string "^2.0.0" + sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -10984,6 +11034,14 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +token-types@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/token-types/-/token-types-2.0.0.tgz#b23618af744818299c6fbf125e0fdad98bab7e85" + integrity sha512-WWvu8sGK8/ZmGusekZJJ5NM6rRVTTDO7/bahz4NGiSDb/XsmdYBn6a1N/bymUHuWYTWeuLUg98wUzvE4jPdCZw== + dependencies: + "@tokenizer/token" "^0.1.0" + ieee754 "^1.1.13" + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" @@ -11157,6 +11215,11 @@ type-fest@^0.13.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== +type-fest@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" + integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"