1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Switch UserStore to injectable migrations

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-11-30 15:49:01 -05:00
parent 1aa3e46262
commit 3958e613ec
9 changed files with 143 additions and 150 deletions

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { MigrationDeclaration } from "../base-store/migrations.injectable";
export const userStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
id: "user-store-migration-token",
});

View File

@ -10,6 +10,8 @@ import directoryForUserDataInjectable from "../app-paths/directory-for-user-data
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import loggerInjectable from "../logger.injectable"; import loggerInjectable from "../logger.injectable";
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
import storeMigrationsInjectable from "../base-store/migrations.injectable";
import { userStoreMigrationInjectionToken } from "./migrations-token";
const userStoreInjectable = getInjectable({ const userStoreInjectable = getInjectable({
id: "user-store", id: "user-store",
@ -21,6 +23,7 @@ const userStoreInjectable = getInjectable({
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
logger: di.inject(loggerInjectable), logger: di.inject(loggerInjectable),
storeMigrationVersion: di.inject(storeMigrationVersionInjectable), storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
migrations: di.inject(storeMigrationsInjectable, userStoreMigrationInjectionToken),
}), }),
}); });

View File

@ -7,7 +7,6 @@ import { app } from "electron";
import { action, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx"; import { action, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
import type { BaseStoreDependencies } from "../base-store/base-store"; import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store"; import { BaseStore } from "../base-store/base-store";
import migrations from "../../migrations/user-store";
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils"; import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
import { DESCRIPTORS } from "./preferences-helpers"; import { DESCRIPTORS } from "./preferences-helpers";
import type { UserPreferencesModel, StoreType } from "./preferences-helpers"; import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
@ -18,7 +17,6 @@ import type { SelectedUpdateChannel } from "../../features/application-update/co
import type { ReleaseChannel } from "../../features/application-update/common/update-channels"; import type { ReleaseChannel } from "../../features/application-update/common/update-channels";
export interface UserStoreModel { export interface UserStoreModel {
lastSeenAppVersion: string;
preferences: UserPreferencesModel; preferences: UserPreferencesModel;
} }
@ -33,14 +31,11 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
constructor(protected readonly dependencies: Dependencies) { constructor(protected readonly dependencies: Dependencies) {
super(dependencies, { super(dependencies, {
configName: "lens-user-store", configName: "lens-user-store",
migrations,
}); });
makeObservable(this); makeObservable(this);
} }
@observable lastSeenAppVersion = "0.0.0";
/** /**
* @deprecated No longer used * @deprecated No longer used
*/ */
@ -137,12 +132,8 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
} }
@action @action
protected fromStore({ lastSeenAppVersion, preferences }: Partial<UserStoreModel> = {}) { protected fromStore({ preferences }: Partial<UserStoreModel> = {}) {
this.dependencies.logger.debug("UserStore.fromStore()", { lastSeenAppVersion, preferences }); this.dependencies.logger.debug("UserStore.fromStore()", { preferences });
if (lastSeenAppVersion) {
this.lastSeenAppVersion = lastSeenAppVersion;
}
for (const [key, { fromStore }] of object.entries(DESCRIPTORS)) { for (const [key, { fromStore }] of object.entries(DESCRIPTORS)) {
const curVal = this[key]; const curVal = this[key];
@ -170,11 +161,8 @@ export class UserStore extends BaseStore<UserStoreModel> /* implements UserStore
) as UserPreferencesModel; ) as UserPreferencesModel;
return toJS({ return toJS({
lastSeenAppVersion: this.lastSeenAppVersion,
preferences: { preferences: {
...preferences, ...preferences,
updateChannel: this.dependencies.selectedUpdateChannel.value.get().id, updateChannel: this.dependencies.selectedUpdateChannel.value.get().id,
}, },
}); });

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Switch representation of hiddenTableColumns in store
import { getInjectable } from "@ogre-tools/injectable";
import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token";
interface PreV500Alpha3UserPreferencesModel {
hiddenTableColumns?: Record<string, string[]>;
}
const v500Alpha3UserStoreMigrationInjectable = getInjectable({
id: "v5.0.0-alpha.3-user-store-migration",
instantiate: () => ({
version: "5.0.0-alpha.3",
run(store) {
const preferences = (store.get("preferences") ?? {}) as PreV500Alpha3UserPreferencesModel;
const oldHiddenTableColumns = preferences.hiddenTableColumns;
if (!oldHiddenTableColumns) {
return;
}
store.set("preferences", {
...preferences,
hiddenTableColumns: Object.entries(oldHiddenTableColumns),
});
},
}),
injectionToken: userStoreMigrationInjectionToken,
});
export default v500Alpha3UserStoreMigrationInjectable;

View File

@ -0,0 +1,91 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { ClusterStoreModel } from "../../../common/cluster-store/cluster-store";
import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../../common/user-store";
import { isErrnoException } from "../../../common/utils";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
import isLogicalChildPathInjectable from "../../../common/path/is-logical-child-path.injectable";
import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable";
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";
const v503Beta1UserStoreMigrationInjectable = getInjectable({
id: "v5.0.3-beta.1-user-store-migration",
instantiate: (di) => {
const userDataPath = di.inject(directoryForUserDataInjectable);
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const logger = di.inject(loggerInjectable);
const isLogicalChildPath = di.inject(isLogicalChildPathInjectable);
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
const readJsonSync = di.inject(readJsonSyncInjectable);
const homeDirectoryPath = di.inject(homeDirectoryPathInjectable);
const { existsSync } = di.inject(fsInjectable);
return {
version: "5.0.3-beta.1",
run(store) {
try {
const { syncKubeconfigEntries = [], ...preferences } = (store.get("preferences") ?? {}) as UserPreferencesModel;
const { clusters = [] }: ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json"), "utf-8") ?? {};
const extensionDataDir = joinPaths(userDataPath, "extension_data");
const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath));
syncPaths.add(joinPaths(homeDirectoryPath, ".kube"));
for (const cluster of clusters) {
if (!cluster.kubeConfigPath) {
continue;
}
const dirOfKubeconfig = getDirnameOfPath(cluster.kubeConfigPath);
if (dirOfKubeconfig === kubeConfigsPath) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
continue;
}
if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is already being synced`);
continue;
}
if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`);
continue;
}
if (!existsSync(cluster.kubeConfigPath)) {
logger.info(`Skipping ${cluster.id} because kubeConfigPath no longer exists`);
continue;
}
logger.info(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`);
syncPaths.add(cluster.kubeConfigPath);
}
const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath }));
logger.info("Final list of synced paths", updatedSyncEntries);
store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries });
} catch (error) {
if (isErrnoException(error) && error.code !== "ENOENT") {
// ignore files being missing
throw error;
}
}
},
};
},
injectionToken: userStoreMigrationInjectionToken,
});
export default v503Beta1UserStoreMigrationInjectable;

View File

@ -1,14 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Add / reset "lastSeenAppVersion"
import type { MigrationDeclaration } from "../helpers";
export default {
version: "2.1.0-beta.4",
run(store) {
store.set("lastSeenAppVersion", "0.0.0");
},
} as MigrationDeclaration;

View File

@ -1,23 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// Switch representation of hiddenTableColumns in store
import type { MigrationDeclaration } from "../helpers";
export default {
version: "5.0.0-alpha.3",
run(store) {
const preferences = store.get("preferences");
const oldHiddenTableColumns: Record<string, string[]> = preferences?.hiddenTableColumns;
if (!oldHiddenTableColumns) {
return;
}
preferences.hiddenTableColumns = Object.entries(oldHiddenTableColumns);
store.set("preferences", preferences);
},
} as MigrationDeclaration;

View File

@ -1,81 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { existsSync, readFileSync } from "fs";
import os from "os";
import type { ClusterStoreModel } from "../../common/cluster-store/cluster-store";
import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store";
import type { MigrationDeclaration } from "../helpers";
import { migrationLog } from "../helpers";
import { isErrnoException } from "../../common/utils";
import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import joinPathsInjectable from "../../common/path/join-paths.injectable";
import isLogicalChildPathInjectable from "../../common/path/is-logical-child-path.injectable";
import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable";
export default {
version: "5.0.3-beta.1",
run(store) {
try {
const { syncKubeconfigEntries = [], ...preferences }: UserPreferencesModel = store.get("preferences") ?? {};
const di = getLegacyGlobalDiForExtensionApi();
const userDataPath = di.inject(directoryForUserDataInjectable);
const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const isLogicalChildPath = di.inject(isLogicalChildPathInjectable);
const getDirnameOfPath = di.inject(getDirnameOfPathInjectable);
const { clusters = [] }: ClusterStoreModel = JSON.parse(readFileSync(joinPaths(userDataPath, "lens-cluster-store.json"), "utf-8")) ?? {};
const extensionDataDir = joinPaths(userDataPath, "extension_data");
const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath));
syncPaths.add(joinPaths(os.homedir(), ".kube"));
for (const cluster of clusters) {
if (!cluster.kubeConfigPath) {
continue;
}
const dirOfKubeconfig = getDirnameOfPath(cluster.kubeConfigPath);
if (dirOfKubeconfig === kubeConfigsPath) {
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under the stored KubeConfig folder`);
continue;
}
if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) {
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is already being synced`);
continue;
}
if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) {
migrationLog(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`);
continue;
}
if (!existsSync(cluster.kubeConfigPath)) {
migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`);
continue;
}
migrationLog(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`);
syncPaths.add(cluster.kubeConfigPath);
}
const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath }));
migrationLog("Final list of synced paths", updatedSyncEntries);
store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries });
} catch (error) {
if (isErrnoException(error) && error.code !== "ENOENT") {
// ignore files being missing
throw error;
}
}
},
} as MigrationDeclaration;

View File

@ -1,18 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
// User store migrations
import { joinMigrations } from "../helpers";
import version210Beta4 from "./2.1.0-beta.4";
import version500Alpha3 from "./5.0.0-alpha.3";
import version503Beta1 from "./5.0.3-beta.1";
export default joinMigrations(
version210Beta4,
version500Alpha3,
version503Beta1,
);