still gets better

This commit is contained in:
Daniel Hübleitner
2019-08-27 04:04:17 +02:00
parent 48b3951a28
commit f6f7faec22
3 changed files with 383 additions and 92 deletions
+115 -83
View File
@@ -9,6 +9,8 @@ import { FrontblockAdmin } from "./FrontblockAdmin";
import { TableDefiniton } from "frontblock-generic/Admin";
import { promises as fs, mkdirSync as mkdir } from "fs"
import { version } from "punycode";
import * as git from "simple-git/promise"
import * as trash from "trash"
var exec = require('child-process-promise').exec;
@@ -45,8 +47,8 @@ const SharedStatus = <Status>
type SharedStatus = {
name: string
installed: boolean
outdated: boolean
installed?: boolean
outdated?: boolean
}
abstract class Extension<Status extends SharedStatus>{
@@ -55,80 +57,91 @@ abstract class Extension<Status extends SharedStatus>{
){}
/**
* promises the generic Status object
* the generic Status object
*/
abstract async status():Promise<Status>
protected async status():Promise<Status>{
const installed = await this.isInstalled()
const outdated = await this.isOutdated()
return <Status>{ name: this.name, installed: installed, outdated: outdated }
}
/**
* promises a boolean.
* true => isInstalled should be true afterwards
* false => an error happend and nothing was installed
* true => extension was installed
* false => extension was not install
* undefined => signals error
*/
abstract async install():Promise<boolean>
abstract async install():Promise<boolean | undefined>
/**
* promises a boolean.
* true => isInstalled should be false afterwards
* false => the function was not able to bring this plugin into an uninstalled state!!!
* reverts the install procedure
*/
abstract async uninstall():Promise<boolean>
abstract async uninstall():Promise<void>
/**
* promises a boolean.
* true => an update was performed
* false => no update was performed
* undefined => signals error
*/
abstract async update(): Promise<boolean>
abstract async update(force?: boolean): Promise<boolean | undefined>
/**
* promises a boolean
* true => update would install a newer version
* false => nothing would happen if update would be called
* false => nothing would be updated if update would be performed
* undefined => signals error
*/
abstract async isOutdated():Promise<boolean>
abstract async isOutdated():Promise<boolean | undefined>
/**
* promises a boolean
* true => install would do nothing would it be called
* false => install would try to install the newest extension
* undefined => signals error
*/
abstract async isInstalled():Promise<boolean>
abstract async isInstalled():Promise<boolean | undefined>
}
export type FSStatus = SharedStatus & {
prefix: string
empty: boolean
empty?: boolean
}
export abstract class FSExtension<Status extends FSStatus> extends Extension<FSStatus>{
export abstract class FSExtension<Status extends FSStatus> extends Extension<Status>{
constructor(
name: string,
protected readonly prefix: string){
super(name)
logger.debug('Creating extension directory', path.resolve(prefix, name))
mkdir(path.resolve(prefix, name))
}
public async status(): Promise<Status | FSStatus>{
const installed = await this.isInstalled()
const outdated = await this.isOutdated()
public async status(): Promise<Status>{
const shdStatus = await super.status()
const empty = await this.isEmpty()
return {
name: this.name,
prefix: this.prefix,
installed: installed,
outdated: outdated,
empty: empty
return <Status>{...shdStatus, prefix: this.prefix, empty: empty}
}
public async install():Promise<boolean>{
const installed = await this.isInstalled()
if (!installed) {
logger.info('Installing extension to', path.resolve(this.prefix, this.name))
mkdir(path.resolve(this.prefix, this.name), {recursive: true})
return true
}
logger.warn('Extension already installed at', path.resolve(this.prefix, this.name))
return false
}
public async uninstall(): Promise<boolean>{
return await rmrf(path.resolve(this.prefix, this.name))
public async uninstall(): Promise<void>{
logger.info('Uninstalling extension from', path.resolve(this.prefix, this.name))
return await trash(path.resolve(this.prefix, this.name))
}
public async isEmpty(): Promise<boolean>{
if (!this.isInstalled) return false
else {
const files = await fs.readdir(this.prefix)
public async isEmpty(): Promise<boolean | undefined>{
if (!this.isInstalled()) return true
try {
const files = await fs.readdir(path.resolve(this.prefix, this.name))
return files.length === 0
} catch (error) {
logger.warn('TODO')
return
}
}
@@ -159,28 +172,8 @@ export class NPMExtension extends FSExtension<NPMStatus>{
public async status(): Promise<NPMStatus> {
const fsStatus = await super.status()
const {
latestError,
latest,
latestStdErr } = await exec('npm view --prefix ' + this.prefix + ' ' + this.name + " version")
if(latestError){
logger.warn(latestStdErr)
return fsStatus
}
const {
authorError,
author,
authorStdErr } = await exec('npm author ls --prefix ' + this.prefix + ' ' + this.name)
if(authorError){
logger.warn(authorStdErr)
return {
...fsStatus,
latest: latest}
}
const latest = await this.getLatest()
const author = await this.getAuthor()
return {
...fsStatus,
latest: latest,
@@ -189,6 +182,7 @@ export class NPMExtension extends FSExtension<NPMStatus>{
}
public async install(): Promise<boolean> {
super.install()
logger.info("npm install", this.name, 'to', path.resolve(this.prefix, this.name))
const { error, stdout, stderr } = await exec('npm install --prefix '+ this.prefix + ' ' + this.name)
if (error !== null) {
@@ -200,22 +194,21 @@ export class NPMExtension extends FSExtension<NPMStatus>{
}
}
public async uninstall(): Promise<boolean> {
public async uninstall(): Promise<void> {
super.uninstall()
logger.info("npm uninstall", this.name, 'from', path.resolve(this.prefix, this.name))
const { error, stdout, stderr } = await exec('npm uninstall --prefix '+ this.prefix + ' ' + this.name)
if (error !== null) {
if (error) {
logger.warn('npm uninstall', this.name, 'from prefix', this.prefix, 'stderr:', stderr)
return false
} else {
logger.info('npm uninstall', this.name, 'from prefix', this.prefix, 'stdout:', stdout)
return true
}
}
public async update(): Promise<boolean> {
logger.info("npm update", path.resolve(this.prefix, this.name))
const { error, stdout, stderr } = await exec('npm update --prefix '+ this.prefix + ' ' + this.name)
if (error !== null) {
if (error) {
logger.warn('npm update', this.name, 'from prefix', this.prefix, 'stderr:', stderr)
return false
} else {
@@ -224,26 +217,48 @@ export class NPMExtension extends FSExtension<NPMStatus>{
}
}
public async isOutdated(): Promise<boolean> {
public async isOutdated(): Promise<boolean | undefined> {
try {
const {
error,
stdout,
stderr } = await exec('npm outdated --prefix ' + this.prefix + " --json" + ' ' + this.name)
if (error){
logger.warn(stderr)
return false
}
const status = JSON.parse(stdout)
if (status){
const outdated = (Object.keys(status).length > 0)
if (outdated){
return true
}
}
return false
if (error) throw new Error(stderr)
if (Object.keys(JSON.parse(stdout)).length > 0) return true
else return false
} catch (error) {
return false
logger.warn('npm outdated', this.name, 'from prefix', this.prefix, 'stderr:', error)
return
}
}
private async getAuthor(): Promise<string | undefined>{
const {
error,
stdout,
stderr } = await exec('npm author ls --prefix ' + this.prefix + ' ' + this.name)
if(error){
logger.warn(stderr)
return
} else {
logger.info(stdout)
return stdout
}
}
private async getLatest(): Promise<string | undefined>{
const {
error,
stdout,
stderr } = await exec('npm view --prefix ' + this.prefix + ' ' + this.name + " version")
if(error){
logger.warn(stderr)
return
} else {
logger.info(stdout)
return stdout
}
}
}
@@ -254,21 +269,38 @@ export type GitStatus = FSStatus & {
latest?: string
}
export class GitExtension extends FSExtension<GitStatus>{
export class GitExtension<Status extends GitStatus> extends FSExtension<Status>{
protected repo: git.SimpleGit
constructor(
name:string,
prefix:string,
protected gitCloneURL: URL
protected gitCloneURL: string,
protected credentials?: [string, string]
){
super(name, version)
}
public async status(): Promise<GitStatus>{
//TODO tomorrow
public async status(): Promise<Status>{
const fsStatus = await super.status()
return {
...fsStatus,
branch: 'wat',
remote: this.gitCloneURL,
latest: 'kek'
}
}
public async install(): Promise<boolean> {
return true
if (!this.isInstalled()){
if (this.credentials){
} else {
}
} else {
}
}