mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 23:45:59 +00:00
packaged plugins
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
"build:app": "cd app && yarn install && yarn build",
|
||||
"build:api": "yarn workspace dbgate-api build",
|
||||
"build:web:docker": "yarn workspace dbgate-web build",
|
||||
"build:plugins:frontend": "yarn workspace dbgate-plugin-csv build:frontend && yarn workspace dbgate-plugin-excel build:frontend && yarn workspace dbgate-plugin-mysql build:frontend && yarn workspace dbgate-plugin-mssql build:frontend && yarn workspace dbgate-plugin-mongo build:frontend && yarn workspace dbgate-plugin-postgres build:frontend &&",
|
||||
"build:plugins:frontend": "workspaces-run --only=\"dbgate-plugin-*\" -- yarn build:frontend",
|
||||
"build:app:local": "cd app && yarn build:local",
|
||||
"start:app:local": "cd app && yarn start:local",
|
||||
"setCurrentVersion": "node setCurrentVersion",
|
||||
@@ -39,7 +39,7 @@
|
||||
"ts:api": "yarn workspace dbgate-api ts",
|
||||
"ts:web": "yarn workspace dbgate-web ts",
|
||||
"ts": "yarn ts:api && yarn ts:web",
|
||||
"postinstall": "patch-package && yarn fillNativeModules"
|
||||
"postinstall": "patch-package && yarn fillNativeModules && yarn build:plugins:frontend"
|
||||
},
|
||||
"dependencies": {
|
||||
"concurrently": "^5.1.0",
|
||||
@@ -48,6 +48,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"copyfiles": "^2.2.0",
|
||||
"prettier": "^2.2.1"
|
||||
"prettier": "^2.2.1",
|
||||
"workspaces-run": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"express-basic-auth": "^1.2.0",
|
||||
"express-fileupload": "^1.2.0",
|
||||
"find-free-port": "^2.0.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"http": "^0.0.0",
|
||||
"json-stable-stringify": "^1.0.1",
|
||||
"line-reader": "^0.4.0",
|
||||
@@ -56,6 +56,7 @@
|
||||
"build": "webpack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^9.0.11",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"dbgate-types": "^4.0.0",
|
||||
"env-cmd": "^10.1.0",
|
||||
@@ -68,4 +69,4 @@
|
||||
"optionalDependencies": {
|
||||
"msnodesqlv8": "^2.0.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ const fs = require('fs-extra');
|
||||
const axios = require('axios');
|
||||
const path = require('path');
|
||||
const { extractPackageName } = require('dbgate-tools');
|
||||
const { pluginsdir, datadir } = require('../utility/directories');
|
||||
const { pluginsdir, datadir, packagedPluginsDir } = require('../utility/directories');
|
||||
const socket = require('../utility/socket');
|
||||
const compareVersions = require('compare-versions');
|
||||
const requirePlugin = require('../shell/requirePlugin');
|
||||
const downloadPackage = require('../utility/downloadPackage');
|
||||
const hasPermission = require('../utility/hasPermission');
|
||||
const _ = require('lodash');
|
||||
|
||||
// async function loadPackageInfo(dir) {
|
||||
// const readmeFile = path.join(dir, 'README.md');
|
||||
@@ -27,19 +28,22 @@ const hasPermission = require('../utility/hasPermission');
|
||||
// };
|
||||
// }
|
||||
|
||||
const preinstallPluginMinimalVersions = {
|
||||
'dbgate-plugin-mssql': '1.2.2',
|
||||
'dbgate-plugin-mysql': '1.2.2',
|
||||
'dbgate-plugin-postgres': '1.2.2',
|
||||
'dbgate-plugin-mongo': '1.0.1',
|
||||
'dbgate-plugin-csv': '1.0.9',
|
||||
'dbgate-plugin-excel': '1.0.8',
|
||||
};
|
||||
// const preinstallPluginMinimalVersions = {
|
||||
// 'dbgate-plugin-mssql': '1.2.2',
|
||||
// 'dbgate-plugin-mysql': '1.2.2',
|
||||
// 'dbgate-plugin-postgres': '1.2.2',
|
||||
// 'dbgate-plugin-mongo': '1.0.1',
|
||||
// 'dbgate-plugin-csv': '1.0.9',
|
||||
// 'dbgate-plugin-excel': '1.0.8',
|
||||
// };
|
||||
|
||||
module.exports = {
|
||||
script_meta: 'get',
|
||||
async script({ packageName }) {
|
||||
const file = path.join(pluginsdir(), packageName, 'dist', 'frontend.js');
|
||||
const file1 = path.join(packagedPluginsDir(), packageName, 'dist', 'frontend.js');
|
||||
const file2 = path.join(pluginsdir(), packageName, 'dist', 'frontend.js');
|
||||
// @ts-ignore
|
||||
const file = (await fs.exists(file1)) ? file1 : file2;
|
||||
const data = await fs.readFile(file, {
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
@@ -63,10 +67,12 @@ module.exports = {
|
||||
const { latest } = infoResp.data['dist-tags'];
|
||||
const manifest = infoResp.data.versions[latest];
|
||||
const { readme } = infoResp.data;
|
||||
const isPackaged = await fs.pathExists(path.join(packagedPluginsDir(), packageName));
|
||||
|
||||
return {
|
||||
readme,
|
||||
manifest,
|
||||
isPackaged,
|
||||
};
|
||||
} catch (err) {
|
||||
return {
|
||||
@@ -88,14 +94,22 @@ module.exports = {
|
||||
|
||||
installed_meta: 'get',
|
||||
async installed() {
|
||||
const files = await fs.readdir(pluginsdir());
|
||||
const files1 = await fs.readdir(packagedPluginsDir());
|
||||
const files2 = await fs.readdir(pluginsdir());
|
||||
|
||||
const res = [];
|
||||
for (const packageName of files) {
|
||||
const manifest = await fs.readFile(path.join(pluginsdir(), packageName, 'package.json')).then(x => JSON.parse(x));
|
||||
for (const packageName of _.union(files1, files2)) {
|
||||
const isPackaged = files1.includes(packageName);
|
||||
const manifest = await fs
|
||||
.readFile(path.join(isPackaged ? packagedPluginsDir() : pluginsdir(), packageName, 'package.json'), {
|
||||
encoding: 'utf-8',
|
||||
})
|
||||
.then(x => JSON.parse(x));
|
||||
const readmeFile = path.join(pluginsdir(), packageName, 'README.md');
|
||||
if (await fs.exists(readmeFile)) {
|
||||
if (await fs.pathExists(readmeFile)) {
|
||||
manifest.readme = await fs.readFile(readmeFile, { encoding: 'utf-8' });
|
||||
}
|
||||
manifest.isPackaged = isPackaged;
|
||||
res.push(manifest);
|
||||
}
|
||||
return res;
|
||||
@@ -106,20 +120,20 @@ module.exports = {
|
||||
// );
|
||||
},
|
||||
|
||||
async saveRemovePlugins() {
|
||||
await fs.writeFile(path.join(datadir(), 'removed-plugins'), this.removedPlugins.join('\n'));
|
||||
},
|
||||
// async saveRemovePlugins() {
|
||||
// await fs.writeFile(path.join(datadir(), 'removed-plugins'), this.removedPlugins.join('\n'));
|
||||
// },
|
||||
|
||||
install_meta: 'post',
|
||||
async install({ packageName }) {
|
||||
if (!hasPermission(`plugins/install`)) return;
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
if (!(await fs.exists(dir))) {
|
||||
if (!(await fs.pathExists(dir))) {
|
||||
await downloadPackage(packageName, dir);
|
||||
}
|
||||
socket.emitChanged(`installed-plugins-changed`);
|
||||
this.removedPlugins = this.removedPlugins.filter(x => x != packageName);
|
||||
await this.saveRemovePlugins();
|
||||
// this.removedPlugins = this.removedPlugins.filter(x => x != packageName);
|
||||
// await this.saveRemovePlugins();
|
||||
},
|
||||
|
||||
uninstall_meta: 'post',
|
||||
@@ -128,7 +142,7 @@ module.exports = {
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
await fs.rmdir(dir, { recursive: true });
|
||||
socket.emitChanged(`installed-plugins-changed`);
|
||||
this.removedPlugins.push(packageName);
|
||||
// this.removedPlugins.push(packageName);
|
||||
await this.saveRemovePlugins();
|
||||
},
|
||||
|
||||
@@ -136,7 +150,7 @@ module.exports = {
|
||||
async upgrade({ packageName }) {
|
||||
if (!hasPermission(`plugins/install`)) return;
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
if (await fs.exists(dir)) {
|
||||
if (await fs.pathExists(dir)) {
|
||||
await fs.rmdir(dir, { recursive: true });
|
||||
await downloadPackage(packageName, dir);
|
||||
}
|
||||
@@ -158,46 +172,46 @@ module.exports = {
|
||||
return content.driver.getAuthTypes() || null;
|
||||
},
|
||||
|
||||
async _init() {
|
||||
const installed = await this.installed();
|
||||
try {
|
||||
this.removedPlugins = (await fs.readFile(path.join(datadir(), 'removed-plugins'), { encoding: 'utf-8' })).split(
|
||||
'\n'
|
||||
);
|
||||
} catch (err) {
|
||||
this.removedPlugins = [];
|
||||
}
|
||||
// async _init() {
|
||||
// const installed = await this.installed();
|
||||
// try {
|
||||
// this.removedPlugins = (await fs.readFile(path.join(datadir(), 'removed-plugins'), { encoding: 'utf-8' })).split(
|
||||
// '\n'
|
||||
// );
|
||||
// } catch (err) {
|
||||
// this.removedPlugins = [];
|
||||
// }
|
||||
|
||||
for (const packageName of Object.keys(preinstallPluginMinimalVersions)) {
|
||||
const installedVersion = installed.find(x => x.name == packageName);
|
||||
if (installedVersion) {
|
||||
// plugin installed, test, whether upgrade
|
||||
const requiredVersion = preinstallPluginMinimalVersions[packageName];
|
||||
if (compareVersions(installedVersion.version, requiredVersion) < 0) {
|
||||
console.log(
|
||||
`Upgrading preinstalled plugin ${packageName}, found ${installedVersion.version}, required version ${requiredVersion}`
|
||||
);
|
||||
await this.upgrade({ packageName });
|
||||
} else {
|
||||
console.log(
|
||||
`Plugin ${packageName} not upgraded, found ${installedVersion.version}, required version ${requiredVersion}`
|
||||
);
|
||||
}
|
||||
// for (const packageName of Object.keys(preinstallPluginMinimalVersions)) {
|
||||
// const installedVersion = installed.find(x => x.name == packageName);
|
||||
// if (installedVersion) {
|
||||
// // plugin installed, test, whether upgrade
|
||||
// const requiredVersion = preinstallPluginMinimalVersions[packageName];
|
||||
// if (compareVersions(installedVersion.version, requiredVersion) < 0) {
|
||||
// console.log(
|
||||
// `Upgrading preinstalled plugin ${packageName}, found ${installedVersion.version}, required version ${requiredVersion}`
|
||||
// );
|
||||
// await this.upgrade({ packageName });
|
||||
// } else {
|
||||
// console.log(
|
||||
// `Plugin ${packageName} not upgraded, found ${installedVersion.version}, required version ${requiredVersion}`
|
||||
// );
|
||||
// }
|
||||
|
||||
continue;
|
||||
}
|
||||
// continue;
|
||||
// }
|
||||
|
||||
if (this.removedPlugins.includes(packageName)) {
|
||||
// plugin was remvoed, don't install again
|
||||
continue;
|
||||
}
|
||||
// if (this.removedPlugins.includes(packageName)) {
|
||||
// // plugin was remvoed, don't install again
|
||||
// continue;
|
||||
// }
|
||||
|
||||
try {
|
||||
console.log('Preinstalling plugin', packageName);
|
||||
await this.install({ packageName });
|
||||
} catch (err) {
|
||||
console.error('Error preinstalling plugin', packageName, err);
|
||||
}
|
||||
}
|
||||
},
|
||||
// try {
|
||||
// console.log('Preinstalling plugin', packageName);
|
||||
// await this.install({ packageName });
|
||||
// } catch (err) {
|
||||
// console.error('Error preinstalling plugin', packageName, err);
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const path = require('path');
|
||||
const { pluginsdir } = require('../utility/directories');
|
||||
const fs = require('fs');
|
||||
const { pluginsdir, packagedPluginsDir } = require('../utility/directories');
|
||||
const nativeModules = require('../nativeModules');
|
||||
const _isRunOnSource = require('../utility/_isRunOnSource');
|
||||
|
||||
const loadedPlugins = {};
|
||||
|
||||
@@ -9,13 +11,25 @@ const dbgateEnv = {
|
||||
nativeModules,
|
||||
};
|
||||
|
||||
function getModulePath(packageName) {
|
||||
const packagedModulePath = _isRunOnSource()
|
||||
? path.join(packagedPluginsDir(), packageName, 'src', 'backend', 'index.js')
|
||||
: path.join(packagedPluginsDir(), packageName, 'dist', 'backend.js');
|
||||
|
||||
if (fs.existsSync(packagedModulePath)) {
|
||||
return packagedModulePath;
|
||||
}
|
||||
|
||||
return path.join(pluginsdir(), packageName, 'dist', 'backend.js');
|
||||
}
|
||||
|
||||
function requirePlugin(packageName, requiredPlugin = null) {
|
||||
if (!packageName) throw new Error('Missing packageName in plugin');
|
||||
if (loadedPlugins[packageName]) return loadedPlugins[packageName];
|
||||
|
||||
if (requiredPlugin == null) {
|
||||
let module;
|
||||
const modulePath = path.join(pluginsdir(), packageName, 'dist', 'backend.js');
|
||||
const modulePath = getModulePath(packageName);
|
||||
console.log(`Loading module ${packageName} from ${modulePath}`);
|
||||
try {
|
||||
// @ts-ignore
|
||||
|
||||
5
packages/api/src/utility/_isRunOnSource.js
Normal file
5
packages/api/src/utility/_isRunOnSource.js
Normal file
@@ -0,0 +1,5 @@
|
||||
function _isRunOnSource() {
|
||||
return __filename.endsWith('_isRunOnSource.js');
|
||||
}
|
||||
|
||||
module.exports = _isRunOnSource;
|
||||
@@ -2,6 +2,7 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const cleanDirectory = require('./cleanDirectory');
|
||||
const _isRunOnSource = require('./_isRunOnSource');
|
||||
|
||||
const createDirectories = {};
|
||||
const ensureDirectory = (dir, clean) => {
|
||||
@@ -39,6 +40,13 @@ const pluginsdir = dirFunc('plugins');
|
||||
const archivedir = dirFunc('archive');
|
||||
const filesdir = dirFunc('files');
|
||||
|
||||
function packagedPluginsDir() {
|
||||
if (_isRunOnSource()) {
|
||||
return path.resolve(__dirname, '../../../../plugins');
|
||||
}
|
||||
return path.resolve(__dirname, '../plugins');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
datadir,
|
||||
jsldir,
|
||||
@@ -48,4 +56,5 @@ module.exports = {
|
||||
ensureDirectory,
|
||||
pluginsdir,
|
||||
filesdir,
|
||||
packagedPluginsDir,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,11 @@
|
||||
<div class="ml-2">
|
||||
<div class="flex">
|
||||
<div class="bold">{packageManifest.name}</div>
|
||||
<div class="ml-1">{packageManifest.version}</div>
|
||||
{#if packageManifest.isPackaged}
|
||||
<div class="ml-1 builtin">(builtin)</div>
|
||||
{:else}
|
||||
<div class="ml-1">{packageManifest.version}</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
{packageManifest.description}
|
||||
@@ -48,4 +52,8 @@
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.builtin {
|
||||
color: var(--theme-font-3);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<script lang="ts">
|
||||
import compareVersions from 'compare-versions';
|
||||
import FormStyledButton from '../elements/FormStyledButton.svelte';
|
||||
import Markdown from '../elements/Markdown.svelte';
|
||||
import Markdown from '../elements/Markdown.svelte';
|
||||
import { extractPluginAuthor, extractPluginIcon } from '../plugins/manifestExtractors';
|
||||
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
@@ -24,6 +24,7 @@ import Markdown from '../elements/Markdown.svelte';
|
||||
});
|
||||
$: readme = $info?.readme;
|
||||
$: manifest = $info?.manifest;
|
||||
$: isPackaged = $info?.isPackaged;
|
||||
|
||||
const handleInstall = async () => {
|
||||
axiosInstance.post('plugins/install', { packageName });
|
||||
@@ -59,17 +60,21 @@ import Markdown from '../elements/Markdown.svelte';
|
||||
<span> | </span>
|
||||
<span>{installedFound ? installedFound.version : manifest.version}</span>
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
{#if hasPermission('plugins/install') && !installedFound}
|
||||
<FormStyledButton type="button" value="Install" on:click={handleInstall} />
|
||||
{/if}
|
||||
{#if hasPermission('plugins/install') && installedFound}
|
||||
<FormStyledButton type="button" value="Uninstall" on:click={handleUninstall} />
|
||||
{/if}
|
||||
{#if hasPermission('plugins/install') && installedFound && onlineFound && compareVersions(onlineFound.version, installedFound.version) > 0}
|
||||
<FormStyledButton type="button" value="Upgrade" on:click={handleUpgrade} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if isPackaged}
|
||||
<div class="mt-2">Plugin is part of DbGate installation</div>
|
||||
{:else}
|
||||
<div class="mt-1">
|
||||
{#if hasPermission('plugins/install') && !installedFound}
|
||||
<FormStyledButton type="button" value="Install" on:click={handleInstall} />
|
||||
{/if}
|
||||
{#if hasPermission('plugins/install') && installedFound}
|
||||
<FormStyledButton type="button" value="Uninstall" on:click={handleUninstall} />
|
||||
{/if}
|
||||
{#if hasPermission('plugins/install') && installedFound && onlineFound && compareVersions(onlineFound.version, installedFound.version) > 0}
|
||||
<FormStyledButton type="button" value="Upgrade" on:click={handleUpgrade} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<Markdown source={readme} />
|
||||
|
||||
Reference in New Issue
Block a user