mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add extension uninstall (#1524)
Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
This commit is contained in:
1 parent
95d7ff847e
commit
ccd38b5cbe
8 files changed
+106
-42
No files matched your search
@@ -18,6 +18,7 @@ jest.mock(
|
||||
name: "TestExtension",
|
||||
version: "1.0.0",
|
||||
},
|
||||
absolutePath: "/test/1",
|
||||
manifestPath,
|
||||
isBundled: false,
|
||||
isEnabled: true,
|
||||
@@ -30,6 +31,7 @@ jest.mock(
|
||||
name: "TestExtension2",
|
||||
version: "2.0.0",
|
||||
},
|
||||
absolutePath: "/test/2",
|
||||
manifestPath: manifestPath2,
|
||||
isBundled: false,
|
||||
isEnabled: true,
|
||||
@@ -52,6 +54,7 @@ jest.mock(
|
||||
name: "TestExtension",
|
||||
version: "1.0.0",
|
||||
},
|
||||
absolutePath: "/test/1",
|
||||
manifestPath,
|
||||
isBundled: false,
|
||||
isEnabled: true,
|
||||
@@ -64,7 +67,8 @@ jest.mock(
|
||||
name: "TestExtension3",
|
||||
version: "3.0.0",
|
||||
},
|
||||
manifestPath3,
|
||||
absolutePath: "/test/3",
|
||||
manifestPath: manifestPath3,
|
||||
isBundled: false,
|
||||
isEnabled: true,
|
||||
},
|
||||
@@ -94,6 +98,7 @@ describe("ExtensionLoader", () => {
|
||||
expect(extensionLoader.userExtensions).toMatchInlineSnapshot(`
|
||||
Map {
|
||||
"manifest/path" => Object {
|
||||
"absolutePath": "/test/1",
|
||||
"isBundled": false,
|
||||
"isEnabled": true,
|
||||
"manifest": Object {
|
||||
@@ -103,13 +108,14 @@ describe("ExtensionLoader", () => {
|
||||
"manifestPath": "manifest/path",
|
||||
},
|
||||
"manifest/path3" => Object {
|
||||
"absolutePath": "/test/3",
|
||||
"isBundled": false,
|
||||
"isEnabled": true,
|
||||
"manifest": Object {
|
||||
"name": "TestExtension3",
|
||||
"version": "3.0.0",
|
||||
},
|
||||
"manifestPath3": "manifest/path3",
|
||||
"manifestPath": "manifest/path3",
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -9,6 +9,7 @@ describe("lens extension", () => {
|
||||
name: "foo-bar",
|
||||
version: "0.1.1"
|
||||
},
|
||||
absolutePath: "/absolute/fake/",
|
||||
manifestPath: "/this/is/fake/package.json",
|
||||
isBundled: false,
|
||||
isEnabled: true
|
||||
|
||||
@@ -11,6 +11,12 @@ import type { LensExtensionId, LensExtensionManifest } from "./lens-extension";
|
||||
|
||||
export interface InstalledExtension {
|
||||
readonly manifest: LensExtensionManifest;
|
||||
|
||||
// Absolute path to the non-symlinked source folder,
|
||||
// e.g. "/Users/user/.k8slens/extensions/helloworld"
|
||||
readonly absolutePath: string;
|
||||
|
||||
// Absolute to the symlinked package.json file
|
||||
readonly manifestPath: string;
|
||||
readonly isBundled: boolean; // defined in project root's package.json
|
||||
isEnabled: boolean;
|
||||
@@ -174,6 +180,24 @@ export class ExtensionDiscovery {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Uninstalls extension by path.
|
||||
* The application will detect the folder unlink and remove the extension from the UI automatically.
|
||||
* @param absolutePath Path to the non-symlinked folder of the extension
|
||||
*/
|
||||
async uninstallExtension(absolutePath: string) {
|
||||
logger.info(`${logModule} Uninstalling ${absolutePath}`);
|
||||
|
||||
const exists = await fs.pathExists(absolutePath);
|
||||
|
||||
if (!exists) {
|
||||
throw new Error(`Extension path ${absolutePath} doesn't exist`);
|
||||
}
|
||||
|
||||
// fs.remove does nothing if the path doesn't exist anymore
|
||||
await fs.remove(absolutePath);
|
||||
}
|
||||
|
||||
async load(): Promise<Map<LensExtensionId, InstalledExtension>> {
|
||||
if (this.loadStarted) {
|
||||
// The class is simplified by only supporting .load() to be called once
|
||||
@@ -230,6 +254,7 @@ export class ExtensionDiscovery {
|
||||
const isEnabled = isBundled || extensionsStore.isEnabled(installedManifestPath);
|
||||
|
||||
return {
|
||||
absolutePath: path.dirname(manifestPath),
|
||||
manifestPath: installedManifestPath,
|
||||
manifest: manifestJson,
|
||||
isBundled,
|
||||
|
||||
@@ -68,15 +68,18 @@ export class ExtensionLoader {
|
||||
logger.info(`${logModule} deleting extension instance ${lensExtensionId}`);
|
||||
const instance = this.instances.get(lensExtensionId);
|
||||
|
||||
if (instance) {
|
||||
try {
|
||||
instance.disable();
|
||||
this.events.emit("remove", instance);
|
||||
this.instances.delete(lensExtensionId);
|
||||
} catch (error) {
|
||||
logger.error(`${logModule}: deactivation extension error`, { lensExtensionId, error });
|
||||
}
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
instance.disable();
|
||||
this.events.emit("remove", instance);
|
||||
this.instances.delete(lensExtensionId);
|
||||
} catch (error) {
|
||||
logger.error(`${logModule}: deactivation extension error`, { lensExtensionId, error });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
removeExtension(lensExtensionId: LensExtensionId) {
|
||||
@@ -85,7 +88,6 @@ export class ExtensionLoader {
|
||||
if (!this.extensions.delete(lensExtensionId)) {
|
||||
throw new Error(`Can't remove extension ${lensExtensionId}, doesn't exist.`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected async initMain() {
|
||||
|
||||
@@ -114,3 +114,7 @@ export class LensExtension {
|
||||
export function sanitizeExtensionName(name: string) {
|
||||
return name.replace("@", "").replace("/", "--");
|
||||
}
|
||||
|
||||
export function extensionDisplayName(name: string, version: string) {
|
||||
return `${name}@${version}`;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ describe("getPageUrl", () => {
|
||||
name: "foo-bar",
|
||||
version: "0.1.1"
|
||||
},
|
||||
absolutePath: "/absolute/fake/",
|
||||
manifestPath: "/this/is/fake/package.json",
|
||||
isBundled: false,
|
||||
isEnabled: true
|
||||
@@ -41,6 +42,7 @@ describe("globalPageRegistry", () => {
|
||||
name: "@acme/foo-bar",
|
||||
version: "0.1.1"
|
||||
},
|
||||
absolutePath: "/absolute/fake/",
|
||||
manifestPath: "/this/is/fake/package.json",
|
||||
isBundled: false,
|
||||
isEnabled: true
|
||||
|
||||
Reference in new issue
Block a user