docker-pilot
Version:
A powerful, scalable Docker CLI library for managing containerized applications of any size
288 lines • 10.3 kB
JavaScript
"use strict";
/**
* Plugin Manager for Docker Pilot
* Manages plugin loading, initialization, and lifecycle
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PluginManager = void 0;
const path = __importStar(require("path"));
const Logger_1 = require("../utils/Logger");
const FileUtils_1 = require("../utils/FileUtils");
const i18n_1 = require("../utils/i18n");
class PluginManager {
constructor(options = {}) {
this.plugins = new Map();
this.hooks = new Map();
this.logger = new Logger_1.Logger();
this.fileUtils = new FileUtils_1.FileUtils(this.logger);
this.i18n = new i18n_1.I18n();
this.options = {
pluginDir: options.pluginDir || path.join(process.cwd(), 'plugins'),
autoLoad: options.autoLoad ?? true,
enabledPlugins: options.enabledPlugins || []
};
} /**
* Initialize plugin manager
*/
async initialize() {
this.logger.debug(this.i18n.t('plugin.manager_initialized'));
if (this.options.autoLoad) {
await this.loadPlugins();
}
this.logger.success(this.i18n.t('plugin.manager_initialized'));
}
/**
* Load plugins from directory
*/
async loadPlugins() {
try {
if (!(await this.fileUtils.exists(this.options.pluginDir))) {
this.logger.debug(this.i18n.t('plugin.dir_not_found', { dir: this.options.pluginDir }));
return;
}
const pluginFiles = await this.fileUtils.findFiles('**/*.js', {
cwd: this.options.pluginDir
});
for (const pluginFile of pluginFiles) {
try {
await this.loadPlugin(pluginFile);
}
catch (error) {
this.logger.error(this.i18n.t('plugin.failed_load', { name: pluginFile }), error);
}
}
}
catch (error) {
this.logger.error(this.i18n.t('plugin.failed_load'), error);
}
}
/**
* Load a specific plugin
*/
async loadPlugin(pluginPath) {
const pluginName = path.basename(pluginPath, '.js');
// Check if plugin is enabled
if (this.options.enabledPlugins.length > 0 &&
!this.options.enabledPlugins.includes(pluginName)) {
this.logger.debug(this.i18n.t('plugin.not_enabled', { name: pluginName }));
throw new Error(this.i18n.t('plugin.not_enabled', { name: pluginName }));
}
// Dynamic import of plugin
const pluginModule = await Promise.resolve(`${pluginPath}`).then(s => __importStar(require(s)));
const PluginClass = pluginModule.default || pluginModule;
if (typeof PluginClass !== 'function') {
throw new Error(this.i18n.t('plugin.invalid', { name: pluginName }));
}
const plugin = new PluginClass();
// Validate plugin structure
if (!this.isValidPlugin(plugin)) {
throw new Error(this.i18n.t('plugin.invalid', { name: pluginName }));
} // Initialize plugin
if (plugin.initialize) {
// Create a minimal context for plugin initialization
const context = {
config: { projectName: '', dockerCompose: 'docker compose', configVersion: '1.0', services: {}, plugins: [], cli: {}, backup: {}, monitoring: {}, development: {}, networks: {}, volumes: {} },
logger: this.logger,
workingDirectory: process.cwd()
};
await plugin.initialize(context);
}
// Register plugin hooks
if (plugin.hooks) {
this.registerPluginHooks(pluginName, plugin.hooks);
}
this.plugins.set(pluginName, plugin);
this.logger.success(this.i18n.t('plugin.loaded', { name: pluginName }));
return plugin;
}
/**
* Unload a plugin
*/ async unloadPlugin(pluginName) {
const plugin = this.plugins.get(pluginName);
if (!plugin) {
throw new Error(this.i18n.t('plugin.not_found', { name: pluginName }));
}
// Cleanup plugin
if (plugin.cleanup) {
await plugin.cleanup();
}
// Unregister hooks
this.unregisterPluginHooks(pluginName);
this.plugins.delete(pluginName);
this.logger.success(this.i18n.t('plugin.unloaded', { name: pluginName }));
}
/**
* Get loaded plugin
*/
getPlugin(pluginName) {
return this.plugins.get(pluginName) || null;
}
/**
* Get all loaded plugins
*/
getPlugins() {
return Array.from(this.plugins.values());
}
/**
* Check if plugin is loaded
*/
hasPlugin(pluginName) {
return this.plugins.has(pluginName);
}
/**
* Register plugin hooks
*/
registerPluginHooks(pluginName, hooks) {
for (const [hookName, handler] of Object.entries(hooks)) {
if (!this.hooks.has(hookName)) {
this.hooks.set(hookName, []);
}
this.hooks.get(hookName).push(handler);
this.logger.debug(`Registered hook: ${hookName} for plugin: ${pluginName}`);
}
}
/**
* Unregister plugin hooks
*/
unregisterPluginHooks(_pluginName) {
for (const [_hookName, _handlers] of this.hooks.entries()) {
// Remove handlers that belong to this plugin
// This is a simplified approach - in a real implementation,
// you'd need to track which handlers belong to which plugin
this.hooks.set(_hookName, []);
}
}
/**
* Execute hook
*/
async executeHook(hookName, ...args) {
const handlers = this.hooks.get(hookName) || [];
const results = [];
for (const handler of handlers) {
try {
const result = await handler(...args);
results.push(result);
}
catch (error) {
this.logger.error(`Hook execution failed: ${hookName}`, error);
results.push(null);
}
}
return results;
}
/**
* Validate plugin structure
*/
isValidPlugin(plugin) {
return (typeof plugin === 'object' &&
plugin !== null &&
typeof plugin.metadata === 'object' &&
typeof plugin.metadata.name === 'string' &&
typeof plugin.metadata.version === 'string');
}
/**
* Get plugin metadata
*/
getPluginMetadata() {
return Array.from(this.plugins.values()).map(plugin => plugin.metadata);
}
/**
* Enable plugin
*/
async enablePlugin(pluginName) {
if (!this.options.enabledPlugins.includes(pluginName)) {
this.options.enabledPlugins.push(pluginName);
}
if (!this.hasPlugin(pluginName)) {
const pluginPath = path.join(this.options.pluginDir, `${pluginName}.js`);
await this.loadPlugin(pluginPath);
}
}
/**
* Disable plugin
*/
async disablePlugin(pluginName) {
const index = this.options.enabledPlugins.indexOf(pluginName);
if (index > -1) {
this.options.enabledPlugins.splice(index, 1);
}
if (this.hasPlugin(pluginName)) {
await this.unloadPlugin(pluginName);
}
} /**
* Update plugin configuration
*/
async updatePluginConfig(pluginName, config) {
const plugin = this.getPlugin(pluginName);
if (!plugin) {
throw new Error(this.i18n.t('plugin.not_found', { name: pluginName }));
}
// For now, we just log the config update
// In a full implementation, this would notify the plugin
this.logger.debug(this.i18n.t('plugin.config_updated', { name: pluginName }), config);
}
/**
* Update language for all plugins
*/
updateLanguage(language) {
this.i18n.setLanguage(language);
// Update language for all loaded plugins
for (const plugin of this.plugins.values()) {
if (plugin && typeof plugin.updateLanguage === 'function') {
plugin.updateLanguage(language);
}
}
}
/**
* Cleanup all plugins
*/
async cleanup() {
this.logger.debug(this.i18n.t('plugin.cleanup_completed'));
const pluginNames = Array.from(this.plugins.keys());
for (const pluginName of pluginNames) {
try {
await this.unloadPlugin(pluginName);
}
catch (error) {
this.logger.error(this.i18n.t('plugin.failed_unload', { name: pluginName }), error);
}
}
this.hooks.clear();
this.logger.success(this.i18n.t('plugin.cleanup_completed'));
}
}
exports.PluginManager = PluginManager;
//# sourceMappingURL=PluginManager.js.map