Browse Source

bundle NPM with Terminus (fixes #584, fixes #10)

Eugene Pankov 6 years ago
parent
commit
59d1a2fc23

+ 4 - 3
terminus-plugin-manager/package.json

@@ -31,13 +31,14 @@
     "@angular/forms": "4.0.1",
     "@angular/platform-browser": "4.0.1",
     "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22",
+    "rxjs": "5.3.0",
     "terminus-core": "*",
-    "terminus-settings": "*",
-    "rxjs": "5.3.0"
+    "terminus-settings": "*"
   },
   "dependencies": {
     "axios": "^0.16.2",
-    "mz": "^2.6.0"
+    "mz": "^2.6.0",
+    "npm": "^6.7.0"
   },
   "false": {}
 }

+ 3 - 14
terminus-plugin-manager/src/components/pluginsSettingsTab.component.pug

@@ -20,7 +20,7 @@
                 small {{plugin.description}}
 
         button.btn.btn-primary.ml-2(
-            *ngIf='npmInstalled && knownUpgrades[plugin.name]',
+            *ngIf='knownUpgrades[plugin.name]',
             (click)='upgradePlugin(plugin)',
             [disabled]='busy[plugin.name] != undefined'
         )
@@ -42,24 +42,13 @@
             
         button.btn.btn-danger.ml-2(
             (click)='uninstallPlugin(plugin)', 
-            *ngIf='!plugin.isBuiltin && npmInstalled',
+            *ngIf='!plugin.isBuiltin',
             [disabled]='busy[plugin.name] != undefined'
         )
             i.fas.fa-fw.fa-trash(*ngIf='busy[plugin.name] != BusyState.Uninstalling')
             i.fas.fa-fw.fa-circle-notch.fa-spin(*ngIf='busy[plugin.name] == BusyState.Uninstalling')
 
-.text-center.mt-5(*ngIf='npmMissing')
-    h4 npm not installed
-    p.mb-2 npm is required to install Terminus plugins.
-    .btn-group
-        button.btn.btn-outline-primary((click)='downloadNPM()')
-            i.fas.fa-download
-            span Get npm
-        button.btn.btn-outline-info((click)='checkNPM()')
-            i.fas.fa-refresh
-            span Try again
-
-div(*ngIf='npmInstalled')
+div
     h3.mt-4 Available
 
     .input-group.mb-3

+ 0 - 12
terminus-plugin-manager/src/components/pluginsSettingsTab.component.ts

@@ -21,8 +21,6 @@ export class PluginsSettingsTabComponent {
     @Input() busy: {[id: string]: BusyState} = {}
     @Input() erroredPlugin: string
     @Input() errorMessage: string
-    @Input() npmInstalled = false
-    @Input() npmMissing = false
 
     constructor (
         private electron: ElectronService,
@@ -50,22 +48,12 @@ export class PluginsSettingsTabComponent {
                 this.knownUpgrades[plugin.name] = available.find(x => x.name === plugin.name && semver.gt(x.version, plugin.version))
             }
         })
-        this.checkNPM()
     }
 
     openPluginsFolder (): void {
         this.hostApp.getShell().openItem(this.pluginManager.userPluginsPath)
     }
 
-    downloadNPM (): void {
-        this.hostApp.getShell().openExternal('https://nodejs.org/en/download/current/')
-    }
-
-    async checkNPM () {
-        this.npmInstalled = await this.pluginManager.isNPMInstalled()
-        this.npmMissing = !this.npmInstalled
-    }
-
     searchAvailable (query: string) {
         this.availablePluginsQuery$.next(query)
     }

+ 28 - 46
terminus-plugin-manager/src/services/pluginManager.service.ts

@@ -1,11 +1,9 @@
-import * as path from 'path'
-import * as fs from 'mz/fs'
-import { exec } from 'mz/child_process'
+import npm from 'npm'
 import axios from 'axios'
 import { Observable, from } from 'rxjs'
 import { map } from 'rxjs/operators'
 import { Injectable } from '@angular/core'
-import { Logger, LogService, ConfigService, HostAppService, Platform } from 'terminus-core'
+import { Logger, LogService } from 'terminus-core'
 
 const NAME_PREFIX = 'terminus-'
 const KEYWORD = 'terminus-plugin'
@@ -29,45 +27,23 @@ export class PluginManagerService {
     builtinPluginsPath: string = (window as any).builtinPluginsPath
     userPluginsPath: string = (window as any).userPluginsPath
     installedPlugins: IPluginInfo[] = (window as any).installedPlugins
-    npmPath: string
-    private envPath: string
+
+    private npmReady: Promise<void>
 
     constructor (
         log: LogService,
-        private config: ConfigService,
-        private hostApp: HostAppService,
     ) {
         this.logger = log.create('pluginManager')
-        this.detectPath()
-    }
-
-    async detectPath () {
-        this.npmPath = this.config.store.npm
-        this.envPath = process.env.PATH
-        if (await fs.exists(this.npmPath)) {
-            return
-        }
-        if (this.hostApp.platform !== Platform.Windows) {
-            this.envPath = (await exec('$SHELL -i -c \'echo $PATH\''))[0].toString().trim()
-            let searchPaths = this.envPath.split(':')
-            for (let searchPath of searchPaths) {
-                if (await fs.exists(path.join(searchPath, 'npm'))) {
-                    this.logger.debug('Found npm in', searchPath)
-                    this.npmPath = path.join(searchPath, 'npm')
-                    return
+        this.npmReady = new Promise(resolve => {
+            npm.load({
+                prefix: this.userPluginsPath,
+            }, err => {
+                if (err) {
+                    this.logger.error(err)
                 }
-            }
-        }
-    }
-
-    async isNPMInstalled (): Promise<boolean> {
-        await this.detectPath()
-        try {
-            await exec(`${this.npmPath} -v`, { env: this.getEnv() })
-            return true
-        } catch (_) {
-            return false
-        }
+                resolve()
+            })
+        })
     }
 
     listAvailable (query?: string): Observable<IPluginInfo[]> {
@@ -92,17 +68,23 @@ export class PluginManagerService {
     }
 
     async installPlugin (plugin: IPluginInfo) {
-        await exec(`${this.npmPath} --prefix "${this.userPluginsPath}" install ${plugin.packageName}@${plugin.version}`, { env: this.getEnv() })
-        this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
-        this.installedPlugins.push(plugin)
+        await this.npmReady
+        npm.commands.install([`${plugin.packageName}@${plugin.version}`], err => {
+            if (err) {
+                this.logger.error(err)
+            }
+            this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
+            this.installedPlugins.push(plugin)
+        })
     }
 
     async uninstallPlugin (plugin: IPluginInfo) {
-        await exec(`${this.npmPath} --prefix "${this.userPluginsPath}" remove ${plugin.packageName}`, { env: this.getEnv() })
-        this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
-    }
-
-    private getEnv (): any {
-        return Object.assign(process.env, { PATH: this.envPath })
+        await this.npmReady
+        npm.commands.remove([plugin.packageName], err => {
+            if (err) {
+                this.logger.error(err)
+            }
+            this.installedPlugins = this.installedPlugins.filter(x => x.packageName !== plugin.packageName)
+        })
     }
 }

+ 1 - 0
terminus-plugin-manager/webpack.config.js

@@ -44,6 +44,7 @@ module.exports = {
   externals: [
     'fs',
     'font-manager',
+    'npm',
     'path',
     'mz/fs',
     'mz/child_process',

File diff suppressed because it is too large
+ 833 - 1
terminus-plugin-manager/yarn.lock


Some files were not shown because too many files changed in this diff