0.1.0 move to gitea dist for downloads

This commit is contained in:
peter
2019-08-20 19:30:35 +02:00
parent 79c832e463
commit b140476155
6 changed files with 240 additions and 166 deletions
+15 -138
View File
@@ -2,7 +2,7 @@
import * as Logger from 'log4js'
import { socketioRPC, ConfigLoader, Plugin } from 'frontblock-generic/Plugin';
import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types';
import { ErrorResponse, SuccessResponse, SubscriptionResponse } from 'frontblock-generic/Types';
import express = require('express');
import http = require('http');
import bsock = require('bsock');
@@ -10,21 +10,22 @@ import { FrontblockCherryPicker } from "git-cherrypicker"
import { promises as fs } from "fs"
import { GitUpdater, RepoFolderStatus, } from "./GitUpdater";
import * as path from "path"
import { UpdateManager } from './UpdateManger';
const kfs = require("key-file-storage").default('kfs')
Logger.configure({
appenders:
{
"frontblock-admin": { type: 'stdout' },
"admin": { type: 'stdout' },
//app: { type: 'file', filename: 'application.log' }
},
categories:
{
default: { appenders: [ 'frontblock-admin' ], level: 'debug' }
default: { appenders: [ 'admin' ], level: 'debug' }
}
})
const logger = Logger.getLogger("frontblock-admin")
const logger = Logger.getLogger("admin")
type hookRPC =
{
@@ -70,12 +71,7 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
private httpServer
private io = bsock.createServer()
private wsServer = http.createServer()
private dashboardUpdater:GitUpdater
private adminUpdater:GitUpdater
private pluginUpdaters:{[name in string]:GitUpdater} = {}
private loadedPlugins:{[name in string]:Plugin} = {}
private updateManager:UpdateManager = new UpdateManager()
constructor(){
super("FrontblockAdmin")
@@ -87,83 +83,10 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
return {httpPort: 8080}
}
private async updateFrontblockLib(){
logger.warn("Picking FrontblockLib...")
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
}
private async updateDashboard():Promise<RepoFolderStatus>{
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 installPlugin(name: string):Promise<RepoFolderStatus>{
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<boolean>{
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<boolean>{
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<RepoFolderStatus>{
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.installPlugin("PluginManager")
//await this.updatePluginmanager()
await this.updateManager.updateAdmin()
await this.updateManager.updateDashboard()
await this.updateManager.updateFrontblockLib()
this.startWebsocket()
this.startWebserver()
@@ -188,61 +111,15 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
type:'call',
fn: () => { return rpcInfos }
}
},{
owner: 'Admin',
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: () => 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.loadedPlugins
for(const name in loadedPlugins){
loadedPlugins[name].exportRPCs().forEach(rpc => {
const info = this.rpcToRpcInfo(name, rpc)
rpcInfos.push(info)
})
}
const loadedPlugins:Plugin[] = [this.updateManager, ...this.updateManager.getLoadedPlugins()]
loadedPlugins.forEach(plugin => plugin.exportRPCs().forEach(rpc => {
const info = this.rpcToRpcInfo(plugin.name, rpc)
rpcInfos.push(info)
}))
//Hook up all the functions
for(const api of rpcInfos){
@@ -405,7 +282,7 @@ export class FrontblockAdmin extends ConfigLoader<AdminConf>{
*
* Note callbacks *need* to accept a singular argument and they have to be the last parameter!
*/
hookGenerator = (rpc:socketioRPC) => {
hookGenerator = (rpc:socketioRPC): (socket)=>(...args:any[])=>Promise<SubscriptionResponse> => {
const argsArr = this.extractArgs(rpc.rpc).split(',')
argsArr.pop()
const args = argsArr.join(',')
+31 -25
View File
@@ -1,10 +1,23 @@
"use strict";
import { assert } from "bsert"
import * as git from "simple-git/promise"
import * as gyt from "git-describe"
import { promises as fs, mkdirSync } from "fs"
import * as rimraf from "rimraf"
import * as path from "path"
import * as Logger from 'log4js'
Logger.configure({
appenders:
{
"admin/gitupdater": { type: 'stdout' },
//app: { type: 'file', filename: 'application.log' }
},
categories:
{
default: { appenders: [ 'admin/gitupdater' ], level: 'debug' }
}
})
const logger = Logger.getLogger("admin/gitupdater")
const rmrf = (path:string, options = {}) => {
@@ -17,6 +30,7 @@ export type RepoFolderStatus = {
currentTag?: string
tags?: string[]
latestTag?: string
remote?: string
}
export class GitUpdater{
@@ -41,6 +55,11 @@ export class GitUpdater{
await this.repo.fetch("origin", "master", {
"--tags": null
});
const remoteInfo = await this.repo.getRemotes(true)
let remoteURL
if(remoteInfo.length != 0){
remoteURL = remoteInfo.find(i => i.name === "origin").refs.fetch
}
const remoteTags = await this.repo.tags();
const desc = await gyt.gitDescribe(this.folderPath, { match: "*" });
return {
@@ -48,19 +67,22 @@ export class GitUpdater{
empty: empty,
currentTag: !desc.tag?null:desc.tag,
tags: !remoteTags.all?[]:remoteTags.all,
latestTag: remoteTags.latest
latestTag: remoteTags.latest,
remote: remoteURL
};
}
async cloneRepo(from:string, force:boolean = false):Promise<RepoFolderStatus> {
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 });
}
const status = await this.getStatus()
assert(status.exists && status.empty)
if(!status.exists || !status.empty){
logger.error("The folder "+this.folderPath+" doesn't exist or is not empty. Not cloning! Pass the force parameter to override this check")
logger.error(status)
return status
}
await git(this.folderPath).clone(from, path.resolve(this.folderPath));
return await this.getStatus();
@@ -68,27 +90,11 @@ export class GitUpdater{
async checkoutTag(tag:string):Promise<RepoFolderStatus> {
const status = await this.getStatus()
assert(status.exists && status.tags && status.tags.length !== 0)
if(!status.exists || !status.tags || status.tags.length === 0){
logger.error("Unable to check out tag", tag, status)
return status
}
await this.repo.checkout(tag);
return await this.getStatus();
}
}
/*
(async () => {
const staticPath = path.join(__dirname, "..", "static")
const gl = new GitUpdater(staticPath)
let status = await gl.getStatus()
console.log(status)
if(status.empty){
status = await gl.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git")
console.log(status)
}
status = await gl.checkoutTag(status.latestTag!)
console.log(status)
})()
*/
+166
View File
@@ -0,0 +1,166 @@
import { Plugin, socketioRPC } from "frontblock-generic/Plugin";
import { GitUpdater, RepoFolderStatus } from "./GitUpdater";
import { FrontblockCherryPicker } from "git-cherrypicker";
import * as Logger from 'log4js'
Logger.configure({
appenders:
{
"admin/updatemanager": { type: 'stdout' },
//app: { type: 'file', filename: 'application.log' }
},
categories:
{
default: { appenders: [ 'admin/updatemanager' ], level: 'debug' }
}
})
const logger = Logger.getLogger("admin/updatemanager")
export class UpdateManager implements Plugin{
name: string = "UpdateManager"
private loadedPlugins:{[name in string]:Plugin} = {}
private dashboardUpdater:GitUpdater
private adminUpdater:GitUpdater
private pluginUpdaters:{[name in string]:GitUpdater} = {}
getDefaultConfig(): void {
return
}
exportRPCs(): socketioRPC[] {
return [{
name: 'installPlugin',
rpc: async (name:string) => {return await this.installPlugin(name)},
type: 'call',
visibility: 'private'
},{
name: 'startPlugin',
rpc: async (name:string) => {return await this.startPlugin(name)},
type: 'call',
visibility: 'private'
},{
name: 'updatePlugin',
rpc: async (name) => {return await this.updatePlugin(name)},
type: 'call',
visibility: 'private'
},{
name: 'setPluginVersion',
rpc: async (name, tag) => {return await this.setPluginVersion(name, tag)},
type: 'call',
visibility: 'private'
},{
name: 'updateDashboard',
rpc: async () => {return await this.updateDashboard()},
type: 'call',
visibility: 'private'
},{
name: 'getLoadedPluginNames',
rpc: async () => {return await this.getLoadedPluginNames()},
type: 'call',
visibility: 'private'
}]
}
async updateAdmin(force:boolean = false){
this.adminUpdater = new GitUpdater("./dist")
let status = await this.adminUpdater.getStatus()
if(force || !status.remote || !status.remote.includes("fb-dist/admin") || !status.exists || status.empty || !status.currentTag){
logger.warn("Cloning fb-dist/admin into ./dist ..."+(force?" USING FORCE!":""))
status = await this.adminUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/admin.git", force)
}
return status
}
async updateFrontblockLib(){
logger.warn("Picking FrontblockLib...")
await (new FrontblockCherryPicker("fb-dist/admin", "master", "FrontblockLib.js")).write("./static/FrontblockLib.js")
}
async updateDashboard(force:boolean = false):Promise<RepoFolderStatus>{
this.dashboardUpdater = new GitUpdater("./static")
let status = await this.dashboardUpdater.getStatus()
if(force || !status.exists || status.empty || !status.currentTag){
logger.warn("Cloning fb-dist/dashboard into ./static ..."+(force?" USING FORCE!":""))
status = await this.dashboardUpdater.cloneRepo("https://gitea.frontblock.me/fb-dist/dashboard.git", force)
}
return status
}
async installPlugin(name: string, force:boolean = false):Promise<RepoFolderStatus>{
logger.warn("Cloning fb-dist/"+name+".git into ./plugins/"+name+" ..."+(force?" USING FORCE!":""))
this.pluginUpdaters[name] = new GitUpdater("./plugins/"+name)
const status = await this.pluginUpdaters[name].cloneRepo("https://gitea.frontblock.me/fb-dist/"+name.toLowerCase()+".git", force)
return status
}
async startPlugin(name:string):Promise<boolean>{
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
}
async updatePlugin(name:string):Promise<boolean>{
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
}
async setPluginVersion(pluginName:string, tag:string):Promise<RepoFolderStatus>{
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)
}
getLoadedPlugins():Plugin[]{
return Object.values(this.loadedPlugins)
}
getLoadedPluginNames():string[]{
return Object.keys(this.loadedPlugins)
}
start(): void | Promise<void> {
throw new Error("Method not implemented (on purpose)");
}
stop(): void | Promise<void> {
throw new Error("Method not implemented (on purpose)");
}
}