diff --git a/package.json b/package.json index 47d863002..def00a653 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/packages/api/package.json b/packages/api/package.json index 6d013aa43..e7cfd0741 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -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" } -} \ No newline at end of file +} diff --git a/packages/api/src/controllers/plugins.js b/packages/api/src/controllers/plugins.js index 0ad2fa0c9..3a4e344e7 100644 --- a/packages/api/src/controllers/plugins.js +++ b/packages/api/src/controllers/plugins.js @@ -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); + // } + // } + // }, }; diff --git a/packages/api/src/shell/requirePlugin.js b/packages/api/src/shell/requirePlugin.js index 3eef6cb66..aabb00424 100644 --- a/packages/api/src/shell/requirePlugin.js +++ b/packages/api/src/shell/requirePlugin.js @@ -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 diff --git a/packages/api/src/utility/_isRunOnSource.js b/packages/api/src/utility/_isRunOnSource.js new file mode 100644 index 000000000..5cbed583a --- /dev/null +++ b/packages/api/src/utility/_isRunOnSource.js @@ -0,0 +1,5 @@ +function _isRunOnSource() { + return __filename.endsWith('_isRunOnSource.js'); +} + +module.exports = _isRunOnSource; diff --git a/packages/api/src/utility/directories.js b/packages/api/src/utility/directories.js index f1c41ac50..0f9e3c564 100644 --- a/packages/api/src/utility/directories.js +++ b/packages/api/src/utility/directories.js @@ -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, }; diff --git a/packages/web/src/plugins/PluginsList.svelte b/packages/web/src/plugins/PluginsList.svelte index a957c4c3b..e90c088da 100644 --- a/packages/web/src/plugins/PluginsList.svelte +++ b/packages/web/src/plugins/PluginsList.svelte @@ -23,7 +23,11 @@