adding registry code in plugman and removing dependencies. Updated configuration handling
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/fd679f38 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/fd679f38 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/fd679f38 Branch: refs/heads/master Commit: fd679f38013c3171cddebed8173409b4546f0c95 Parents: 453553d Author: Anis Kadri <[email protected]> Authored: Sat Jul 27 14:17:27 2013 -0700 Committer: Anis Kadri <[email protected]> Committed: Sat Jul 27 14:17:27 2013 -0700 ---------------------------------------------------------------------- package.json | 5 +- spec/adduser.spec.js | 9 +- spec/config.js | 10 ++ spec/fetch.spec.js | 2 + spec/publish.spec.js | 5 +- spec/registry/registry.js | 20 ++++ spec/search.spec.js | 5 +- spec/unpublish.spec.js | 5 +- src/adduser.js | 23 ++--- src/config.js | 15 +++ src/fetch.js | 4 +- src/publish.js | 25 +++-- src/registry/manifest.js | 69 +++++++++++++ src/registry/registry.js | 218 +++++++++++++++++++++++++++++++++++++++++ src/search.js | 13 +-- src/unpublish.js | 23 ++--- 16 files changed, 381 insertions(+), 70 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/package.json ---------------------------------------------------------------------- diff --git a/package.json b/package.json index 16d9285..6a2af97 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,10 @@ "underscore":"1.4.4", "dep-graph":"1.1.0", "semver": "2.0.x", - "plugman-registry": "0.0.6" + "npm": "1.3.4", + "rc": "0.3.0", + "xmldom": "0.1.16", + "tar.gz": "0.1.1" }, "devDependencies": { "jasmine-node": "1.7.0" http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/adduser.spec.js ---------------------------------------------------------------------- diff --git a/spec/adduser.spec.js b/spec/adduser.spec.js index 563592d..732ee71 100644 --- a/spec/adduser.spec.js +++ b/spec/adduser.spec.js @@ -1,13 +1,10 @@ var adduser = require('../src/adduser'), - config = require('../config'), - registry = require('plugman-registry'); + registry = require('../src/registry/registry'); describe('adduser', function() { it('should add a user', function() { - var sUse = spyOn(registry, 'use').andCallThrough(); var sAddUser = spyOn(registry, 'adduser'); - adduser(); - expect(sUse).toHaveBeenCalledWith(config.registry, jasmine.any(Function)); - expect(sAddUser).toHaveBeenCalled(); + adduser(function(err, result) { }); + expect(sAddUser).toHaveBeenCalledWith(null, jasmine.any(Function)); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/config.js ---------------------------------------------------------------------- diff --git a/spec/config.js b/spec/config.js new file mode 100644 index 0000000..5f4f781 --- /dev/null +++ b/spec/config.js @@ -0,0 +1,10 @@ +var config = require('../src/config'), + registry = require('../src/registry/registry'); + +describe('config', function() { + it('should run config', function() { + var sConfig = spyOn(registry, 'config'); + config(function(err, result) { }); + expect(sConfig).toHaveBeenCalledWith(jasmine.any(Function)); + }); +}); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/fetch.spec.js ---------------------------------------------------------------------- diff --git a/spec/fetch.spec.js b/spec/fetch.spec.js index 4151020..3213ad4 100644 --- a/spec/fetch.spec.js +++ b/spec/fetch.spec.js @@ -28,6 +28,8 @@ describe('fetch', function() { expect(cp).toHaveBeenCalledWith('-R', path.join(test_plugin, '*'), path.join(temp, 'id')); }); it('should copy locally-available plugin to plugins directory when spaces in path', function() { + //XXX: added this because plugman tries to fetch from registry when plugin folder does not exist + spyOn(fs,'existsSync').andReturn(true); fetch(test_plugin_with_space, temp); expect(cp).toHaveBeenCalledWith('-R', path.join(test_plugin_with_space, '*'), path.join(temp, 'id')); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/publish.spec.js ---------------------------------------------------------------------- diff --git a/spec/publish.spec.js b/spec/publish.spec.js index 3a253e7..59f863e 100644 --- a/spec/publish.spec.js +++ b/spec/publish.spec.js @@ -1,13 +1,10 @@ var publish = require('../src/publish'), - config = require('../config'), - registry = require('plugman-registry'); + registry = require('../src/registry/registry'); describe('publish', function() { it('should publish a plugin', function() { - var sUse = spyOn(registry, 'use').andCallThrough(); var sPublish = spyOn(registry, 'publish'); publish(new Array('/path/to/myplugin')); - expect(sUse).toHaveBeenCalledWith(config.registry, jasmine.any(Function)); expect(sPublish).toHaveBeenCalledWith(['/path/to/myplugin'], jasmine.any(Function)); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/registry/registry.js ---------------------------------------------------------------------- diff --git a/spec/registry/registry.js b/spec/registry/registry.js new file mode 100644 index 0000000..d4baf59 --- /dev/null +++ b/spec/registry/registry.js @@ -0,0 +1,20 @@ +var registry = require('../../src/registry/registry'), + npm = require('npm'); + +describe('registry', function() { + beforeEach(function() { + registry.settings = { + cache: plugmanCacheDir, + force: true, + logstream: fs.createWriteStream(path.resolve(plugmanConfigDir, 'plugman.log')), + userconfig: path.resolve(plugmanConfigDir, 'config') + }; + }); + it('should run config', function() { + var sLoad = spyOn(npm, 'load').andCallThrough(); + var sConfig = spyOn(npm, 'config'); + registry.config(new Array('/path/to/myplugin')); + expect(sLoad).toHaveBeenCalledWith(registry.settings, jasmine.any(Function)); + expect(sPublish).toHaveBeenCalledWith(['/path/to/myplugin'], jasmine.any(Function)); + }); +}); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/search.spec.js ---------------------------------------------------------------------- diff --git a/spec/search.spec.js b/spec/search.spec.js index f708854..2393c70 100644 --- a/spec/search.spec.js +++ b/spec/search.spec.js @@ -1,13 +1,10 @@ var search = require('../src/search'), - config = require('../config'), - registry = require('plugman-registry'); + registry = require('../src/registry/registry'); describe('search', function() { it('should search a plugin', function() { - var sUse = spyOn(registry, 'use').andCallThrough(); var sSearch = spyOn(registry, 'search'); search(new Array('myplugin', 'keyword')); - expect(sUse).toHaveBeenCalledWith(config.registry, jasmine.any(Function)); expect(sSearch).toHaveBeenCalledWith(['myplugin', 'keyword'], jasmine.any(Function)); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/spec/unpublish.spec.js ---------------------------------------------------------------------- diff --git a/spec/unpublish.spec.js b/spec/unpublish.spec.js index 207804d..f454a27 100644 --- a/spec/unpublish.spec.js +++ b/spec/unpublish.spec.js @@ -1,13 +1,10 @@ var unpublish = require('../src/unpublish'), - config = require('../config'), - registry = require('plugman-registry'); + registry = require('../src/registry/registry'); describe('unpublish', function() { it('should unpublish a plugin', function() { - var sUse = spyOn(registry, 'use').andCallThrough(); var sUnpublish = spyOn(registry, 'unpublish'); unpublish(new Array('[email protected]')); - expect(sUse).toHaveBeenCalledWith(config.registry, jasmine.any(Function)); expect(sUnpublish).toHaveBeenCalledWith(['[email protected]'], jasmine.any(Function)); }); }); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/adduser.js ---------------------------------------------------------------------- diff --git a/src/adduser.js b/src/adduser.js index 8ca9c9a..3ff5023 100644 --- a/src/adduser.js +++ b/src/adduser.js @@ -1,18 +1,15 @@ -var registry = require('plugman-registry') - , config = require('../config'); +var registry = require('./registry/registry') module.exports = function(callback) { - registry.use(config.registry, function(err) { registry.adduser(null, function(err) { - if(callback && typeof callback === 'function') { - err ? callback(err) : callback(null); - } else { - if(err) { - throw err; - } else { - console.log('user added'); - } - } + if(callback && typeof callback === 'function') { + err ? callback(err) : callback(null); + } else { + if(err) { + throw err; + } else { + console.log('user added'); + } + } }); - }); } http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/config.js ---------------------------------------------------------------------- diff --git a/src/config.js b/src/config.js new file mode 100644 index 0000000..f863717 --- /dev/null +++ b/src/config.js @@ -0,0 +1,15 @@ +var registry = require('./registry/registry') + +module.exports = function(params, callback) { + registry.config(params, function(err) { + if(callback && typeof callback === 'function') { + err ? callback(err) : callback(null); + } else { + if(err) { + throw err; + } else { + console.log('done'); + } + } + }); +} http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/fetch.js ---------------------------------------------------------------------- diff --git a/src/fetch.js b/src/fetch.js index 8f76bb5..59b95cf 100644 --- a/src/fetch.js +++ b/src/fetch.js @@ -5,7 +5,7 @@ var shell = require('shelljs'), xml_helpers = require('./util/xml-helpers'), metadata = require('./util/metadata'), path = require('path'), - registry = require('plugman-registry'); + registry = require('./registry/registry'); // XXX: leave the require('../plugman') because jasmine shits itself if you declare it up top // possible options: link, subdir, git_ref module.exports = function fetchPlugin(plugin_dir, plugins_dir, options, callback) { @@ -82,7 +82,6 @@ module.exports = function fetchPlugin(plugin_dir, plugins_dir, options, callback if(!fs.existsSync(plugin_dir)) { - registry.use(require('../plugman').config.registry, function() { registry.fetch([plugin_dir], function(err, plugin_dir) { if (err) { if(callback) { @@ -93,7 +92,6 @@ module.exports = function fetchPlugin(plugin_dir, plugins_dir, options, callback } movePlugin(plugin_dir, false); }); - }) } else { movePlugin(plugin_dir, true); } http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/publish.js ---------------------------------------------------------------------- diff --git a/src/publish.js b/src/publish.js index 06412cc..b5f6832 100644 --- a/src/publish.js +++ b/src/publish.js @@ -1,19 +1,16 @@ -var registry = require('plugman-registry') - , config = require('../config'); +var registry = require('./registry/registry') module.exports = function(plugin_path, callback) { - registry.use(config.registry, function(err) { - // plugin_path is an array of paths + // plugin_path is an array of paths registry.publish(plugin_path, function(err, d) { - if(callback && typeof callback === 'function') { - err ? callback(err) : callback(null); - } else { - if(err) { - throw err; - } else { - console.log('Plugin published'); - } - } + if(callback && typeof callback === 'function') { + err ? callback(err) : callback(null); + } else { + if(err) { + throw err; + } else { + console.log('Plugin published'); + } + } }); - }); } http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/registry/manifest.js ---------------------------------------------------------------------- diff --git a/src/registry/manifest.js b/src/registry/manifest.js new file mode 100644 index 0000000..59f7bb6 --- /dev/null +++ b/src/registry/manifest.js @@ -0,0 +1,69 @@ +var DOMParser = require('xmldom').DOMParser, + path = require('path'), + fs = require('fs'); + +// Java world big-up! +// TODO use CALLBACK +function generatePackageJsonFromPluginXml(plugin_path, cb) { + var package_json = {}; + var plugin_xml = fs.readFileSync(path.resolve(plugin_path, 'plugin.xml'), "utf8"); + var doc = new DOMParser().parseFromString(plugin_xml); + + if(!doc || !doc.documentElement) { + throw new Error('invalid plugin.xml document'); + } + + // name, version REQUIRED + // setting version + var version = doc.documentElement.getAttribute('version') + if(!version) { + var e = new Error('`version` required'); + if(cb) { + cb(e); + return null; + } + throw e; + } + package_json.version = version; + + // setting name + if(doc.documentElement.getElementsByTagName('name').length != 1 || + !doc.documentElement.getElementsByTagName('name').item(0).firstChild) { + var e = new Error('`name` is required'); + if(cb) { + cb(e); + return null; + } + throw e; + } + var name = doc.documentElement.getElementsByTagName('name').item(0).firstChild.nodeValue; + if(!name.match(/^\w+|-*$/)) throw new Error('`name` can only contain alphanumberic characters and -') + package_json.name = name.toLowerCase(); + + // OPTIONAL fields: description, license, keywords. TODO: add more! + if(doc.documentElement.getElementsByTagName('description').length == 1 && + doc.documentElement.getElementsByTagName('description').item(0).firstChild) { + package_json.description = doc.documentElement + .getElementsByTagName('description') + .item(0).firstChild.nodeValue; + } + if(doc.documentElement.getElementsByTagName('license').length == 1 && + doc.documentElement.getElementsByTagName('license').item(0).firstChild) { + package_json.license = doc.documentElement + .getElementsByTagName('license') + .item(0).firstChild.nodeValue; + } + if(doc.documentElement.getElementsByTagName('keywords').length == 1 && + doc.documentElement.getElementsByTagName('keywords').item(0).firstChild) { + package_json.keywords = doc.documentElement + .getElementsByTagName('keywords') + .item(0).firstChild.nodeValue.split(','); + } + + // write package.json + var package_json_path = path.resolve(plugin_path, 'package.json'); + fs.writeFileSync(package_json_path, JSON.stringify(package_json, null, 4), 'utf8'); + return package_json; +} + +module.exports.generatePackageJsonFromPluginXml = generatePackageJsonFromPluginXml; http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/registry/registry.js ---------------------------------------------------------------------- diff --git a/src/registry/registry.js b/src/registry/registry.js new file mode 100644 index 0000000..bf99a15 --- /dev/null +++ b/src/registry/registry.js @@ -0,0 +1,218 @@ +var npm = require('npm'), + path = require('path'), + http = require('http'), + targz = require('tar.gz'), + fs = require('fs'), + manifest = require('./manifest'), + os = require('os'), + rc = require('rc'), + plugmanConfigDir = path.resolve(process.env.HOME, '.plugman'), + plugmanCacheDir = path.resolve(plugmanConfigDir, 'cache'); + +var settings = module.exports.settings; + +function checkConfig(cb) { + if(settings != null) { + cb(); + } else { + use(cb); + } +} + +function handleError(err, cb) { + if(typeof cb == 'function') { + return cb(err); + } + throw err; +} +/** + * @method use + * @param {String} registry NPM registry URL + * @param {Function} cb callback + */ +function use(cb) { + if(typeof cb != 'function') throw new Error('Please provide a callback'); + // check if settings already set + if(settings != null) return cb(); + + // setting up settings + // obviously if settings dir does not exist settings is going to be empty + if(!fs.existsSync(plugmanConfigDir)) { + fs.mkdirSync(plugmanConfigDir); + fs.mkdirSync(plugmanCacheDir); + } + + settings = rc('plugman', { + cache: plugmanCacheDir, + force: true, + logstream: fs.createWriteStream(path.resolve(plugmanConfigDir, 'plugman.log')), + userconfig: path.resolve(plugmanConfigDir, 'config') + }); + + if(settings.registry) { + cb(); + } else { + // setting registry + npm.load(settings, function(er) { + if (er) return handlError(er); + npm.commands.config(['set', 'registry', 'http://registry.cordova.io'], cb); + }); + } + +} + +/** + * @method getPackageInfo + * @param {String} args Package names + * @param {Function} cb callback + */ +function getPackageInfo(args, cb) { + var thing = args.length ? args.shift().split("@") : [], + name = thing.shift(), + version = thing.join("@"), + + version = version ? version : 'latest'; + + http.get(settings.registry + '/' + name + '/' + version, function(res) { + if(res.statusCode != 200) { + var err = new Error('Error'); + if (cb) cb(err); + else throw err; + } else { + var info = ''; + res.on('data', function(chunk) { + info += chunk; + }); + res.on('end', function() { + cb(null, JSON.parse(info)); + }); + } + }).on('error', function(err) { + cb(err); + }); +} + +/** + * @method fetchPackage + * @param {String} info Package info + * @param {Function} cb callback + */ +function fetchPackage(info, cb) { + var cached = path.resolve(settings.cache, info.name, info.version, 'package'); + if(fs.existsSync(cached)) { + cb(null, cached); + } else { + var target = os.tmpdir() + info.name; + var filename = target + '.tgz'; + var filestream = fs.createWriteStream(filename); + var request = http.get(info.dist.tarball, function(res) { + if(res.statusCode != 200) { + var err = new Error('failed to fetch the plugin archive'); + if (cb) cb(err); + else throw err; + } else { + res.pipe(filestream); + filestream.on('finish', function() { + var decompress = new targz().extract(filename, target, function(err) { + cb(err, path.resolve(target, 'package')); + }); + }); + } + }); + } +} + +module.exports = { + settings: null, + /** + * @method config + * @param {Array} args Command argument + * @param {Function} cb Command callback + */ + config: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb) + npm.load(settings, function(er) { + if (er) return handlError(er); + npm.commands.config(args, cb); + }); + }); + }, + /** + * @method adduser + * @param {Array} args Command argument + * @param {Function} cb Command callback + */ + adduser: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb) + npm.load(settings, function(er) { + if (er) return handlError(er); + npm.commands.adduser(args, cb); + }); + }); + }, + /** + * @method publish + * @param {Array} args Command argument + * @param {Function} cb Command callback + */ + publish: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb); + manifest.generatePackageJsonFromPluginXml(args[0]); + npm.load(settings, function(er) { + if (er) return handlError(er); + npm.commands.publish(args, function(err, data) { + fs.unlink(path.resolve(args[0], 'package.json')); + cb(err, data); + }); + }); + }); + }, + /** + * @method search + * @param {Array} args Array of keywords + * @param {Function} cb Command callback + */ + search: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb); + npm.load(settings, function(er) { + if (er) return handlError(er, cb); + npm.commands.search(args, true, cb); + }); + }); + }, + /** + * @method unpublish + * @param {Array} args Command argument + * @param {Function} cb Command callback + */ + unpublish: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb); + npm.load(settings, function(er) { + if (er) return handlError(er); + npm.commands.unpublish(args, function(err, d) { + if(err) return handleError(err, cb); + npm.commands.cache(["clean"], cb); + }); + }); + }); + }, + /** + * @method fetch + * @param {String} name Plugin name + * @param {Function} cb Command callback + */ + fetch: function(args, cb) { + checkConfig(function(err) { + if(err) return handleError(err, cb) + getPackageInfo(args, function(err, info) { + if(err) return handleError(err, cb) + fetchPackage(info, cb); + }); + }); + } +} http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/search.js ---------------------------------------------------------------------- diff --git a/src/search.js b/src/search.js index 31b1094..4d679c4 100644 --- a/src/search.js +++ b/src/search.js @@ -1,18 +1,15 @@ -var registry = require('plugman-registry') - , config = require('../config'); +var registry = require('./registry/registry') module.exports = function(search_opts, callback) { - registry.use(config.registry, function(err) { registry.search(search_opts, function(err, plugins) { if(callback) { if(err) return callback(err); callback(null, plugins); } else { - if(err) return console.log(err); - for(var plugin in plugins) { - console.log(plugins[plugin].name, '-', plugins[plugin].description || 'no description provided'); - } + if(err) return console.log(err); + for(var plugin in plugins) { + console.log(plugins[plugin].name, '-', plugins[plugin].description || 'no description provided'); + } } }); - }); } http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/fd679f38/src/unpublish.js ---------------------------------------------------------------------- diff --git a/src/unpublish.js b/src/unpublish.js index 22db926..5a428f1 100644 --- a/src/unpublish.js +++ b/src/unpublish.js @@ -1,18 +1,15 @@ -var registry = require('plugman-registry') - , config = require('../config'); +var registry = require('./registry/registry') module.exports = function(plugin, callback) { - registry.use(config.registry, function(err) { registry.unpublish(plugin, function(err, d) { - if(callback && typeof callback === 'function') { - err ? callback(err) : callback(null); - } else { - if(err) { - throw err; - } else { - console.log('Plugin unpublished'); - } - } + if(callback && typeof callback === 'function') { + err ? callback(err) : callback(null); + } else { + if(err) { + throw err; + } else { + console.log('Plugin unpublished'); + } + } }); - }); }
