cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fil...@apache.org
Subject git commit: giant refactor for dependencies, part one: changing the way install works.
Date Tue, 14 May 2013 19:46:37 GMT
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 <maj.fil@gmail.com>
Authored: Tue May 14 12:45:56 2013 -0700
Committer: Fil Maj <maj.fil@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);
 


Mime
View raw message