diff --git a/src/extensions/extension-manager.ts b/src/extensions/extension-manager.ts index a0ec3ad897..1e0ebf9387 100644 --- a/src/extensions/extension-manager.ts +++ b/src/extensions/extension-manager.ts @@ -1,5 +1,6 @@ import type { ExtensionManifest } from "./lens-extension" import path from "path" +import os from "os" import fs from "fs-extra" import logger from "../main/logger" import { extensionPackagesRoot, InstalledExtension } from "./extension-loader" @@ -24,10 +25,14 @@ export class ExtensionManager { return extensionPackagesRoot() } - get folderPath(): string { + get inTreeFolderPath(): string { return path.resolve(__static, "../extensions"); } + get localFolderPath(): string { + return path.join(os.homedir(), ".k8slens", "extensions"); + } + get npmPath() { return __non_webpack_require__.resolve('npm/bin/npm-cli') } @@ -35,7 +40,7 @@ export class ExtensionManager { async load() { logger.info("[EXTENSION-MANAGER] loading extensions from " + this.extensionPackagesRoot) await fs.ensureDir(path.join(this.extensionPackagesRoot, "node_modules")) - + await fs.ensureDir(this.localFolderPath) return await this.loadExtensions(); } @@ -74,14 +79,17 @@ export class ExtensionManager { } async loadExtensions() { - const extensions = await this.loadFromFolder(this.folderPath); + const bundledExtensions = await this.loadBundledExtensions() + const localExtendions = await this.loadFromFolder(this.localFolderPath) + const extensions = bundledExtensions.concat(localExtendions) return new Map(extensions.map(ext => [ext.id, ext])); } - async loadFromFolder(folderPath: string): Promise { - const paths = await fs.readdir(folderPath); + async loadBundledExtensions() { const extensions: InstalledExtension[] = [] + const folderPath = this.inTreeFolderPath const bundledExtensions = getBundledExtensions() + const paths = await fs.readdir(folderPath); for (const fileName of paths) { if (!bundledExtensions.includes(fileName)) { continue @@ -94,10 +102,33 @@ export class ExtensionManager { extensions.push(ext) } } + logger.debug(`[EXTENSION-MANAGER]: ${extensions.length} extensions loaded`, { folderPath, extensions }); + await fs.writeFile(path.join(this.extensionPackagesRoot, "package.json"), JSON.stringify(this.packagesJson), {mode: 0o600}) + await this.installPackages() + return extensions + } + + async loadFromFolder(folderPath: string): Promise { + const bundledExtensions = getBundledExtensions() + const extensions: InstalledExtension[] = [] + const paths = await fs.readdir(folderPath); + for (const fileName of paths) { + if (bundledExtensions.includes(fileName)) { // do no allow to override bundled extensions + continue + } + const absPath = path.resolve(folderPath, fileName); + const manifestPath = path.resolve(absPath, "package.json"); + await fs.access(manifestPath, fs.constants.F_OK) + const ext = await this.getExtensionByManifest(manifestPath).catch(() => null) + if (ext) { + extensions.push(ext) + } + } + + logger.debug(`[EXTENSION-MANAGER]: ${extensions.length} extensions loaded`, { folderPath, extensions }); await fs.writeFile(path.join(this.extensionPackagesRoot, "package.json"), JSON.stringify(this.packagesJson), {mode: 0o600}) await this.installPackages() - logger.debug(`[EXTENSION-MANAGER]: ${extensions.length} extensions loaded`, { folderPath, extensions }); return extensions; } }