mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Move box into injectable within InitializableState to fix tests
- The slight difference in the unit testing where we pretend that there are multiple environments but actually on one caused a problem that doesn't exist in the actual running program. Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
4f3b9cb326
commit
a70992e005
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import directoryForUserDataInjectable, { initDirectoryForUserDataOnMainInjectable, initDirectoryForUserDataOnRendererInjectable } from "./directory-for-user-data.injectable";
|
||||
import joinPathsInjectable from "../path/join-paths.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
|
||||
const {
|
||||
value: directoryForBinariesInjectable,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { initAppPathsOnMainInjectable } from "../../main/app-paths/impl.injectable";
|
||||
import { initAppPathsOnRendererInjectable } from "../../renderer/app-paths/impl.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
import { appPathsInjectionToken } from "./token";
|
||||
|
||||
const {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { initAppPathsOnMainInjectable } from "../../main/app-paths/impl.injectable";
|
||||
import { initAppPathsOnRendererInjectable } from "../../renderer/app-paths/impl.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
import { appPathsInjectionToken } from "./token";
|
||||
|
||||
const {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import directoryForUserDataInjectable, { initDirectoryForUserDataOnMainInjectable, initDirectoryForUserDataOnRendererInjectable } from "./directory-for-user-data.injectable";
|
||||
import joinPathsInjectable from "../path/join-paths.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
|
||||
const {
|
||||
value: directoryForKubeConfigsInjectable,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import directoryForBinariesInjectable, { initDirectoryForBinariesOnMainInjectable, initDirectoryForBinariesOnRendererInjectable } from "./directory-for-binaries.injectable";
|
||||
import joinPathsInjectable from "../path/join-paths.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
|
||||
const {
|
||||
value: directoryForKubectlBinariesInjectable,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { initAppPathsOnMainInjectable } from "../../main/app-paths/impl.injectable";
|
||||
import { initAppPathsOnRendererInjectable } from "../../renderer/app-paths/impl.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
import { appPathsInjectionToken } from "./token";
|
||||
|
||||
const {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { initAppPathsOnMainInjectable } from "../../main/app-paths/impl.injectable";
|
||||
import { initAppPathsOnRendererInjectable } from "../../renderer/app-paths/impl.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
import { appPathsInjectionToken } from "./token";
|
||||
|
||||
const {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import directoryForUserDataInjectable, { initDirectoryForUserDataOnMainInjectable, initDirectoryForUserDataOnRendererInjectable } from "../app-paths/directory-for-user-data.injectable";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
import joinPathsInjectable from "../path/join-paths.injectable";
|
||||
|
||||
const {
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { DiContainerForInjection, Injectable, InjectionToken } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../runnable/run-many-for";
|
||||
import type { InitializableState, InitializableStateValue } from "./create";
|
||||
|
||||
export interface CreateDependentInitializableStateArgs<T> {
|
||||
id: string;
|
||||
init: (di: DiContainerForInjection) => Promise<T> | T;
|
||||
injectionToken?: InjectionToken<InitializableState<T>, void>;
|
||||
initAfter: Injectable<Runnable<void>, Runnable<void>, void>[];
|
||||
}
|
||||
|
||||
export interface CreateDependentInitializableStateResult<T> {
|
||||
value: Injectable<InitializableState<T>, unknown, void>;
|
||||
initializers: Injectable<Runnable<void>, Runnable<void>, void>[];
|
||||
}
|
||||
|
||||
export function createDependentInitializableState<T>(args: CreateDependentInitializableStateArgs<T>): CreateDependentInitializableStateResult<T> {
|
||||
const { id, init, injectionToken, initAfter } = args;
|
||||
|
||||
let box: InitializableStateValue<T> = {
|
||||
set: false,
|
||||
};
|
||||
let initCalled = false;
|
||||
|
||||
const valueInjectable = getInjectable({
|
||||
id,
|
||||
instantiate: (): InitializableState<T> => ({
|
||||
get: () => {
|
||||
if (!initCalled) {
|
||||
throw new Error(`InitializableState(${id}) has not been initialized yet`);
|
||||
}
|
||||
|
||||
if (box.set === false) {
|
||||
throw new Error(`InitializableState(${id}) has not finished initializing`);
|
||||
}
|
||||
|
||||
return box.value;
|
||||
},
|
||||
}),
|
||||
injectionToken,
|
||||
});
|
||||
|
||||
const initializers = initAfter.map(runnableInjectable => getInjectable({
|
||||
id: `initialize-${id}-during-${runnableInjectable.injectionToken?.id}`,
|
||||
instantiate: (di) => ({
|
||||
id: `initialize-${id}`,
|
||||
run: (): void | Promise<void> => {
|
||||
if (initCalled) {
|
||||
throw new Error(`Cannot initialize InitializableState(${id}) more than once`);
|
||||
}
|
||||
|
||||
initCalled = true;
|
||||
const potentialValue = init(di);
|
||||
|
||||
if (potentialValue instanceof Promise) {
|
||||
// This is done because we have to run syncronously if `init` is syncronous to prevent ordering issues
|
||||
return (async () => {
|
||||
box = {
|
||||
set: true,
|
||||
value: await potentialValue,
|
||||
};
|
||||
})();
|
||||
} else {
|
||||
box = {
|
||||
set: true,
|
||||
value: potentialValue,
|
||||
};
|
||||
}
|
||||
},
|
||||
runAfter: di.inject(runnableInjectable),
|
||||
}),
|
||||
injectionToken: runnableInjectable.injectionToken,
|
||||
}));
|
||||
|
||||
return {
|
||||
value: valueInjectable,
|
||||
initializers,
|
||||
};
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
import type { DiContainerForInjection, Injectable, InjectionToken } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Runnable } from "../runnable/run-many-for";
|
||||
import type { Discriminable } from "../utils/composable-responsibilities/discriminable/discriminable";
|
||||
|
||||
export interface CreateInitializableStateArgs<T> {
|
||||
id: string;
|
||||
@ -14,13 +15,23 @@ export interface CreateInitializableStateArgs<T> {
|
||||
when: InjectionToken<Runnable<void>, void>;
|
||||
}
|
||||
|
||||
const setInitializing = Symbol("set-initializing");
|
||||
const initialize = Symbol("initialize");
|
||||
|
||||
export interface InitializableState<T> {
|
||||
get: () => T;
|
||||
[setInitializing]: () => void;
|
||||
[initialize]: (value: T) => void;
|
||||
}
|
||||
|
||||
export type UnsetValue = Discriminable<"uninitialized">;
|
||||
export type InitializingValue = Discriminable<"initializing">;
|
||||
export type InitializedValue<T> = Discriminable<"initialized"> & { value: T };
|
||||
|
||||
export type InitializableStateValue<T> =
|
||||
| { set: false }
|
||||
| { set: true; value: T };
|
||||
| UnsetValue
|
||||
| InitializingValue
|
||||
| InitializedValue<T>;
|
||||
|
||||
export interface CreateInitializableStateResult<T> {
|
||||
value: Injectable<InitializableState<T>, unknown, void>;
|
||||
@ -30,54 +41,62 @@ export interface CreateInitializableStateResult<T> {
|
||||
export function createInitializableState<T>(args: CreateInitializableStateArgs<T>): CreateInitializableStateResult<T> {
|
||||
const { id, init, injectionToken, when } = args;
|
||||
|
||||
let box: InitializableStateValue<T> = {
|
||||
set: false,
|
||||
};
|
||||
let initCalled = false;
|
||||
|
||||
const valueInjectable = getInjectable({
|
||||
id,
|
||||
instantiate: (): InitializableState<T> => ({
|
||||
get: () => {
|
||||
if (!initCalled) {
|
||||
throw new Error(`InitializableState(${id}) has not been initialized yet`);
|
||||
}
|
||||
instantiate: (): InitializableState<T> => {
|
||||
let box: InitializableStateValue<T> = {
|
||||
kind: "uninitialized",
|
||||
};
|
||||
|
||||
if (box.set === false) {
|
||||
throw new Error(`InitializableState(${id}) has not finished initializing`);
|
||||
return {
|
||||
get: () => {
|
||||
if (box.kind !== "initialized") {
|
||||
throw new Error(`Cannot get value from "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
return box.value;
|
||||
},
|
||||
}),
|
||||
[setInitializing]: () => {
|
||||
if (box.kind !== "uninitialized") {
|
||||
throw new Error(`Cannot start initializing value for "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
box = {
|
||||
kind: "initializing",
|
||||
};
|
||||
},
|
||||
[initialize]: (value) => {
|
||||
if (box.kind !== "initializing") {
|
||||
throw new Error(`Cannot initialize value for "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
box = {
|
||||
kind: "initialized",
|
||||
value,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken,
|
||||
});
|
||||
|
||||
const subId = `initialize id="${id}" during id="${when.id}"`;
|
||||
const initializer = getInjectable({
|
||||
id: `initialize-${id}`,
|
||||
id: subId,
|
||||
instantiate: (di) => ({
|
||||
id: `initialize-${id}`,
|
||||
run: async () => {
|
||||
if (initCalled) {
|
||||
throw new Error(`Cannot initialize InitializableState(${id}) more than once`);
|
||||
}
|
||||
id: subId,
|
||||
run: (): void | Promise<void> => {
|
||||
const value = di.inject(valueInjectable);
|
||||
|
||||
value[setInitializing]();
|
||||
|
||||
initCalled = true;
|
||||
const potentialValue = init(di);
|
||||
|
||||
if (potentialValue instanceof Promise) {
|
||||
// This is done because we have to run syncronously if `init` is syncronous to prevent ordering issues
|
||||
return (async () => {
|
||||
box = {
|
||||
set: true,
|
||||
value: await potentialValue,
|
||||
};
|
||||
})();
|
||||
return potentialValue.then(value[initialize]);
|
||||
} else {
|
||||
box = {
|
||||
set: true,
|
||||
value: potentialValue,
|
||||
};
|
||||
value[initialize](potentialValue);
|
||||
}
|
||||
},
|
||||
}),
|
||||
@ -89,3 +108,91 @@ export function createInitializableState<T>(args: CreateInitializableStateArgs<T
|
||||
initializer,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface CreateDependentInitializableStateArgs<T> {
|
||||
id: string;
|
||||
init: (di: DiContainerForInjection) => Promise<T> | T;
|
||||
injectionToken?: InjectionToken<InitializableState<T>, void>;
|
||||
initAfter: Injectable<Runnable<void>, Runnable<void>, void>[];
|
||||
}
|
||||
|
||||
export interface CreateDependentInitializableStateResult<T> {
|
||||
value: Injectable<InitializableState<T>, unknown, void>;
|
||||
initializers: Injectable<Runnable<void>, Runnable<void>, void>[];
|
||||
}
|
||||
|
||||
export function createDependentInitializableState<T>(args: CreateDependentInitializableStateArgs<T>): CreateDependentInitializableStateResult<T> {
|
||||
const { id, init, injectionToken, initAfter } = args;
|
||||
|
||||
const valueInjectable = getInjectable({
|
||||
id,
|
||||
instantiate: (): InitializableState<T> => {
|
||||
let box: InitializableStateValue<T> = {
|
||||
kind: "uninitialized",
|
||||
};
|
||||
|
||||
return {
|
||||
get: () => {
|
||||
if (box.kind !== "initialized") {
|
||||
throw new Error(`Cannot get value from "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
return box.value;
|
||||
},
|
||||
[setInitializing]: () => {
|
||||
if (box.kind !== "uninitialized") {
|
||||
throw new Error(`Cannot start initializing value for "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
box = {
|
||||
kind: "initializing",
|
||||
};
|
||||
},
|
||||
[initialize]: (value) => {
|
||||
if (box.kind !== "initializing") {
|
||||
throw new Error(`Cannot initialize value for "${id}"; it is currently in state=${box.kind}`);
|
||||
}
|
||||
|
||||
box = {
|
||||
kind: "initialized",
|
||||
value,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken,
|
||||
});
|
||||
|
||||
const initializers = initAfter.map(runnableInjectable => {
|
||||
const subId = `initialize "${id}" after "${runnableInjectable.id}"`;
|
||||
|
||||
return getInjectable({
|
||||
id: subId,
|
||||
instantiate: (di) => ({
|
||||
id: subId,
|
||||
run: (): void | Promise<void> => {
|
||||
const value = di.inject(valueInjectable);
|
||||
|
||||
value[setInitializing]();
|
||||
|
||||
const potentialValue = init(di);
|
||||
|
||||
if (potentialValue instanceof Promise) {
|
||||
// This is done because we have to run syncronously if `init` is syncronous to prevent ordering issues
|
||||
return potentialValue.then(value[initialize]);
|
||||
} else {
|
||||
value[initialize](potentialValue);
|
||||
}
|
||||
},
|
||||
runAfter: di.inject(runnableInjectable),
|
||||
}),
|
||||
injectionToken: runnableInjectable.injectionToken,
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
value: valueInjectable,
|
||||
initializers,
|
||||
};
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import { SemVer } from "semver";
|
||||
import { initializeBuildVersionOnMainInjectable } from "../../../main/vars/build-version/build-version.injectable";
|
||||
import { initializeBuildVersionOnRendererInjectable } from "../../../renderer/vars/build-version.injectable";
|
||||
import { createDependentInitializableState } from "../../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../../initializable-state/create";
|
||||
import { buildVersionInjectionToken } from "./token";
|
||||
|
||||
const {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import buildSemanticVersionInjectable, { initBuildSemanticVersionOnMainInjectable, initBuildSemanticVersionOnRendererInjectable } from "./build-version/semantic-version.injectable";
|
||||
import type { ReleaseChannel } from "../../features/application-update/common/update-channels";
|
||||
import { createDependentInitializableState } from "../initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../initializable-state/create";
|
||||
|
||||
const {
|
||||
value: releaseChannelInjectable,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import directoryForUserDataInjectable, { initDirectoryForUserDataOnMainInjectable, initDirectoryForUserDataOnRendererInjectable } from "../../common/app-paths/directory-for-user-data.injectable";
|
||||
import { createDependentInitializableState } from "../../common/initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../../common/initializable-state/create";
|
||||
|
||||
const {
|
||||
value: extensionPackageRootDirectoryInjectable,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import directoryForUserDataInjectable, { initDirectoryForUserDataOnMainInjectable, initDirectoryForUserDataOnRendererInjectable } from "../../../common/app-paths/directory-for-user-data.injectable";
|
||||
import { createDependentInitializableState } from "../../../common/initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../../../common/initializable-state/create";
|
||||
import joinPathsInjectable from "../../../common/path/join-paths.injectable";
|
||||
|
||||
const {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { createDependentInitializableState } from "../../../../common/initializable-state/create-dependent";
|
||||
import { createDependentInitializableState } from "../../../../common/initializable-state/create";
|
||||
import releaseChannelInjectable, { initReleaseChannelOnMainInjectable, initReleaseChannelOnRendererInjectable } from "../../../../common/vars/release-channel.injectable";
|
||||
import { updateChannels } from "../update-channels";
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user