Skip to content

Commit

Permalink
feat: verbose and yarn.lock support
Browse files Browse the repository at this point in the history
uses yarn.lock file of plugin if it exists
  • Loading branch information
jdx committed May 24, 2018
1 parent 4e734b0 commit 577f9a5
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
9 changes: 7 additions & 2 deletions src/commands/plugins/install.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Command} from '@oclif/command'
import {Command, flags} from '@oclif/command'
import chalk from 'chalk'
import cli from 'cli-ux'

Expand All @@ -10,12 +10,17 @@ export default class PluginsInstall extends Command {
static examples = ['$ <%= config.bin %> plugins:install <%- config.pjson.oclif.examplePlugin || "myplugin" %> ']
static strict = false
static args = [{name: 'plugin', description: 'plugin to install', required: true}]
static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
}
static aliases = ['plugins:add']

plugins = new Plugins(this.config)

async run() {
const {argv} = this.parse(PluginsInstall)
const {flags, argv} = this.parse(PluginsInstall)
if (flags.verbose) this.plugins.verbose = true
for (let plugin of argv) {
let {name, tag} = parsePlugin(plugin)
cli.action.start(`Installing plugin ${chalk.cyan(this.plugins.friendlyName(name))}`)
Expand Down
9 changes: 7 additions & 2 deletions src/commands/plugins/link.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Command} from '@oclif/command'
import {Command, flags} from '@oclif/command'
import chalk from 'chalk'
import cli from 'cli-ux'

Expand All @@ -9,11 +9,16 @@ export default class PluginsLink extends Command {
static usage = 'plugins:link PLUGIN'
static examples = ['$ <%= config.bin %> plugins:link <%- config.pjson.oclif.examplePlugin || "myplugin" %> ']
static args = [{name: 'path', description: 'path to plugin', required: true, default: '.'}]
static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
}

plugins = new Plugins(this.config)

async run() {
const {args} = this.parse(PluginsLink)
const {flags, args} = this.parse(PluginsLink)
this.plugins.verbose = flags.verbose
cli.action.start(`Linking plugin ${chalk.cyan(args.path)}`)
await this.plugins.link(args.path)
cli.action.stop()
Expand Down
9 changes: 7 additions & 2 deletions src/commands/plugins/uninstall.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Command} from '@oclif/command'
import {Command, flags} from '@oclif/command'
import cli from 'cli-ux'

import Plugins from '../../plugins'
Expand All @@ -12,13 +12,18 @@ export default class PluginsUninstall extends Command {
`
static variableArgs = true
static args = [{name: 'plugin', description: 'plugin to uninstall'}]
static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
}
static aliases = ['plugins:unlink', 'plugins:remove']

plugins = new Plugins(this.config)

async run() {
const {argv} = this.parse(PluginsUninstall)
const {flags, argv} = this.parse(PluginsUninstall)
this.plugins = new Plugins(this.config)
if (flags.verbose) this.plugins.verbose = true
if (!argv.length) argv.push('.')
for (let plugin of argv) {
const friendly = this.plugins.friendlyName(plugin)
Expand Down
9 changes: 7 additions & 2 deletions src/commands/plugins/update.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import {Command} from '@oclif/command'
import {Command, flags} from '@oclif/command'

import Plugins from '../../plugins'

export default class PluginsUpdate extends Command {
static topic = 'plugins'
static command = 'update'
static description = 'update installed plugins'
static flags = {
help: flags.help({char: 'h'}),
verbose: flags.boolean({char: 'v'}),
}

plugins = new Plugins(this.config)

async run() {
this.parse(PluginsUpdate)
const {flags} = this.parse(PluginsUpdate)
this.plugins.verbose = flags.verbose
await this.plugins.update()
}
}
22 changes: 18 additions & 4 deletions src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import Yarn from './yarn'
const initPJSON: Config.PJSON.User = {private: true, oclif: {schema: 1, plugins: []}, dependencies: {}}

export default class Plugins {
verbose = false
readonly yarn: Yarn
private readonly debug: any

constructor(public config: Config.IConfig) {
this.yarn = new Yarn({config, cwd: this.config.dataDir})
this.yarn = new Yarn({config})
this.debug = require('debug')('@oclif/plugins')
}

Expand Down Expand Up @@ -54,24 +55,34 @@ export default class Plugins {
name = unfriendly
}
await this.createPJSON()
await this.yarn.exec(['add', `${name}@${tag}`])
await this.yarn.exec(['add', `${name}@${tag}`], {cwd: this.config.dataDir, verbose: this.verbose})
const plugin = await Config.load({devPlugins: false, userPlugins: false, root: path.join(this.config.dataDir, 'node_modules', name), name})
if (!plugin.valid && !this.config.plugins.find(p => p.name === '@oclif/plugin-legacy')) {
throw new Error('plugin is invalid')
}
await this.refresh(plugin.root)
await this.add({name, tag: range || tag, type: 'user'})
} catch (err) {
await this.uninstall(name).catch(err => this.debug(err))
throw err
}
}

// if yarn.lock exists, fetch locked dependencies
async refresh(root: string, {prod = true}: {prod?: boolean} = {}) {
if (fs.existsSync(path.join(root, 'yarn.lock'))) {
// use yarn.lock to fetch dependencies
await this.yarn.exec(prod ? ['--prod'] : [], {cwd: root, verbose: this.verbose})
}
}

async link(p: string) {
const c = await Config.load(path.resolve(p))
cli.action.start(`${this.config.name}: linking plugin ${c.name}`)
if (!c.valid && !this.config.plugins.find(p => p.name === '@oclif/plugin-legacy')) {
throw new CLIError('plugin is not a valid oclif plugin')
}
await this.refresh(c.root, {prod: false})
await this.add({type: 'link', name: c.name, root: c.root})
}

Expand All @@ -93,7 +104,7 @@ export default class Plugins {
try {
const pjson = await this.pjson()
if ((pjson.oclif.plugins || []).find(p => typeof p === 'object' && p.type === 'user' && p.name === name)) {
await this.yarn.exec(['remove', name])
await this.yarn.exec(['remove', name], {cwd: this.config.dataDir, verbose: this.verbose})
}
} finally {
await this.remove(name)
Expand All @@ -104,7 +115,10 @@ export default class Plugins {
const plugins = (await this.list()).filter((p): p is Config.PJSON.PluginTypes.User => p.type === 'user')
if (plugins.length === 0) return
cli.action.start(`${this.config.name}: Updating plugins`)
await this.yarn.exec(['add', ...plugins.map(p => `${p.name}@${p.tag}`)])
await this.yarn.exec(['add', ...plugins.map(p => `${p.name}@${p.tag}`)], {cwd: this.config.dataDir, verbose: this.verbose})
for (let p of plugins) {
await this.refresh(path.join(this.config.dataDir, 'node_modules', p.name))
}
cli.action.stop()
}

Expand Down
28 changes: 18 additions & 10 deletions src/yarn.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import {IConfig} from '@oclif/config'
import ux from 'cli-ux'
import * as path from 'path'

const debug = require('debug')('cli:yarn')

export default class Yarn {
config: IConfig
cwd: string

constructor({config, cwd}: { config: IConfig; cwd: string }) {
constructor({config}: { config: IConfig }) {
this.config = config
this.cwd = cwd
}

get bin(): string {
Expand All @@ -20,8 +19,12 @@ export default class Yarn {
return new Promise((resolve, reject) => {
const {fork} = require('child_process')
let forked = fork(modulePath, args, options)
forked.stdout.on('data', (d: any) => process.stdout.write(d))
forked.stderr.on('data', (d: any) => process.stderr.write(d))
forked.stdout.setEncoding('utf8')
forked.stdout.on('data', (d: any) => {
if (options.verbose) process.stdout.write(d)
else ux.action.status = d.replace(/\n$/, '').split('\n').pop()
})

forked.on('error', reject)
forked.on('exit', (code: number) => {
Expand All @@ -39,13 +42,14 @@ export default class Yarn {
})
}

async exec(args: string[] = []): Promise<void> {
async exec(args: string[] = [], opts: {cwd: string, verbose: boolean}): Promise<void> {
const cwd = opts.cwd
if (args[0] !== 'run') {
const cacheDir = path.join(this.config.cacheDir, 'yarn')
args = [
...args,
'--non-interactive',
`--mutex=file:${path.join(this.cwd, 'yarn.lock')}`,
`--mutex=file:${path.join(cwd, 'yarn.lock')}`,
`--preferred-cache-folder=${cacheDir}`,
'--check-files',
]
Expand All @@ -56,12 +60,16 @@ export default class Yarn {

const npmRunPath = require('npm-run-path')
let options = {
cwd: this.cwd,
...opts,
cwd,
stdio: [0, null, null, 'ipc'],
env: npmRunPath.env({cwd: this.cwd, env: process.env}),
env: npmRunPath.env({cwd, env: process.env}),
}

debug(`${this.cwd}: ${this.bin} ${args.join(' ')}`)
if (opts.verbose) {
process.stderr.write(`${cwd}: ${this.bin} ${args.join(' ')}`)
}
debug(`${cwd}: ${this.bin} ${args.join(' ')}`)
try {
await this.fork(this.bin, args, options)
debug('done')
Expand All @@ -70,7 +78,7 @@ export default class Yarn {
let networkConcurrency = '--network-concurrency=1'
if (err.message.includes('EAI_AGAIN') && !args.includes(networkConcurrency)) {
debug('EAI_AGAIN')
return this.exec([...args, networkConcurrency])
return this.exec([...args, networkConcurrency], opts)
}
throw err
}
Expand Down

0 comments on commit 577f9a5

Please sign in to comment.