mirror of https://github.com/onivim/oni.git
* Add prettierignore * Add yarn * Hook up yarn script to plugin installer * Initial implementation of plugin installer * Fix lint issues
This commit is contained in:
parent
3e397df022
commit
f4e627007e
|
@ -1,2 +1,3 @@
|
||||||
package.json
|
package.json
|
||||||
vim/core/oni-plugin-typescript/package.json
|
vim/core/oni-plugin-typescript/package.json
|
||||||
|
lib/yarn/*
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* PluginInstaller.ts
|
||||||
|
*
|
||||||
|
* Responsible for installing, updating, and uninstalling plugins.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from "fs"
|
||||||
|
import * as path from "path"
|
||||||
|
|
||||||
|
import { Event, IEvent } from "oni-types"
|
||||||
|
|
||||||
|
// import * as Oni from "oni-api"
|
||||||
|
|
||||||
|
import { getUserConfigFolderPath } from "./../Services/Configuration"
|
||||||
|
// import { IContributions } from "./Api/Capabilities"
|
||||||
|
|
||||||
|
// import { AnonymousPlugin } from "./AnonymousPlugin"
|
||||||
|
// import { Plugin } from "./Plugin"
|
||||||
|
|
||||||
|
import { FileSystem, IFileSystem } from "./../Services/Explorer/ExplorerFileSystem"
|
||||||
|
|
||||||
|
import Process from "./Api/Process"
|
||||||
|
|
||||||
|
import * as Log from "./../Log"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin identifier:
|
||||||
|
* - For _git_, this should be of the form `welle/targets.vim`
|
||||||
|
* - For _npm_, this should be the name of the module, `oni-plugin-tslint`
|
||||||
|
*/
|
||||||
|
export type PluginIdentifier = string
|
||||||
|
|
||||||
|
export interface IPluginInstallerOperationEvent {
|
||||||
|
type: "install" | "uninstall"
|
||||||
|
identifier: string
|
||||||
|
error?: Error
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPluginInstaller {
|
||||||
|
onOperationStarted: IEvent<IPluginInstallerOperationEvent>
|
||||||
|
onOperationCompleted: IEvent<IPluginInstallerOperationEvent>
|
||||||
|
onOperationError: IEvent<IPluginInstallerOperationEvent>
|
||||||
|
|
||||||
|
install(pluginInfo: PluginIdentifier): Promise<void>
|
||||||
|
uninstall(pluginInfo: PluginIdentifier): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class YarnPluginInstaller implements IPluginInstaller {
|
||||||
|
private _onOperationStarted = new Event<IPluginInstallerOperationEvent>()
|
||||||
|
private _onOperationCompleted = new Event<IPluginInstallerOperationEvent>()
|
||||||
|
private _onOperationError = new Event<IPluginInstallerOperationEvent>()
|
||||||
|
|
||||||
|
public get onOperationStarted(): IEvent<IPluginInstallerOperationEvent> {
|
||||||
|
return this._onOperationStarted
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onOperationCompleted(): IEvent<IPluginInstallerOperationEvent> {
|
||||||
|
return this._onOperationCompleted
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onOperationError(): IEvent<IPluginInstallerOperationEvent> {
|
||||||
|
return this._onOperationError
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private _fileSystem: IFileSystem = new FileSystem(fs)) {}
|
||||||
|
|
||||||
|
public async install(identifier: string): Promise<void> {
|
||||||
|
const eventInfo: IPluginInstallerOperationEvent = {
|
||||||
|
type: "install",
|
||||||
|
identifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._onOperationStarted.dispatch(eventInfo)
|
||||||
|
await this._ensurePackageJsonIsCreated()
|
||||||
|
await this._runYarnCommand("add", [identifier])
|
||||||
|
this._onOperationCompleted.dispatch(eventInfo)
|
||||||
|
} catch (ex) {
|
||||||
|
this._onOperationError.dispatch({
|
||||||
|
...eventInfo,
|
||||||
|
error: ex,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async uninstall(identifier: string): Promise<void> {
|
||||||
|
const eventInfo: IPluginInstallerOperationEvent = {
|
||||||
|
type: "uninstall",
|
||||||
|
identifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._onOperationStarted.dispatch(eventInfo)
|
||||||
|
await this._runYarnCommand("remove", [identifier])
|
||||||
|
this._onOperationCompleted.dispatch(eventInfo)
|
||||||
|
} catch (ex) {
|
||||||
|
this._onOperationError.dispatch({
|
||||||
|
...eventInfo,
|
||||||
|
error: ex,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _ensurePackageJsonIsCreated(): Promise<void> {
|
||||||
|
const packageJsonFile = this._getPackageJsonFile()
|
||||||
|
Log.info(
|
||||||
|
`[YarnPluginInstaller::_ensurePackageJsonIsCreated] - checking file: ${packageJsonFile}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
const doesPackageFileExist = await this._fileSystem.exists(packageJsonFile)
|
||||||
|
|
||||||
|
if (!doesPackageFileExist) {
|
||||||
|
Log.info(
|
||||||
|
`[YarnPluginInstaller::_ensurePackageJsonIsCreated] - package file does not exist, initializing.`,
|
||||||
|
)
|
||||||
|
await this._runYarnCommand("init", ["-y"])
|
||||||
|
Log.info(
|
||||||
|
`[YarnPluginInstaller::_ensurePackageJsonIsCreated] - package file created successfully.`,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Log.info(
|
||||||
|
`[YarnPluginInstaller::_ensurePackageJsonIsCreated] - package file is available.`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _runYarnCommand(command: string, args: string[]): Promise<void> {
|
||||||
|
const yarnPath = this._getYarnPath()
|
||||||
|
|
||||||
|
const workingDirectory = getUserConfigFolderPath()
|
||||||
|
const pluginDirectory = this._getPluginsFolder()
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
Process.execNodeScript(
|
||||||
|
yarnPath,
|
||||||
|
["--modules-folder", pluginDirectory, "--production", "true", command, ...args],
|
||||||
|
{ cwd: workingDirectory },
|
||||||
|
(err: any, stdout: string, stderr: string) => {
|
||||||
|
if (err) {
|
||||||
|
Log.error("Error installing: " + stderr)
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getPackageJsonFile(): string {
|
||||||
|
return path.join(getUserConfigFolderPath(), "package.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getPluginsFolder(): string {
|
||||||
|
return path.join(getUserConfigFolderPath(), "plugins")
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getYarnPath(): string {
|
||||||
|
return path.join(__dirname, "lib", "yarn", "yarn-1.5.1.js")
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,16 +15,23 @@ const extensionsRoot = path.join(__dirname, "extensions")
|
||||||
|
|
||||||
import { flatMap } from "./../Utility"
|
import { flatMap } from "./../Utility"
|
||||||
|
|
||||||
|
import { IPluginInstaller, YarnPluginInstaller } from "./PluginInstaller"
|
||||||
|
|
||||||
export class PluginManager implements Oni.IPluginManager {
|
export class PluginManager implements Oni.IPluginManager {
|
||||||
private _rootPluginPaths: string[] = []
|
private _rootPluginPaths: string[] = []
|
||||||
private _plugins: Plugin[] = []
|
private _plugins: Plugin[] = []
|
||||||
private _anonymousPlugin: AnonymousPlugin
|
private _anonymousPlugin: AnonymousPlugin
|
||||||
private _pluginsActivated: boolean = false
|
private _pluginsActivated: boolean = false
|
||||||
|
private _installer: IPluginInstaller = new YarnPluginInstaller()
|
||||||
|
|
||||||
public get plugins(): Plugin[] {
|
public get plugins(): Plugin[] {
|
||||||
return this._plugins
|
return this._plugins
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get installer(): IPluginInstaller {
|
||||||
|
return this._installer
|
||||||
|
}
|
||||||
|
|
||||||
constructor(private _config: Configuration) {}
|
constructor(private _config: Configuration) {}
|
||||||
|
|
||||||
public discoverPlugins(): void {
|
public discoverPlugins(): void {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { FolderOrFile } from "./ExplorerStore"
|
||||||
*/
|
*/
|
||||||
export interface IFileSystem {
|
export interface IFileSystem {
|
||||||
readdir(fullPath: string): Promise<FolderOrFile[]>
|
readdir(fullPath: string): Promise<FolderOrFile[]>
|
||||||
|
exists(fullPath: string): Promise<boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileSystem implements IFileSystem {
|
export class FileSystem implements IFileSystem {
|
||||||
|
@ -40,4 +41,12 @@ export class FileSystem implements IFileSystem {
|
||||||
|
|
||||||
return Promise.resolve(filesAndFolders)
|
return Promise.resolve(filesAndFolders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public exists(fullPath: string): Promise<boolean> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this._fs.exists(fullPath, (exists: boolean) => {
|
||||||
|
resolve(exists)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue