From 636777d9352d15feb419bf3573123e976424bcd4 Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Mon, 25 Nov 2024 12:22:16 +0000 Subject: [PATCH] Add locally provided plugins by default --- packages/controller/controller.ts | 9 +--- packages/ctl/ctl.ts | 9 +--- packages/host/host.ts | 9 +--- packages/lib/index.ts | 1 + packages/lib/src/load_plugin_list.ts | 74 ++++++++++++++++++++++++++++ packages/lib/src/plugin_loader.ts | 9 ++++ 6 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 packages/lib/src/load_plugin_list.ts diff --git a/packages/controller/controller.ts b/packages/controller/controller.ts index d9bdaf9c..6587e01d 100644 --- a/packages/controller/controller.ts +++ b/packages/controller/controller.ts @@ -317,14 +317,7 @@ async function initialize(): Promise { } logger.info(`Loading available plugins from ${args.pluginList}`); - let pluginList = new Map(); - try { - pluginList = new Map(JSON.parse(await fs.readFile(args.pluginList, { encoding: "utf8" }))); - } catch (err: any) { - if (err.code !== "ENOENT") { - throw err; - } - } + let pluginList = await lib.loadPluginList(args.pluginList); // If the command is plugin management we don't try to load plugins if (command === "plugin") { diff --git a/packages/ctl/ctl.ts b/packages/ctl/ctl.ts index b5edb31c..70d49964 100755 --- a/packages/ctl/ctl.ts +++ b/packages/ctl/ctl.ts @@ -188,14 +188,7 @@ async function startControl() { lib.handleUnhandledErrors(); logger.verbose(`Loading available plugins from ${args.pluginList}`); - let pluginList = new Map(); - try { - pluginList = new Map(JSON.parse(await fs.readFile(args.pluginList, "utf8"))); - } catch (err: any) { - if (err.code !== "ENOENT") { - throw err; - } - } + let pluginList = await lib.loadPluginList(args.pluginList); // If the command is plugin management we don't try to load plugins if (args._[0] === "plugin") { diff --git a/packages/host/host.ts b/packages/host/host.ts index b0123964..0247e9aa 100755 --- a/packages/host/host.ts +++ b/packages/host/host.ts @@ -147,14 +147,7 @@ async function startHost() { } logger.info(`Loading available plugins from ${args.pluginList}`); - let pluginList = new Map(); - try { - pluginList = new Map(JSON.parse(await fs.readFile(args.pluginList, "utf8"))); - } catch (err: any) { - if (err.code !== "ENOENT") { - throw err; - } - } + let pluginList = await lib.loadPluginList(args.pluginList); // If the command is plugin management we don't try to load plugins if (command === "plugin") { diff --git a/packages/lib/index.ts b/packages/lib/index.ts index bec088ad..9cd87213 100644 --- a/packages/lib/index.ts +++ b/packages/lib/index.ts @@ -29,6 +29,7 @@ export * from "./src/system_collectors"; export * from "./src/zip_ops"; export * from "./src/subscriptions"; export * from "./src/datastore"; +export * from "./src/load_plugin_list"; export { default as ExponentialBackoff } from "./src/ExponentialBackoff"; export { default as ModStore } from "./src/ModStore"; diff --git a/packages/lib/src/load_plugin_list.ts b/packages/lib/src/load_plugin_list.ts new file mode 100644 index 00000000..3545c747 --- /dev/null +++ b/packages/lib/src/load_plugin_list.ts @@ -0,0 +1,74 @@ +import fs from "fs-extra"; +import path from "path"; +import { logger } from "./logging"; +import * as libFileOps from "./file_ops"; + +/** + * Find local plugins to add to the plugin list. This is primarily used during development. + */ +async function findLocalPlugins(pluginList: Map, pluginListPath: string) { + // Check folders for plugins + const pluginFolders = [ + path.join(process.cwd(), "plugins"), + path.join(process.cwd(), "external_plugins"), + ]; + + let has_changed = 0; + for (const pluginFolder of pluginFolders) { + const pluginNames = await fs.readdir(pluginFolder); + for (const pluginName of pluginNames) { + if (pluginList.has(pluginName)) { + continue; + } + const pluginPath = path.resolve(pluginFolder, pluginName); + const stats = await fs.stat(pluginPath); + if (!stats.isDirectory()) { + continue; + } + + // Check that the plugin has a package.json file + const packageJsonPath = path.resolve(pluginPath, "package.json"); + if (!(await fs.exists(packageJsonPath))) { + continue; + } + console.log(`Adding ${pluginName} from ${pluginFolder}`); + + pluginList.set(pluginName, pluginPath); + logger.info(`Added ${pluginName} from ${pluginFolder}`); + has_changed++; + } + } + + if (has_changed > 0) { + await libFileOps.safeOutputFile(pluginListPath, JSON.stringify([...pluginList], null, "\t")); + } +} + +/** + * Loads the plugin list from the specified file and optionally discovers local plugins + * + * @param pluginListPath - Path to the plugin list JSON file + * @param findLocal - Whether to look for local plugins in plugins/ and external_plugins/ directories + * @returns Map of plugin name to plugin path + */ +export async function loadPluginList(pluginListPath: string, findLocal = true): Promise> { + let pluginList = new Map(); + + // Try to load existing plugin list + try { + pluginList = new Map(JSON.parse(await fs.readFile(pluginListPath, { encoding: "utf8" }))); + logger.info(`Loaded ${pluginList.size} plugins from ${pluginListPath}`); + } catch (err: any) { + if (err.code !== "ENOENT") { + throw err; + } + logger.info(`No existing plugin list found at ${pluginListPath}`); + } + + // Optionally discover local plugins + if (findLocal) { + await findLocalPlugins(pluginList, pluginListPath); + } + + return pluginList; +} diff --git a/packages/lib/src/plugin_loader.ts b/packages/lib/src/plugin_loader.ts index 3c1af67f..824ca94f 100644 --- a/packages/lib/src/plugin_loader.ts +++ b/packages/lib/src/plugin_loader.ts @@ -26,6 +26,15 @@ export async function loadPluginInfos(pluginList: Map) { let pluginInfo: libPlugin.PluginNodeEnvInfo; let pluginPackage: { name?: string, version: string, main?: string, private?: boolean }; + // Check if plugin path exists, otherwise remove it + try { + require.resolve(pluginPath); + } catch (err) { + logger.warn(`Plugin path ${pluginPath} does not exist, removing ${pluginName}`); + pluginList.delete(pluginName); + continue; + } + try { pluginInfo = require(pluginPath).plugin; pluginPackage = require(path.posix.join(pluginPath, "package.json"));