mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-20 09:26:42 +00:00
Implement plugin support
This commit is contained in:
parent
4eb9f93f30
commit
2a8f1f1dc2
@ -1,10 +1,12 @@
|
||||
_ = require('lodash')
|
||||
path = require('path')
|
||||
capitano = require('capitano')
|
||||
resin = require('resin-sdk')
|
||||
packageJSON = require('../package.json')
|
||||
actions = require('./actions')
|
||||
log = require('./log/log')
|
||||
errors = require('./errors/errors')
|
||||
plugin = require('./plugin/plugin')
|
||||
|
||||
capitano.command
|
||||
signature: 'version'
|
||||
@ -591,6 +593,21 @@ capitano.command
|
||||
'''
|
||||
action: actions.examples.info
|
||||
|
||||
try
|
||||
for pluginPath in plugin.getPluginsPathsByGlob('resin-plugin-*')
|
||||
pluginCommands = plugin.getPluginMeta(pluginPath).resin or []
|
||||
pluginCommands = _.map pluginCommands, (command) ->
|
||||
pluginCommandActionPath = path.join(pluginPath, command.action)
|
||||
command.action = require(pluginCommandActionPath)
|
||||
return command
|
||||
|
||||
_.each(pluginCommands, capitano.command)
|
||||
|
||||
# In case of an error, we log it to stderr, but we don't
|
||||
# allow plugins to crash the main process.
|
||||
catch error
|
||||
errors.handle(error)
|
||||
|
||||
cli = capitano.parse(process.argv)
|
||||
|
||||
changeProjectDirectory = (directory) ->
|
||||
|
44
lib/plugin/plugin.coffee
Normal file
44
lib/plugin/plugin.coffee
Normal file
@ -0,0 +1,44 @@
|
||||
_ = require('lodash')
|
||||
fs = require('fs')
|
||||
path = require('path')
|
||||
yeoman = require('yeoman-environment')
|
||||
glob = require('glob')
|
||||
|
||||
exports.getNpmPaths = ->
|
||||
return yeoman.createEnv().getNpmPaths()
|
||||
|
||||
exports.getPluginsPathsByGlob = (nameGlob) ->
|
||||
|
||||
if not nameGlob?
|
||||
throw new Error('Missing glob')
|
||||
|
||||
if not _.isString(nameGlob)
|
||||
throw new Error('Invalid glob')
|
||||
|
||||
npmPaths = exports.getNpmPaths()
|
||||
result = []
|
||||
|
||||
for npmPath in npmPaths
|
||||
foundModules = glob.sync(nameGlob, cwd: npmPath)
|
||||
foundModules = _.map foundModules, (foundModule) ->
|
||||
return path.join(npmPath, foundModule)
|
||||
|
||||
result = result.concat(foundModules)
|
||||
|
||||
return result
|
||||
|
||||
exports.getPluginMeta = (pluginPath) ->
|
||||
pluginPackageJSONPath = path.join(pluginPath, 'package.json')
|
||||
|
||||
if not fs.existsSync(pluginPackageJSONPath)
|
||||
throw new Error("Missing or invalid plugin: #{pluginPath}")
|
||||
|
||||
pluginPackageJSON = fs.readFileSync pluginPackageJSONPath,
|
||||
encoding: 'utf8'
|
||||
|
||||
try
|
||||
meta = JSON.parse(pluginPackageJSON)
|
||||
catch
|
||||
throw new Error("Invalid package.json: #{pluginPackageJSONPath}")
|
||||
|
||||
return meta
|
138
lib/plugin/plugin.spec.coffee
Normal file
138
lib/plugin/plugin.spec.coffee
Normal file
@ -0,0 +1,138 @@
|
||||
_ = require('lodash')
|
||||
path = require('path')
|
||||
sinon = require('sinon')
|
||||
chai = require('chai')
|
||||
chai.use(require('sinon-chai'))
|
||||
glob = require('glob')
|
||||
fs = require('fs')
|
||||
fsPlus = require('fs-plus')
|
||||
mockFs = require('mock-fs')
|
||||
expect = chai.expect
|
||||
plugin = require('./plugin')
|
||||
|
||||
describe 'Plugin:', ->
|
||||
|
||||
describe '#getPluginsPathsByGlob()', ->
|
||||
|
||||
describe 'given no glob', ->
|
||||
|
||||
it 'should throw an error', ->
|
||||
expect ->
|
||||
plugin.getPluginsPathsByGlob()
|
||||
.to.throw('Missing glob')
|
||||
|
||||
describe 'given an invalid glob', ->
|
||||
|
||||
it 'should throw an error', ->
|
||||
expect ->
|
||||
plugin.getPluginsPathsByGlob([ 'glob' ])
|
||||
.to.throw('Invalid glob')
|
||||
|
||||
describe 'given a glob that does not matches anything', ->
|
||||
|
||||
beforeEach ->
|
||||
@globSyncStub = sinon.stub(glob, 'sync')
|
||||
@globSyncStub.returns []
|
||||
|
||||
@plugins = plugin.getPluginsPathsByGlob('myGlob*')
|
||||
|
||||
afterEach ->
|
||||
@globSyncStub.restore()
|
||||
|
||||
it 'should return an empty array', ->
|
||||
expect(@plugins).to.deep.equal([])
|
||||
|
||||
describe 'given a glob that matches packages', ->
|
||||
|
||||
beforeEach ->
|
||||
@getNpmPathsStub = sinon.stub(plugin, 'getNpmPaths')
|
||||
@getNpmPathsStub.returns([ '/usr/lib/node_modules' ])
|
||||
|
||||
@globSyncStub = sinon.stub(glob, 'sync')
|
||||
@globSyncStub.returns [
|
||||
'one'
|
||||
'two'
|
||||
'three'
|
||||
]
|
||||
|
||||
@plugins = plugin.getPluginsPathsByGlob('myGlob*')
|
||||
|
||||
afterEach ->
|
||||
@getNpmPathsStub.restore()
|
||||
@globSyncStub.restore()
|
||||
|
||||
it 'should return an array', ->
|
||||
expect(@plugins).to.be.an.instanceof(Array)
|
||||
|
||||
it 'should have the proper length', ->
|
||||
expect(@plugins).to.have.length(3)
|
||||
|
||||
it 'should contain absolute paths', ->
|
||||
for pluginPath in @plugins
|
||||
expect(fsPlus.isAbsolute(pluginPath)).to.be.true
|
||||
|
||||
it 'should return the appropriate paths', ->
|
||||
expect(@plugins[0]).to.equal('/usr/lib/node_modules/one')
|
||||
expect(@plugins[1]).to.equal('/usr/lib/node_modules/two')
|
||||
expect(@plugins[2]).to.equal('/usr/lib/node_modules/three')
|
||||
|
||||
describe '#getNpmPaths()', ->
|
||||
|
||||
beforeEach ->
|
||||
@npmPaths = plugin.getNpmPaths()
|
||||
|
||||
it 'should return an array', ->
|
||||
expect(@npmPaths).to.be.an.instanceof(Array)
|
||||
|
||||
it 'should return at least one path', ->
|
||||
expect(@npmPaths.length > 1).to.be.true
|
||||
|
||||
it 'should contain absolute paths', ->
|
||||
for npmPath in @npmPaths
|
||||
expect(fsPlus.isAbsolute(npmPath)).to.be.true
|
||||
|
||||
describe '#getPluginMeta()', ->
|
||||
|
||||
describe 'given an invalid plugin', ->
|
||||
|
||||
beforeEach ->
|
||||
mockFs
|
||||
'/hello/world':
|
||||
'package.json': 'Invalid package.json'
|
||||
|
||||
afterEach ->
|
||||
mockFs.restore()
|
||||
|
||||
it 'should throw an error', ->
|
||||
expect ->
|
||||
plugin.getPluginMeta('/hello/world')
|
||||
.to.throw('Invalid package.json: /hello/world/package.json')
|
||||
|
||||
describe 'given a plugin that exists', ->
|
||||
|
||||
beforeEach ->
|
||||
mockFs
|
||||
'/hello/world':
|
||||
'package.json': JSON.stringify({ name: 'myPlugin' })
|
||||
|
||||
afterEach ->
|
||||
mockFs.restore()
|
||||
|
||||
it 'should return the parsed object', ->
|
||||
result = plugin.getPluginMeta('/hello/world')
|
||||
expect(result).to.deep.equal
|
||||
name: 'myPlugin'
|
||||
|
||||
describe 'given a plugin that does not exist', ->
|
||||
|
||||
beforeEach ->
|
||||
@fsExistsSyncStub = sinon.stub(fs, 'existsSync')
|
||||
@fsExistsSyncStub.returns(false)
|
||||
|
||||
afterEach ->
|
||||
@fsExistsSyncStub.restore()
|
||||
|
||||
it 'should throw an error', ->
|
||||
expect ->
|
||||
plugin.getPluginMeta('/hello/world')
|
||||
.to.throw('Missing or invalid plugin: /hello/world')
|
@ -39,6 +39,7 @@
|
||||
"gulp-util": "~3.0.1",
|
||||
"mocha": "~2.0.1",
|
||||
"mocha-notifier-reporter": "~0.1.0",
|
||||
"mock-fs": "^2.3.2",
|
||||
"run-sequence": "~1.0.2",
|
||||
"sinon": "~1.12.1",
|
||||
"sinon-chai": "~2.6.0"
|
||||
@ -49,7 +50,9 @@
|
||||
"cliff": "~0.1.9",
|
||||
"coffee-script": "~1.8.0",
|
||||
"conf.js": "^0.1.1",
|
||||
"fs-plus": "^2.4.0",
|
||||
"git-cli": "~0.8.2",
|
||||
"glob": "^4.3.4",
|
||||
"inquirer": "~0.8.0",
|
||||
"lodash": "~2.4.1",
|
||||
"lodash-contrib": "~241.4.14",
|
||||
@ -58,6 +61,7 @@
|
||||
"progress": "~1.1.8",
|
||||
"progress-bar": "~0.1.1",
|
||||
"resin-sdk": "git+ssh://git@bitbucket.org/rulemotion/resin-sdk.git",
|
||||
"underscore.string": "~2.4.0"
|
||||
"underscore.string": "~2.4.0",
|
||||
"yeoman-environment": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user