2017-04-15 16:20:18 +03:00
|
|
|
import * as fs from 'fs-promise'
|
|
|
|
import * as path from 'path'
|
2017-05-01 14:35:26 +03:00
|
|
|
const nodeModule = require('module')
|
|
|
|
const nodeRequire = (global as any).require
|
2017-04-17 15:57:22 +03:00
|
|
|
|
2017-06-24 00:52:51 +03:00
|
|
|
declare function delay (ms: number): Promise<void>
|
|
|
|
|
2017-04-17 15:57:22 +03:00
|
|
|
function normalizePath (path: string): string {
|
|
|
|
const cygwinPrefix = '/cygdrive/'
|
|
|
|
if (path.startsWith(cygwinPrefix)) {
|
|
|
|
path = path.substring(cygwinPrefix.length).replace('/', '\\')
|
|
|
|
path = path[0] + ':' + path.substring(1)
|
|
|
|
}
|
|
|
|
return path
|
2017-05-01 14:35:26 +03:00
|
|
|
}
|
2017-04-17 15:57:22 +03:00
|
|
|
|
2017-05-01 14:35:26 +03:00
|
|
|
nodeRequire.main.paths.map(x => nodeModule.globalPaths.push(normalizePath(x)))
|
2017-04-30 20:21:53 +03:00
|
|
|
|
|
|
|
if (process.env.DEV) {
|
|
|
|
nodeModule.globalPaths.unshift(path.dirname(require('electron').remote.app.getAppPath()))
|
|
|
|
}
|
|
|
|
|
2017-06-01 23:23:36 +03:00
|
|
|
const builtinPluginsPath = path.join(
|
2017-04-30 20:21:53 +03:00
|
|
|
path.dirname(require('electron').remote.app.getPath('exe')),
|
2017-05-14 14:45:14 +03:00
|
|
|
(process.platform === 'darwin') ? '../Resources' : 'resources',
|
2017-06-10 01:29:16 +03:00
|
|
|
'builtin-plugins',
|
2017-06-01 23:23:36 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const userPluginsPath = path.join(
|
2017-04-30 20:21:53 +03:00
|
|
|
require('electron').remote.app.getPath('appData'),
|
|
|
|
'terminus',
|
|
|
|
'plugins',
|
2017-06-01 23:23:36 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
Object.assign(window, { builtinPluginsPath, userPluginsPath })
|
|
|
|
nodeModule.globalPaths.unshift(builtinPluginsPath)
|
2017-06-03 18:11:38 +03:00
|
|
|
nodeModule.globalPaths.unshift(path.join(userPluginsPath, 'node_modules'))
|
2017-04-15 16:20:18 +03:00
|
|
|
|
|
|
|
if (process.env.TERMINUS_PLUGINS) {
|
2017-04-17 15:57:22 +03:00
|
|
|
process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.unshift(normalizePath(x)))
|
2017-04-15 16:20:18 +03:00
|
|
|
}
|
|
|
|
|
2017-04-24 01:34:07 +03:00
|
|
|
export declare type ProgressCallback = (current, total) => void
|
|
|
|
|
2017-06-01 23:23:36 +03:00
|
|
|
export interface IPluginInfo {
|
2017-04-24 01:34:07 +03:00
|
|
|
name: string
|
2017-06-01 23:23:36 +03:00
|
|
|
description: string
|
|
|
|
packageName: string
|
|
|
|
isBuiltin: boolean
|
|
|
|
version: string
|
|
|
|
homepage?: string
|
|
|
|
path?: string
|
|
|
|
info?: any
|
2017-04-24 01:34:07 +03:00
|
|
|
}
|
|
|
|
|
2017-06-01 23:23:36 +03:00
|
|
|
export async function findPlugins (): Promise<IPluginInfo[]> {
|
2017-04-17 15:57:22 +03:00
|
|
|
let paths = nodeModule.globalPaths
|
2017-06-01 23:23:36 +03:00
|
|
|
let foundPlugins: IPluginInfo[] = []
|
2017-04-24 01:34:07 +03:00
|
|
|
|
2017-04-15 16:20:18 +03:00
|
|
|
for (let pluginDir of paths) {
|
2017-04-17 15:57:22 +03:00
|
|
|
pluginDir = normalizePath(pluginDir)
|
2017-04-15 16:20:18 +03:00
|
|
|
if (!await fs.exists(pluginDir)) {
|
|
|
|
continue
|
|
|
|
}
|
2017-04-24 01:34:07 +03:00
|
|
|
let pluginNames = await fs.readdir(pluginDir)
|
2017-04-24 22:26:59 +03:00
|
|
|
for (let pluginName of pluginNames.filter(x => /^terminus-/.exec(x))) {
|
|
|
|
let pluginPath = path.join(pluginDir, pluginName)
|
|
|
|
let infoPath = path.join(pluginPath, 'package.json')
|
|
|
|
if (!await fs.exists(infoPath)) {
|
|
|
|
continue
|
|
|
|
}
|
2017-04-30 20:21:53 +03:00
|
|
|
|
|
|
|
if (foundPlugins.some(x => x.name === pluginName)) {
|
|
|
|
console.info(`Plugin ${pluginName} already exists`)
|
|
|
|
}
|
|
|
|
|
2017-04-24 22:26:59 +03:00
|
|
|
try {
|
2017-06-01 23:23:36 +03:00
|
|
|
let info = await fs.readJson(infoPath)
|
|
|
|
console.log(pluginDir, builtinPluginsPath)
|
2017-04-24 22:26:59 +03:00
|
|
|
foundPlugins.push({
|
2017-06-01 23:23:36 +03:00
|
|
|
name: pluginName.substring('terminus-'.length),
|
|
|
|
packageName: pluginName,
|
|
|
|
isBuiltin: pluginDir === builtinPluginsPath,
|
|
|
|
version: info.version,
|
|
|
|
description: info.description,
|
2017-04-24 22:26:59 +03:00
|
|
|
path: pluginPath,
|
2017-06-01 23:23:36 +03:00
|
|
|
info,
|
2017-04-24 22:26:59 +03:00
|
|
|
})
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Cannot load package info for', pluginName)
|
|
|
|
}
|
|
|
|
}
|
2017-04-15 16:20:18 +03:00
|
|
|
}
|
2017-04-24 22:26:59 +03:00
|
|
|
|
2017-06-01 23:23:36 +03:00
|
|
|
(window as any).installedPlugins = foundPlugins
|
2017-04-24 22:26:59 +03:00
|
|
|
return foundPlugins
|
|
|
|
}
|
|
|
|
|
2017-06-01 23:23:36 +03:00
|
|
|
export async function loadPlugins (foundPlugins: IPluginInfo[], progress: ProgressCallback): Promise<any[]> {
|
2017-04-24 22:26:59 +03:00
|
|
|
let plugins: any[] = []
|
|
|
|
progress(0, 1)
|
2017-04-28 23:40:58 +03:00
|
|
|
let index = 0
|
|
|
|
for (let foundPlugin of foundPlugins) {
|
2017-05-01 14:35:26 +03:00
|
|
|
console.info(`Loading ${foundPlugin.name}: ${nodeRequire.resolve(foundPlugin.path)}`)
|
2017-04-24 01:34:07 +03:00
|
|
|
progress(index, foundPlugins.length)
|
|
|
|
try {
|
2017-05-01 14:35:26 +03:00
|
|
|
let pluginModule = nodeRequire(foundPlugin.path)
|
2017-04-24 01:34:07 +03:00
|
|
|
plugins.push(pluginModule)
|
|
|
|
} catch (error) {
|
|
|
|
console.error(`Could not load ${foundPlugin.name}:`, error)
|
|
|
|
}
|
2017-04-28 23:40:58 +03:00
|
|
|
await delay(1)
|
|
|
|
index++
|
|
|
|
}
|
2017-04-24 01:34:07 +03:00
|
|
|
progress(1, 1)
|
2017-04-15 16:20:18 +03:00
|
|
|
return plugins
|
|
|
|
}
|