You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/05/14 21:46:37 UTC
git commit: giant refactor for dependencies,
part one: changing the way install works.
Updated Branches:
refs/heads/dependencies 14eed99e0 -> 7ea9eda9e
giant refactor for dependencies, part one: changing the way install works.
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/7ea9eda9
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/7ea9eda9
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/7ea9eda9
Branch: refs/heads/dependencies
Commit: 7ea9eda9e427680dd4081da796f7b74211c9f5e5
Parents: 14eed99
Author: Fil Maj <ma...@gmail.com>
Authored: Tue May 14 12:45:56 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Tue May 14 12:46:25 2013 -0700
----------------------------------------------------------------------
main.js | 2 +-
package.json | 3 +-
src/install.js | 183 +++++++++++++----------------
src/platforms/android.js | 65 ++---------
src/platforms/blackberry.js | 55 ++-------
src/platforms/common.js | 13 ++
src/platforms/ios.js | 235 ++++++++++++++++++--------------------
src/util/action-stack.js | 50 ++++++++
src/util/dependencies.js | 56 ---------
src/util/plugins.js | 2 +
10 files changed, 283 insertions(+), 381 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/main.js
----------------------------------------------------------------------
diff --git a/main.js b/main.js
index 8913d02..ca2e000 100755
--- a/main.js
+++ b/main.js
@@ -74,7 +74,7 @@ else {
if (/^[\w-_]+$/.test(key)) cli_variables[key] = tokens.join('=');
});
}
- plugman.install(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, cli_variables, cli_opts.www);
+ plugman.install(cli_opts.platform, cli_opts.project, cli_opts.plugin, plugins_dir, '.', cli_variables, cli_opts.www);
}
function printUsage() {
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 2dfe157..6380287 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,8 @@
"plist": "0.4.x",
"bplist-parser": "0.0.x",
"shelljs": "0.1.x",
- "osenv": "0.0.x"
+ "osenv": "0.0.x",
+ "ncallbacks":"1.1.0"
},
"devDependencies": {
"jasmine-node": "1.7.0"
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/install.js
----------------------------------------------------------------------
diff --git a/src/install.js b/src/install.js
index 37d789c..f73f5f3 100644
--- a/src/install.js
+++ b/src/install.js
@@ -1,12 +1,12 @@
var path = require('path'),
fs = require('fs'),
et = require('elementtree'),
+ n = require('ncallbacks'),
config_changes = require('./util/config-changes'),
- dependencies = require('./util/dependencies'),
+ action_stack = require('./util/action-stack'),
platform_modules = require('./platforms');
-// TODO: is name necessary as a param ehre?
-module.exports = function installPlugin(platform, project_dir, name, plugins_dir, cli_variables, www_dir, callback) {
+module.exports = function installPlugin(platform, project_dir, id, plugins_dir, subdir, cli_variables, www_dir, callback) {
if (!platform_modules[platform]) {
var err = new Error(platform + " not supported.");
if (callback) {
@@ -16,12 +16,12 @@ module.exports = function installPlugin(platform, project_dir, name, plugins_dir
else throw err;
}
- var plugin_dir = path.join(plugins_dir, name);
+ var plugin_dir = path.join(plugins_dir, id);
// Check that the plugin has already been fetched.
if (!fs.existsSync(plugin_dir)) {
// if plugin doesnt exist, use fetch to get it.
- require('../plugman').fetch(name, plugins_dir, false, '.', function(err, plugin_dir) {
+ require('../plugman').fetch(id, plugins_dir, false, subdir, function(err, plugin_dir) {
if (err) {
callback(err);
} else {
@@ -41,6 +41,21 @@ function runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variable
, filtered_variables = {};
var name = plugin_et.findall('name').text;
var plugin_id = plugin_et._root.attrib['id'];
+
+ // check if platform has plugin installed already.
+ var platform_config = config_changes.get_platform_json(plugins_dir, platform);
+ var plugin_basename = path.basename(plugin_dir);
+ var is_fully_installed = false;
+ Object.keys(platform_config.installed_plugins).forEach(function(installed_plugin_id) {
+ if (installed_plugin_id == plugin_id) {
+ is_fully_installed = true;
+ }
+ });
+ if (is_fully_installed) {
+ console.log('Plugin "' + plugin_id + '" already installed. Carry on.');
+ if (callback) callback();
+ return;
+ }
// checking preferences, if certain variables are not provided, we should throw.
prefs = plugin_et.findall('./preference') || [];
@@ -60,115 +75,79 @@ function runInstall(platform, project_dir, plugin_dir, plugins_dir, cli_variable
return;
}
- // check if platform has plugin fully installed or queued already.
- var platform_config = config_changes.get_platform_json(plugins_dir, platform);
- var plugin_basename = path.basename(plugin_dir);
- if (platform_config.prepare_queue.installed.indexOf(plugin_basename) > -1) {
- var err = new Error('plugin "' + plugin_basename + '" is already installed (but needs to be prepared)');
- if (callback) callback(err);
- else throw err;
- return;
- }
- var is_fully_installed = false;
- Object.keys(platform_config.installed_plugins).forEach(function(installed_plugin_id) {
- if (installed_plugin_id == plugin_id) {
- is_fully_installed = true;
- }
- });
- if (is_fully_installed) {
- var err = new Error('plugin "' + plugin_basename + '" (id: '+plugin_id+') is already installed');
- if (callback) callback(err);
- else throw err;
- return;
+ // Check for dependencies, (co)recurse to install each one
+ var dependencies = plugin_et.findall('dependency');
+ if (dependencies && dependencies.length) {
+ var end = n(dependencies.length, function() {
+ handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, callback);
+ });
+ dependencies.forEach(function(dep) {
+ var dep_plugin_id = dep.attrib.id;
+ var dep_subdir = dep.attrib.subdir;
+ var dep_url = dep.attrib.url;
+ if (dep_subdir) {
+ dep_subdir = path.join.apply(null, dep_subdir.split('/'));
+ }
+
+ if (fs.existsSync(path.join(plugins_dir, dep_plugin_id))) {
+ console.log('Dependent plugin ' + dep.attrib.id + ' already fetched, using that version.');
+ module.exports(platform, project_dir, dep_plugin_id, plugins_dir, dep_subdir, filtered_variables, www_dir, end);
+ } else {
+ console.log('Dependent plugin ' + dep.attrib.id + ' not fetched, retrieving then installing.');
+ module.exports(platform, project_dir, dep_url, plugins_dir, dep_subdir, filtered_variables, www_dir, end);
+ }
+ });
+ } else {
+ handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, callback);
}
+}
- // We need to install this plugin, so install its dependencies first.
- dependencies.installAll(platform, project_dir, path.basename(plugin_dir), plugins_dir, cli_variables, www_dir, callback);
+function handleInstall(plugin_id, plugin_et, platform, project_dir, plugins_dir, plugin_basename, plugin_dir, filtered_variables, www_dir, callback) {
+ var handler = platform_modules[platform];
+ www_dir = www_dir || handler.www_dir(project_dir);
- // TODO: if plugin does not have platform tag but has platform-agnostic config changes, should we queue it up?
var platformTag = plugin_et.find('./platform[@name="'+platform+'"]');
- if (!platformTag) {
- // Either this plugin doesn't support this platform, or it's a JS-only plugin.
- // Either way, return now.
- // should call prepare probably!
- finalizeInstall(project_dir, plugins_dir, platform, plugin_basename, filtered_variables, callback);
- return;
- }
+ var assets = plugin_et.findall('asset');
+ if (platformTag) {
+ var sourceFiles = platformTag.findall('./source-file'),
+ headerFiles = platformTag.findall('./header-file'),
+ resourceFiles = platformTag.findall('./resource-file'),
+ frameworks = platformTag.findall('./framework');
+ assets = assets.concat(platformTag.findall('./asset'));
- // parse plugin.xml into transactions
- var handler = platform_modules[platform];
- var txs = [];
- var sourceFiles = platformTag.findall('./source-file'),
- headerFiles = platformTag.findall('./header-file'),
- resourceFiles = platformTag.findall('./resource-file'),
- assets = platformTag.findall('./asset'),
- frameworks = platformTag.findall('./framework');
+ // queue up native stuff
+ sourceFiles && sourceFiles.forEach(function(source) {
+ action_stack.push(action_stack.createAction(handler["source-file"].install, [source, plugin_dir, project_dir], handler["source-file"].uninstall, [source, project_dir]));
+ });
- assets = assets.concat(plugin_et.findall('./asset'));
+ headerFiles && headerFiles.forEach(function(header) {
+ action_stack.push(action_stack.createAction(handler["header-file"].install, [header, plugin_dir, project_dir], handler["header-file"].uninstall, [header, project_dir]));
+ });
- // asset installation
- var installedAssets = [];
- var common = require('./platforms/common');
- www_dir = www_dir || handler.www_dir(project_dir);
- try {
- for(var i = 0, j = assets.length ; i < j ; i++) {
- var src = assets[i].attrib['src'],
- target = assets[i].attrib['target'];
- common.copyFile(plugin_dir, src, www_dir, target);
- installedAssets.push(assets[i]);
- }
- } catch(err) {
- var issue = 'asset installation failed\n'+err.stack+'\n';
- try {
- // removing assets and reverting install
- for(var i = 0, j = installedAssets.length ; i < j ; i++) {
- common.removeFile(www_dir, installedAssets[i].attrib.target);
- }
- common.removeFileF(path.resolve(www_dir, 'plugins', plugin_id));
- issue += 'but successfully reverted\n';
- } catch(err2) {
- issue += 'and reversion failed :(\n' + err2.stack;
- }
- var error = new Error(issue);
- if (callback) callback(error);
- else throw error;
+ resourceFiles && resourceFiles.forEach(function(resource) {
+ action_stack.push(action_stack.createAction(handler["resource-file"].install, [resource, plugin_dir, project_dir], handler["resource-file"].uninstall, [resource, project_dir]));
+ });
+
+ frameworks && frameworks.forEach(function(framework) {
+ action_stack.push(action_stack.createAction(handler["framework"].install, [framework, plugin_dir, project_dir], handler["framework"].uninstall, [framework, project_dir]));
+ });
}
- txs = txs.concat(sourceFiles, headerFiles, resourceFiles, frameworks);
- // pass platform-specific transactions into install
- handler.install(txs, plugin_id, project_dir, plugin_dir, filtered_variables, function(err) {
+
+ // queue up asset installation
+ var common = require('./platforms/common');
+ assets && assets.forEach(function(asset) {
+ action_stack.push(action_stack.createAction(common.asset.install, [asset, plugin_dir, www_dir], common.asset.uninstall, [asset, www_dir, plugin_id]));
+ });
+
+ // run through the action stack
+ action_stack.process(function(err) {
if (err) {
- // FAIL
- var issue = '';
- try {
- for(var i = 0, j = installedAssets.length ; i < j ; i++) {
- common.removeFile(www_dir, installedAssets[i].attrib.target);
- }
- common.removeFileF(path.resolve(www_dir, 'plugins', plugin_id));
- } catch(err2) {
- issue += 'Could not revert assets' + err2.stack + '\n';
- }
- if (err.transactions) {
- handler.uninstall(err.transactions.executed, plugin_id, project_dir, plugin_dir, function(superr) {
-
- if (superr) {
- // Even reversion failed. super fail.
- issue += 'Install failed, then reversion of installation failed. Sorry :(. Instalation issue: ' + err.stack + ', reversion issue: ' + superr.stack;
- } else {
- issue += 'Install failed, plugin reversion successful so you should be good to go. Installation issue: ' + err.stack;
- }
- var error = new Error(issue);
- if (callback) callback(error);
- else throw error;
- });
- } else {
- if (callback) callback(err);
- else throw err;
- }
+ console.error(err.message, err.stack);
+ console.error('Plugin installation failed :(');
} else {
-
// WIN!
// Log out plugin INFO element contents in case additional install steps are necessary
- var info = platformTag.findall('./info');
+ var info = (platformTag ? platformTag.findall('./info') : '');
if(info.length) {
console.log(info[0].text);
}
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/platforms/android.js
----------------------------------------------------------------------
diff --git a/src/platforms/android.js b/src/platforms/android.js
index cf62f93..cda9e72 100644
--- a/src/platforms/android.js
+++ b/src/platforms/android.js
@@ -19,19 +19,10 @@
var fs = require('fs') // use existsSync in 0.6.x
, path = require('path')
- , shell = require('shelljs')
, common = require('./common')
- , getConfigChanges = require(path.join(__dirname, '..', 'util', 'config-changes'))
- , plugins_module = require(path.join(__dirname, '..', 'util', 'plugins'))
, xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'));
module.exports = {
- install:function(transactions, plugin_id, project_dir, plugin_dir, variables, callback) {
- handlePlugin('install', plugin_id, transactions, project_dir, plugin_dir, variables, callback);
- },
- uninstall:function(transactions, plugin_id, project_dir, plugin_dir, callback) {
- handlePlugin('uninstall', plugin_id, transactions, project_dir, plugin_dir, null, callback);
- },
www_dir:function(project_dir) {
return path.join(project_dir, 'assets', 'www');
},
@@ -42,51 +33,15 @@ module.exports = {
var mDoc = xml_helpers.parseElementtreeSync(path.join(project_dir, 'AndroidManifest.xml'));
return mDoc._root.attrib['package'];
- }
-};
-
-function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
- variables = variables || {};
-
- // TODO: adding access tags?
- // TODO: move this to prepare?
- /*
- var root = et.Element("config-file");
- root.attrib['parent'] = '.';
- plugin_et.findall('./access').forEach(function (tag) {
- root.append(tag);
- });
- */
- var completed = [];
- while(txs.length) {
- var mod = txs.shift();
- try {
- switch(mod.tag.toLowerCase()) {
- case 'source-file':
- var destFile = path.join(mod.attrib['target-dir'], path.basename(mod.attrib['src']));
-
- if (action == 'install') {
- common.copyFile(plugin_dir, mod.attrib['src'], project_dir, destFile);
- } else {
- common.deleteJava(project_dir, destFile);
- }
- break;
- default:
- throw new Error('Unrecognized plugin.xml element/action in android installer: ' + mod.tag);
- break;
- }
- } catch(e) {
- // propagate error up and provide completed tx log
- e.transactions = {
- executed:completed,
- incomplete:txs.unshift(mod)
- };
- if (callback) callback(e);
- else throw e;
- return;
+ },
+ "source-file":{
+ install:function(source_el, plugin_dir, project_dir) {
+ var dest = path.join(source_el.attrib['target-dir'], path.basename(source_el.attrib['src']));
+ common.copyFile(plugin_dir, source_el.attrib['src'], project_dir, dest);
+ },
+ uninstall:function(source_el, project_dir) {
+ var dest = path.join(source_el.attrib['target-dir'], path.basename(source_el.attrib['src']));
+ common.deleteJava(project_dir, dest);
}
- completed.push(mod);
}
-
- if (callback) callback();
-}
+};
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/platforms/blackberry.js
----------------------------------------------------------------------
diff --git a/src/platforms/blackberry.js b/src/platforms/blackberry.js
index 9643a77..353ef92 100644
--- a/src/platforms/blackberry.js
+++ b/src/platforms/blackberry.js
@@ -19,59 +19,26 @@
var fs = require('fs') // use existsSync in 0.6.x
, path = require('path')
- , shell = require('shelljs')
- , et = require('elementtree')
- , getConfigChanges = require('../util/config-changes')
, common = require('./common')
, xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'));
module.exports = {
- install:function(transactions, plugin_id, project_dir, plugin_dir, variables, callback) {
- handlePlugin('install', plugin_id, transactions, project_dir, plugin_dir, variables, callback);
- },
- uninstall:function(transactions, plugin_id, project_dir, plugin_dir, callback) {
- handlePlugin('uninstall', plugin_id, transactions, project_dir, plugin_dir, null, callback);
- },
www_dir:function(project_dir) {
return path.join(project_dir, 'www');
},
package_name:function(project_dir) {
var config_path = path.join(module.exports.www_dir(project_dir), 'config.xml');
- var widget_doc = new et.ElementTree(et.XML(fs.readFileSync(config_path, 'utf-8')));
+ var widget_doc = xml_helpers.parseElementtreeSync(config_path);
return widget_doc._root.attrib['id'];
- }
-};
-
-function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
- var completed = [];
- while(txs.length) {
- var mod = txs.shift();
- try {
- switch(mod.tag.toLowerCase()) {
- case 'source-file':
- var destFile = path.join(mod.attrib['target-dir'], path.basename(mod.attrib['src']));
-
- if (action == 'install') {
- common.copyFile(plugin_dir, mod.attrib['src'], project_dir, destFile);
- } else {
- common.deleteJava(project_dir, destFile);
- }
- break;
- default:
- throw new Error('Unrecognized plugin.xml element/action in blackberry installer: ' + mod.tag);
- break;
- }
- } catch(e) {
- // propagate error up and provide completed tx log
- e.transactions = {
- executed:completed,
- incomplete:txs.unshift(mod)
- };
- if (callback) callback(e);
- else throw e;
- return;
+ },
+ "source-file":{
+ install:function(source_el, plugin_dir, project_dir) {
+ var dest = path.join(source_el.attrib['target-dir'], path.basename(source_el.attrib['src']));
+ common.copyFile(plugin_dir, source_el.attrib['src'], project_dir, dest);
+ },
+ uninstall:function(source_el, project_dir) {
+ var dest = path.join(source_el.attrib['target-dir'], path.basename(source_el.attrib['src']));
+ common.deleteJava(project_dir, dest);
}
- completed.push(mod);
}
- if (callback) callback();
-}
+};
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/platforms/common.js
----------------------------------------------------------------------
diff --git a/src/platforms/common.js b/src/platforms/common.js
index 7d294b9..d4ee21d 100644
--- a/src/platforms/common.js
+++ b/src/platforms/common.js
@@ -55,5 +55,18 @@ module.exports = {
break;
}
}
+ },
+ // handle <asset> elements
+ asset:{
+ install:function(asset_el, plugin_dir, www_dir) {
+ var src = asset_el.attrib.src;
+ var target = asset_el.attrib.target;
+ module.exports.copyFile(plugin_dir, src, www_dir, target);
+ },
+ uninstall:function(asset_el, www_dir, plugin_id) {
+ var target = asset_el.attrib.target;
+ module.exports.removeFile(www_dir, target);
+ module.exports.removeFileF(path.resolve(www_dir, 'plugins', plugin_id));
+ }
}
};
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/platforms/ios.js
----------------------------------------------------------------------
diff --git a/src/platforms/ios.js b/src/platforms/ios.js
index 4c012d7..c0187c5 100644
--- a/src/platforms/ios.js
+++ b/src/platforms/ios.js
@@ -20,44 +20,130 @@
var path = require('path')
, fs = require('../util/fs') // use existsSync in 0.6.x
, glob = require('glob')
- , et = require('elementtree')
, xcode = require('xcode')
, plist = require('plist')
- , bplist = require('bplist-parser')
- , shell = require('shelljs')
- , common = require('./common')
- , xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'))
- , searchAndReplace = require(path.join(__dirname, '..', 'util', 'search-and-replace'))
- , getConfigChanges = require(path.join(__dirname, '..', 'util', 'config-changes'));
+ , shell = require('shelljs');
module.exports = {
- install:function(transactions, plugin_id, project_dir, plugin_dir, variables, callback) {
- handlePlugin('install', plugin_id, transactions, project_dir, plugin_dir, variables, callback);
- },
- uninstall:function(transactions, plugin_id, project_dir, plugin_dir, callback) {
- handlePlugin('uninstall', plugin_id, transactions, project_dir, plugin_dir, null, callback);
- },
www_dir:function(project_dir) {
return path.join(project_dir, 'www');
},
package_name:function(project_dir) {
var plist_file = glob.sync(path.join(project_dir, '**', '*-Info.plist'))[0];
return plist.parseFileSync(plist_file).CFBundleIdentifier;
+ },
+ "source-file":{
+ install:function(source_el, plugin_dir, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = source_el.attrib['src'];
+ var srcFile = path.resolve(plugin_dir, src);
+ var targetDir = path.resolve(project.plugins_dir, getRelativeDir(source_el));
+ var destFile = path.resolve(targetDir, path.basename(src));
+
+ if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <source-file>');
+ if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
+ project.xcode.addSourceFile(path.join('Plugins', path.relative(project.plugins_dir, destFile)));
+ shell.mkdir('-p', targetDir);
+ shell.cp(srcFile, destFile);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ },
+ uninstall:function(source_el, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = source_el.attrib['src'];
+ var targetDir = path.resolve(project.plugins_dir, getRelativeDir(source_el));
+ var destFile = path.resolve(targetDir, path.basename(src));
+
+ project.xcode.removeSourceFile(path.join('Plugins', path.relative(project.plugins_dir, destFile)));
+ shell.rm('-rf', destFile);
+
+ if(fs.existsSync(targetDir) && fs.readdirSync(targetDir).length>0){
+ shell.rm('-rf', targetDir);
+ }
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ }
+ },
+ "header-file":{
+ install:function(header_el, plugin_dir, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = header_el.attrib['src'];
+ var srcFile = path.resolve(plugin_dir, src);
+ var targetDir = path.resolve(project.plugins_dir, getRelativeDir(header_el));
+ var destFile = path.resolve(targetDir, path.basename(src));
+ if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <header-file>');
+ if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
+ project.xcode.addHeaderFile(path.join('Plugins', path.relative(project.plugins_dir, destFile)));
+ shell.mkdir('-p', targetDir);
+ shell.cp(srcFile, destFile);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ },
+ uninstall:function(header_el, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = header_el.attrib['src'];
+ var srcFile = path.resolve(plugin_dir, src);
+ var targetDir = path.resolve(project.plugins_dir, getRelativeDir(header_el));
+ var destFile = path.resolve(targetDir, path.basename(src));
+ project.xcode.removeHeaderFile(path.join('Plugins', path.relative(project.plugins_dir, destFile)));
+ shell.rm('-rf', destFile);
+ if(fs.existsSync(targetDir) && fs.readdirSync(targetDir).length>0){
+ shell.rm('-rf', targetDir);
+ }
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ }
+ },
+ "resource-file":{
+ install:function(resource_el, plugin_dir, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = resource_el.attrib['src'],
+ srcFile = path.resolve(plugin_dir, src),
+ destFile = path.resolve(project.resources_dir, path.basename(src));
+ if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <resource-file>');
+ if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
+ project.xcode.addResourceFile(path.join('Resources', path.basename(src)));
+ shell.cp('-R', srcFile, resourcesDir);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ },
+ uninstall:function(resource_el, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = resource_el.attrib['src'],
+ destFile = path.resolve(project.resources_dir, path.basename(src));
+ project.xcode.removeResourceFile(path.join('Resources', path.basename(src)));
+ shell.rm('-rf', destFile);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ }
+ },
+ "framework":{
+ install:function(framework_el, plugin_dir, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = framework_el.attrib['src'],
+ weak = framework_el.attrib['weak'];
+ var opt = { weak: (weak == undefined || weak == null || weak != 'true' ? false : true ) };
+ project.xcode.addFramework(src, opt);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ },
+ uninstall:function(framework_el, project_dir) {
+ var project = getIOSProjectFiles(project_dir);
+ var src = framework_el.attrib['src'];
+ project.xcode.removeFramework(src);
+ // write out xcodeproj file
+ fs.writeFileSync(project.pbx, project.xcode.writeSync());
+ }
}
};
-function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables, callback) {
- variables = variables || {};
-
+function getIOSProjectFiles(project_dir) {
// grab and parse pbxproj
// we don't want CordovaLib's xcode project
var project_files = glob.sync(path.join(project_dir, '*.xcodeproj', 'project.pbxproj'));
if (project_files.length === 0) {
- var err = new Error("does not appear to be an xcode project (no xcode project file)");
- if (callback) callback(err);
- else throw err;
- return;
+ throw new Error("does not appear to be an xcode project (no xcode project file)");
}
var pbxPath = project_files[0];
var xcodeproj = xcode.project(pbxPath);
@@ -74,10 +160,7 @@ function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables
});
if (config_files.length === 0) {
- var err = new Error("could not find PhoneGap/Cordova plist file, or config.xml file.");
- if (callback) callback(err);
- else throw err;
- return;
+ throw new Error("could not find PhoneGap/Cordova plist file, or config.xml file.");
}
var config_file = config_files[0];
@@ -92,95 +175,12 @@ function handlePlugin(action, plugin_id, txs, project_dir, plugin_dir, variables
// for certain config changes, we need to know if plugins-plist elements are present
var plistEle = txs.filter(function(t) { return t.tag.toLowerCase() == 'plugins-plist'; })[0];
- var completed = [];
- while(txs.length) {
- var mod = txs.shift();
- try {
- switch(mod.tag.toLowerCase()) {
- case 'source-file':
- var src = mod.attrib['src'];
- var srcFile = path.resolve(plugin_dir, src);
- var targetDir = path.resolve(pluginsDir, getRelativeDir(mod));
- var destFile = path.resolve(targetDir, path.basename(src));
- if (action == 'install') {
- if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <source-file>');
- if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
- xcodeproj.addSourceFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
- shell.mkdir('-p', targetDir);
- shell.cp(srcFile, destFile);
- } else {
- xcodeproj.removeSourceFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
- shell.rm('-rf', destFile);
-
- if(fs.existsSync(targetDir) && fs.readdirSync(targetDir).length>0){
- shell.rm('-rf', targetDir);
- }
- }
- break;
- case 'header-file':
- var src = mod.attrib['src'];
- var srcFile = path.resolve(plugin_dir, src);
- var targetDir = path.resolve(pluginsDir, getRelativeDir(mod));
- var destFile = path.resolve(targetDir, path.basename(src));
- if (action == 'install') {
- if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <header-file>');
- if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
- xcodeproj.addHeaderFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
- shell.mkdir('-p', targetDir);
- shell.cp(srcFile, destFile);
- } else {
- // TODO: doesnt preserve-dirs affect what the originally-added path to xcodeproj (see above) affect how we should call remove too?
- xcodeproj.removeHeaderFile(path.join('Plugins', path.relative(pluginsDir, destFile)));
- shell.rm('-rf', destFile);
- // TODO: again.. is this right? same as source-file
- shell.rm('-rf', targetDir);
- }
- break;
- case 'resource-file':
- var src = mod.attrib['src'],
- srcFile = path.resolve(plugin_dir, src),
- destFile = path.resolve(resourcesDir, path.basename(src));
-
- if (action == 'install') {
- if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <resource-file>');
- if (fs.existsSync(destFile)) throw new Error('target destination "' + destFile + '" already exists');
- xcodeproj.addResourceFile(path.join('Resources', path.basename(src)));
- shell.cp('-R', srcFile, resourcesDir);
- } else {
- xcodeproj.removeResourceFile(path.join('Resources', path.basename(src)));
- shell.rm('-rf', destFile);
- }
- break;
- case 'framework':
- var src = mod.attrib['src'],
- weak = mod.attrib['weak'];
- if (action == 'install') {
- var opt = { weak: (weak == undefined || weak == null || weak != 'true' ? false : true ) };
- xcodeproj.addFramework(src, opt);
- } else {
- xcodeproj.removeFramework(src);
- }
- break;
- default:
- throw new Error('Unrecognized plugin.xml element/action in ios installer: ' + mod.tag);
- break;
- }
- } catch(e) {
- // propagate error up and provide completed tx log
- e.transactions = {
- executed:completed,
- incomplete:txs.unshift(mod)
- };
- if (callback) callback(e);
- else throw e;
- return;
- }
- completed.push(mod);
- }
- // write out xcodeproj file
- fs.writeFileSync(pbxPath, xcodeproj.writeSync());
-
- if (callback) callback();
+ return {
+ plugins_dir:pluginsDir,
+ resources_dir:resourcesDir,
+ xcode:xcodeproj,
+ pbx:pbxPath
+ };
}
function getRelativeDir(file) {
@@ -191,12 +191,3 @@ function getRelativeDir(file) {
return '';
}
}
-
-// determine if a plist file is binary
-function isBinaryPlist(filename) {
- // I wish there was a synchronous way to read only the first 6 bytes of a
- // file. This is wasteful :/
- var buf = '' + fs.readFileSync(filename, 'utf8');
- // binary plists start with a magic header, "bplist"
- return buf.substring(0, 6) === 'bplist';
-}
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/util/action-stack.js
----------------------------------------------------------------------
diff --git a/src/util/action-stack.js b/src/util/action-stack.js
new file mode 100644
index 0000000..849bb54
--- /dev/null
+++ b/src/util/action-stack.js
@@ -0,0 +1,50 @@
+var stack = [];
+var completed = [];
+
+module.exports = {
+ createAction:function(handler, action_params, reverter, revert_params) {
+ return {
+ handler:{
+ run:handler,
+ params:action_params
+ },
+ reverter:{
+ run:reverter,
+ params:revert_params
+ }
+ };
+ },
+ push:function(tx) {
+ stack.push(tx);
+ },
+ process:function(callback) {
+ while(stack.length) {
+ var action = stack.shift();
+ var handler = action.handler.run;
+ var action_params = action.handler.params;
+ try {
+ handler.apply(null, action_params);
+ } catch(e) {
+ var incomplete = stack.unshift(action);
+ var issue = 'Install failed!\n';
+ // revert completed tasks
+ while(completed.length) {
+ var undo = completed.shift();
+ var revert = undo.reverter.run;
+ var revert_params = undo.reverter.params;
+ try {
+ revert.apply(null, revert_params);
+ } catch(err) {
+ issue += 'A reversion action failed: ' + err.message + '\n';
+ }
+ }
+ e.message = issue + e.message;
+ if (callback) callback(e);
+ else throw e;
+ return;
+ }
+ completed.push(action);
+ }
+ if (callback) callback();
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/util/dependencies.js
----------------------------------------------------------------------
diff --git a/src/util/dependencies.js b/src/util/dependencies.js
deleted file mode 100644
index 9f7a594..0000000
--- a/src/util/dependencies.js
+++ /dev/null
@@ -1,56 +0,0 @@
-var install = require('../install'),
- fetch = require('../fetch'),
- path = require('path'),
- fs = require('fs'),
- xml_helpers = require('./xml-helpers');
-
-exports.installAll = function(platform, project_dir, name, plugins_dir, cli_variables, www_dir, callback) {
- // It should have been fetched already, so read the plugin.xml from plugin_dir
- var plugin_dir = path.join(plugins_dir, name);
- var xml = xml_helpers.parseElementtreeSync(path.join(plugin_dir, 'plugin.xml'));
-
- var dependencies = xml.findall('dependency');
-
- if (!dependencies || dependencies.length == 0) {
- return;
- }
-
- function waitForAll(n) {
- var count = n;
- var errs = [];
- return function(err) {
- count--;
- if (err) {
- throw err;
- }
- if (count == 0) {
- callback();
- }
- };
- }
-
- var dependencyCallback = waitForAll(dependencies.length);
-
- dependencies && dependencies.forEach(function(dep) {
- function doInstall(plugin_dir) {
- // Call installation for this plugin after it gets fetched.
- install(platform, project_dir, path.basename(plugin_dir), plugins_dir, cli_variables, www_dir, dependencyCallback);
- }
-
- // Check if this dependency is already there.
- if (fs.existsSync(path.join(plugins_dir, dep.attrib.id))) {
- console.log('Plugin ' + dep.attrib.id + ' already fetched, using that version.');
- doInstall(path.join(plugins_dir, dep.attrib.id));
- } else {
- // Fetch it.
- var subdir = dep.attrib.subdir;
- if (subdir) {
- subdir = path.join.apply(null, dep.attrib.subdir.split('/'));
- }
-
- console.log('Fetching dependency ' + dep.attrib.id);
- fetch(dep.attrib.url, plugins_dir, false /* no link */, subdir, doInstall);
- }
- });
-};
-
http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ea9eda9/src/util/plugins.js
----------------------------------------------------------------------
diff --git a/src/util/plugins.js b/src/util/plugins.js
index ff9cace..d5141cb 100644
--- a/src/util/plugins.js
+++ b/src/util/plugins.js
@@ -53,6 +53,8 @@ module.exports = {
var xml = xml_helpers.parseElementtreeSync(xml_file);
var plugin_id = xml.getroot().attrib.id;
+ // TODO: what if a plugin dependended on different subdirectories of the same plugin? this would fail.
+ // should probably copy over entire plugin git repo contents into plugins_dir and handle subdir seperately during install.
var plugin_dir = path.join(plugins_dir, plugin_id);
shell.cp('-R', path.join(tmp_dir, '*'), plugin_dir);