Implement plugin support

This commit is contained in:
Juan Cruz Viotti 2015-01-14 14:25:16 -03:00
parent 4eb9f93f30
commit 2a8f1f1dc2
4 changed files with 204 additions and 1 deletions

View File

@ -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
View 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

View 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')

View File

@ -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"
}
}