From 79c832e4636ba4e5428f7248dfddb976e952329c Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 20 Aug 2019 00:34:24 +0200 Subject: [PATCH] something something git --- package-lock.json | 46 +++++----- package.json | 8 +- src/backend/FrontblockAdmin.ts | 149 ++++++++++++++++++++++++++------- src/backend/GitUpdater.ts | 4 +- src/backend/webpack.prod.js | 47 +++++++++++ 5 files changed, 202 insertions(+), 52 deletions(-) create mode 100644 src/backend/webpack.prod.js diff --git a/package-lock.json b/package-lock.json index dcf7545..8013735 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1415,9 +1415,9 @@ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, "base64id": { @@ -7215,12 +7215,20 @@ } }, "string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } } } } @@ -10554,9 +10562,9 @@ } }, "terser": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.2.tgz", - "integrity": "sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.1.4.tgz", + "integrity": "sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg==", "dev": true, "requires": { "commander": "^2.20.0", @@ -10667,9 +10675,9 @@ } }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "dev": true, "requires": { "setimmediate": "^1.0.4" @@ -11383,9 +11391,9 @@ "dev": true }, "webpack": { - "version": "4.39.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.1.tgz", - "integrity": "sha512-/LAb2TJ2z+eVwisldp3dqTEoNhzp/TLCZlmZm3GGGAlnfIWDgOEE758j/9atklNLfRyhKbZTCOIoPqLJXeBLbQ==", + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -11414,9 +11422,9 @@ }, "dependencies": { "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true } } diff --git a/package.json b/package.json index 54e072d..8e8960b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build-widget": "rollup -c src/frontend/widget/rollup.config.js; mkdir -p plugins/PluginManager; cp FrontendPlugin.js plugins/PluginManager", "clean": "rm -rf lib static plugins data conf dist widget .rpt2_cache *.js *.ts src/frontend/dashboard/dist", "update-frontblock": "rm -rf node_modules/frontblock*; npm install", - "webpack": "webpack --mode production --entry ./dist/FrontblockLib.js --output ./dist/FrontblockLib.js" + "webpack": "webpack --config src/backend/webpack.prod.js --progress --colors" }, "repository": { "type": "git", @@ -88,7 +88,7 @@ "rollup-plugin-typescript2": "^0.10.0", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", - "terser-webpack-plugin": "^1.3.0", + "terser-webpack-plugin": "^1.4.1", "ts-jest": "^24.0.2", "ts-loader": "^5.3.3", "tslint": "^5.18.0", @@ -98,10 +98,10 @@ "typescript-declaration-webpack-plugin": "^0.1.1", "uglifyjs-webpack-plugin": "^2.1.3", "url-loader": "^1.1.2", - "webpack": "^4.35.2", + "webpack": "^4.39.2", "webpack-cli": "^3.3.5" }, "files": [ "lib/**/*" ] -} \ No newline at end of file +} diff --git a/src/backend/FrontblockAdmin.ts b/src/backend/FrontblockAdmin.ts index 4108211..36b4f2a 100644 --- a/src/backend/FrontblockAdmin.ts +++ b/src/backend/FrontblockAdmin.ts @@ -1,15 +1,15 @@ 'use strict' import * as Logger from 'log4js' -import { socketioRPC, ConfigLoader } from 'frontblock-generic/Plugin'; +import { socketioRPC, ConfigLoader, Plugin } from 'frontblock-generic/Plugin'; import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types'; import express = require('express'); import http = require('http'); import bsock = require('bsock'); import { FrontblockCherryPicker } from "git-cherrypicker" import { promises as fs } from "fs" -import { GitUpdater } from "./GitUpdater"; -import * as git from "simple-git/promise" +import { GitUpdater, RepoFolderStatus, } from "./GitUpdater"; +import * as path from "path" const kfs = require("key-file-storage").default('kfs') @@ -70,7 +70,12 @@ export class FrontblockAdmin extends ConfigLoader{ private httpServer private io = bsock.createServer() private wsServer = http.createServer() - private pm + + private dashboardUpdater:GitUpdater + private adminUpdater:GitUpdater + private pluginUpdaters:{[name in string]:GitUpdater} = {} + private loadedPlugins:{[name in string]:Plugin} = {} + constructor(){ super("FrontblockAdmin") @@ -83,29 +88,82 @@ export class FrontblockAdmin extends ConfigLoader{ } private async updateFrontblockLib(){ + logger.warn("Picking FrontblockLib...") await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js") } - private async updateDashboard(){ - const dashboard = new GitUpdater("./static") - const status = await dashboard.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", true) - console.log(status) + private async updateDashboard():Promise{ + logger.warn("Cloning dashboard...") + this.dashboardUpdater = new GitUpdater("./static") + const status = await this.dashboardUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", true) + return(status) } - private async updatePluginmanager(){ - const dashboard = new GitUpdater("./plugins/PluginManager") - const status = await dashboard.cloneRepo("https://gitea.frontblock.me/fb-dist/pluginmanager.git", true) - console.log(status) + private async installPlugin(name: string):Promise{ + logger.warn("Cloning "+name+"...") + this.pluginUpdaters[name] = new GitUpdater("./plugins/"+name) + const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", true) + return status + } + + private async startPlugin(name:string):Promise{ + if(!this.pluginUpdaters[name]) return false + const status = await this.pluginUpdaters[name].getStatus() + if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ + logger.error("Bad repo status", name, status) + return false + } + + if(this.loadedPlugins[name]){ + logger.error("Plugin", name, "is already started") + return false + } + + + let str = "../plugins/"+name+"/Plugin" + const pluginClass = await import(str) + const pluginObj = new pluginClass.default() + await pluginObj.start() + this.loadedPlugins[name] = pluginObj + return true + } + + private async updatePlugin(name:string):Promise{ + if(!this.pluginUpdaters[name]) return false + const status = await this.pluginUpdaters[name].getStatus() + if(!status.exists || status.empty || !status.tags || status.tags.length === 0){ + logger.error("Bad repo status", name, status) + return false + } + if(status.currentTag == status.latestTag){ + logger.warn(name, "already at latest tag") + return false + } + + if(this.loadedPlugins[name]){ + logger.error("Plugin", name, "is running. Stop it first") + return false + } + + this.pluginUpdaters[name].checkoutTag(status.latestTag!) + return true + } + + private async setPluginVersion(pluginName:string, tag:string):Promise{ + const status = await this.pluginUpdaters[pluginName].getStatus() + if(!status.exists || !status.tags || status.tags.length === 0 || !status.tags.includes(tag)){ + logger.error("Bad repo status", pluginName, status) + return status + } + + return await this.pluginUpdaters[pluginName].checkoutTag(tag) } private async initialize(){ await this.updateDashboard() await this.updateFrontblockLib() - await this.updatePluginmanager() - - let str = "../plugins/PluginManager/Plugin" - const PM = await import(str) - this.pm = new PM.default() + await this.installPlugin("PluginManager") + //await this.updatePluginmanager() this.startWebsocket() this.startWebserver() @@ -132,20 +190,55 @@ export class FrontblockAdmin extends ConfigLoader{ } },{ owner: 'Admin', - name: 'installPluginManager', + name: 'installPlugin', + args: 'name', + info: { + type: 'call', + fn: async (name:string) => { + return await this.installPlugin(name) + } + } + },{ + owner: 'Admin', + name: 'startPlugin', + args: 'name', + info: { + type: 'call', + fn: async (name:string) => { + return await this.startPlugin(name) + } + } + },{ + owner: 'PluginManager', + name: 'getLoadedPluginNames', args: '', info: { type: 'call', - fn: () => {} + fn: () => Object.keys(this.loadedPlugins) + } + },{ + owner: 'Admin', + name: 'updatePlugin', + args: 'name', + info: { + type: 'call', + fn: async (name) => {return await this.updatePlugin(name)} + } + },{ + owner: 'Admin', + name: 'setPluginVersion', + args: 'name, tag', + info: { + type: 'call', + fn: async (name, tag) => {return await this.setPluginVersion(name, tag)} } } ] - //translate RPCs to socket-bound function metadata - const loadedPlugins = this.pm.getLoadedPlugins() + const loadedPlugins = this.loadedPlugins for(const name in loadedPlugins){ - loadedPlugins[name].backend.exportRPCs().forEach(rpc => { + loadedPlugins[name].exportRPCs().forEach(rpc => { const info = this.rpcToRpcInfo(name, rpc) rpcInfos.push(info) }) @@ -207,10 +300,6 @@ export class FrontblockAdmin extends ConfigLoader{ }) }) } - - private installPluginManager(){ - - } private startWebserver(){ if(this.httpServer != null || this.express != null){ @@ -225,8 +314,12 @@ export class FrontblockAdmin extends ConfigLoader{ /** * get the compiled FrontendPlugins.js */ - this.express.get('/plugins/:id'+".js", (request, response) => { - let frontend = this.pm.getFrontend(request.params.id) + this.express.get('/plugins/:id'+".js", async (request, response) => { + const pth = path.resolve("plugins/"+request.params.id, "FrontendPlugin.js"); + logger.info("Loading frontend plugin from fs", pth) + const file = await fs.readFile(pth) + const frontend = file.toString() + response.status(200) response.set('Content-Type', 'application/javascript') response.send(frontend) diff --git a/src/backend/GitUpdater.ts b/src/backend/GitUpdater.ts index 8535ac4..e7cc579 100644 --- a/src/backend/GitUpdater.ts +++ b/src/backend/GitUpdater.ts @@ -11,7 +11,7 @@ const rmrf = (path:string, options = {}) => { return new Promise((acc, _) => rimraf(path, options, acc)) } -type RepoFolderStatus = { +export type RepoFolderStatus = { exists: boolean empty: boolean currentTag?: string @@ -53,6 +53,8 @@ export class GitUpdater{ } async cloneRepo(from:string, force:boolean = false):Promise { + if(this.folderPath === "." && force) + throw new Error("refusing to `rm -rf .`: \ncloneRepo(from: "+from+", force: "+force+")") if(force){ await rmrf(this.folderPath) await fs.mkdir(this.folderPath, { recursive: true }); diff --git a/src/backend/webpack.prod.js b/src/backend/webpack.prod.js new file mode 100644 index 0000000..a69f602 --- /dev/null +++ b/src/backend/webpack.prod.js @@ -0,0 +1,47 @@ +const TerserPlugin = require('terser-webpack-plugin'); + +const path = require('path'); + +module.exports = { + optimization: { + minimize: false + }, + mode: 'production', + target: "node", + + entry: path.resolve(__dirname, '../../dist/FrontblockLib.js'), + output: { + path: path.resolve(__dirname, '../../dist'), + filename: 'FrontblockLib.js', + libraryTarget: 'commonjs', + }, + optimization: { + minimizer: [new TerserPlugin({ + cache: true, + parallel: true, + terserOptions:{ + mangle: false, + keep_classnames: true + } + })], + splitChunks: { + cacheGroups: { + common: { + chunks: 'all', + minChunks: 2, + maxInitialRequests: 5, + minSize: 0, + name: 'common' + }, + vendor: { + test: /node_modules/, + chunks: 'all', + name: 'vendor', + priority: 10, + enforce: true, + minChunks: 2 + } + } + } + } +}