src/package-manager/index.ts
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/member-delimiter-style */
/* eslint-disable @typescript-eslint/interface-name-prefix */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
IXyoPluginWithConfig,
XyoBase,
IXyoConfig,
IXyoPluginConfig,
IXyoPlugin
} from '@xyo-network/sdk-base-nodejs'
import globalModules from 'global-modules'
import { execSync } from 'child_process'
import fsExtra from 'fs-extra'
const defaultConfig = {
port: 11001,
plugins: []
}
export class XyoPackageManager extends XyoBase {
public pathToConfig: string
private pluginTypes: { [key: string]: (config: any) => Promise<void> } = {}
private pluginTypeInstallers: {
[key: string]: (config: any) => Promise<IXyoPluginWithConfig[]>
} = {}
constructor(pathToConfig: string) {
super()
this.pathToConfig = pathToConfig
this.pluginTypes.npmRemote = npmRemotePluginResolver
this.pluginTypes.npmLocal = npmLocalPluginResolver
this.pluginTypes.path = pathPluginResolver
this.pluginTypeInstallers.path = pathPluginRunner
this.pluginTypeInstallers.npmRemote = npmRemotePluginRunner
this.pluginTypeInstallers.npmLocal = npmLocalPluginRunner
}
public async install() {
const pluginsToInstall = (await this.readConfigFromPath(this.pathToConfig))
.plugins
for (const plugin of pluginsToInstall) {
await this.installPlugin(plugin)
}
}
public async getConfig() {
return this.readConfigFromPath(this.pathToConfig)
}
public async resolve(): Promise<IXyoPluginWithConfig[]> {
const pluginsToRun = (await this.readConfigFromPath(this.pathToConfig))
.plugins
let plugins: IXyoPluginWithConfig[] = []
for (const toRun of pluginsToRun) {
const resolver = this.pluginTypeInstallers[toRun.type]
if (resolver) {
plugins = plugins.concat(await resolver(toRun.config))
}
}
for (const plugin of plugins) {
this.logInfo(`Running with plugin: ${plugin.plugin.getName()}`)
}
return plugins
}
public async makeConfigIfNotExist() {
fsExtra.ensureDirSync(
this.pathToConfig.substring(0, this.pathToConfig.lastIndexOf('/'))
)
if (!fsExtra.existsSync(this.pathToConfig)) {
fsExtra.writeFileSync(this.pathToConfig, JSON.stringify(defaultConfig))
}
}
private async installPlugin(config: IXyoPluginConfig) {
const resolver = this.pluginTypes[config.type]
if (!resolver) {
return undefined
}
await resolver(config.config)
}
private async readConfigFromPath(path: string): Promise<IXyoConfig> {
try {
return require(path) as IXyoConfig
} catch (error) {
console.log(error)
this.logError(`Can not find config at path: ${path}`)
process.exit(1)
throw new Error()
}
}
}
interface INpmRemoteConfig {
packageName: string
version: string
subPlugins: INpmRemoteSubPluginConfig[]
}
interface INpmRemoteLocalConfig {
path: string
subPlugins: INpmRemoteSubPluginConfig[]
}
interface INpmRemoteSubPluginConfig {
name: string
config: any
}
interface IPathConfig {
path: string
config: any
}
const npmRemotePluginResolver = async (config: any) => {
execSync(
`npm install --unsafe-perm -g ${config.packageName}@${config.version}`
).toString('utf8')
installNpmRepository(
`${globalModules}/${config.packageName}`,
config.subPlugins
)
}
const npmLocalPluginResolver = async (config: any) => {
installNpmRepository(config.path, config.subPlugins)
}
const pathPluginResolver = async (config: IPathConfig) => {
try {
const _ = require(config.path) as IXyoPlugin
} catch {
throw new Error(`Can not find plugin at path ${config.path}`)
}
}
const installNpmRepository = (
pathOfNpm: string,
subPlugins: INpmRemoteSubPluginConfig[]
) => {
const xyoPlugins: string[] =
require(`${pathOfNpm}/package.json`).xyoPlugins || []
const pluginsWithConfig: IXyoPluginWithConfig[] = []
const resolvedPlugins: { [key: string]: IXyoPlugin } = {}
for (const pluginPath of xyoPlugins) {
const absPath = `${pathOfNpm}/${pluginPath}`
try {
const plugin = require(absPath) as IXyoPlugin
resolvedPlugins[plugin.getName()] = plugin
} catch {
throw new Error(`Can not find plugin at path ${absPath}`)
}
}
for (const pluginShouldBeFound of subPlugins) {
const didFind = resolvedPlugins[pluginShouldBeFound.name]
if (!didFind) {
throw new Error(
`Can not find plugin with name ${pluginShouldBeFound.name}`
)
}
pluginsWithConfig.push({
plugin: didFind,
config: pluginShouldBeFound.config
})
}
return pluginsWithConfig
}
const npmRemotePluginRunner = async (config: any) => {
return installNpmRepository(
`${globalModules}/${config.packageName}`,
config.subPlugins
)
}
const npmLocalPluginRunner = async (config: any) => {
return installNpmRepository(config.path, config.subPlugins)
}
const pathPluginRunner = async (config: any) => {
try {
const plugin = require(config.path) as IXyoPlugin
const pWC: IXyoPluginWithConfig = {
plugin,
config: config.config
}
return [pWC]
} catch {
throw new Error(`Can not find plugin at path ${config.path}`)
}
}