mirror of
https://github.com/beekeeper-studio/beekeeper-studio.git
synced 2026-03-13 10:12:54 +08:00
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
import path from "path";
|
|
import fs from "fs";
|
|
import rawLog from "@bksLogger";
|
|
import platformInfo from "@/common/platform_info";
|
|
import globals from "@/common/globals";
|
|
import { Module, type ModuleOptions } from "@/services/plugin/Module";
|
|
|
|
const log = rawLog.scope("BundledPluginModule");
|
|
|
|
/**
|
|
* A plugin system module that copies bundled plugins from node_modules (dev)
|
|
* or extraResources (prod) to the user's plugins directory on first launch.
|
|
*
|
|
* @example
|
|
*
|
|
* ```ts
|
|
* const manager = new PluginManager();
|
|
* manager.registerModule(BundledPluginModule);
|
|
* await manager.initialize();
|
|
* ```
|
|
**/
|
|
export class BundledPluginModule extends Module {
|
|
constructor(options: ModuleOptions) {
|
|
super(options);
|
|
|
|
this.hook("before-initialize", this.installBundledPlugins);
|
|
}
|
|
|
|
private async installBundledPlugins() {
|
|
for (const plugin of globals.plugins.ensureInstalled) {
|
|
try {
|
|
await this.ensureInstall(plugin);
|
|
} catch (e) {
|
|
log.error(`Error installing plugin ${plugin}`, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Install a plugin from a given path if it is not already installed.
|
|
*
|
|
* @param pkg Package name (e.g., "@beekeeperstudio/bks-ai-shell")
|
|
*/
|
|
private async ensureInstall(pkg: string) {
|
|
log.info(`Resolving ${pkg}`);
|
|
|
|
const pluginPath = BundledPluginModule.resolve(pkg);
|
|
const pluginsDirectory = this.manager.fileManager.options.pluginsDirectory;
|
|
|
|
if (!fs.existsSync(pluginsDirectory)) {
|
|
fs.mkdirSync(pluginsDirectory, { recursive: true });
|
|
}
|
|
|
|
const manifestPath = path.join(pluginPath, "manifest.json");
|
|
if (!fs.existsSync(manifestPath)) {
|
|
throw new Error(`Plugin not found at ${pluginPath}`);
|
|
}
|
|
|
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
const pluginId = manifest.id;
|
|
|
|
// Have installed before?
|
|
if (this.manager.pluginSettings[pluginId]) {
|
|
log.info(
|
|
`Plugin "${pluginId}" is previously installed, skipping.`
|
|
);
|
|
return;
|
|
}
|
|
|
|
const dst = path.join(pluginsDirectory, pluginId);
|
|
if (fs.existsSync(dst)) {
|
|
// This must be set, otherwise the plugin will be copied again
|
|
await this.manager.setPluginAutoUpdateEnabled(pluginId, true);
|
|
log.info(
|
|
`Plugin "${pluginId}" installation directory already exists on disk.`
|
|
);
|
|
return;
|
|
}
|
|
|
|
log.info(`Installing plugin ${pluginId}`);
|
|
fs.cpSync(pluginPath, dst, { recursive: true });
|
|
|
|
// This must be set, otherwise the plugin will be copied again
|
|
await this.manager.setPluginAutoUpdateEnabled(pluginId, true);
|
|
}
|
|
|
|
/**
|
|
* Resolve a bundled plugin path.
|
|
*
|
|
* @param pkg Package name (e.g., "@beekeeperstudio/bks-ai-shell")
|
|
* @returns The resolved path to the plugin directory
|
|
*/
|
|
static resolve(pkg: string): string {
|
|
if (platformInfo.env.production) {
|
|
// Production: use extraResources location
|
|
return path.join(platformInfo.resourcesPath, "bundled_plugins", pkg);
|
|
}
|
|
|
|
// Development: resolve from node_modules
|
|
const manifestPath = require.resolve(`${pkg}/manifest.json`);
|
|
return path.dirname(manifestPath);
|
|
}
|
|
}
|