You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ka...@apache.org on 2014/06/03 20:50:02 UTC

[2/2] git commit: CB-6698: Support library references for Android via the framework tag

CB-6698: Support library references for Android via the framework tag


Project: http://git-wip-us.apache.org/repos/asf/cordova-lib/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-lib/commit/513967db
Tree: http://git-wip-us.apache.org/repos/asf/cordova-lib/tree/513967db
Diff: http://git-wip-us.apache.org/repos/asf/cordova-lib/diff/513967db

Branch: refs/heads/master
Commit: 513967dbc8f983ebfe08ba7b96cfc4211ffd7515
Parents: 71e7ba3
Author: Martin Bektchiev <ma...@telerik.com>
Authored: Tue May 27 14:53:19 2014 +0300
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Tue Jun 3 14:44:03 2014 -0400

----------------------------------------------------------------------
 cordova-lib/npm-shrinkwrap.json                 |   3 +
 cordova-lib/package.json                        |  49 ++++----
 .../spec-plugman/platforms/android.spec.js      |  91 +++++++++++++++
 .../spec-plugman/util/action-stack.spec.js      |  14 +--
 cordova-lib/src/plugman/install.js              |   2 +-
 cordova-lib/src/plugman/platforms/android.js    | 115 ++++++++++++++++++-
 cordova-lib/src/plugman/platforms/ios.js        |   2 +-
 cordova-lib/src/plugman/util/config-changes.js  |  22 ++--
 8 files changed, 252 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/npm-shrinkwrap.json
----------------------------------------------------------------------
diff --git a/cordova-lib/npm-shrinkwrap.json b/cordova-lib/npm-shrinkwrap.json
index 2debb81..3e53081 100644
--- a/cordova-lib/npm-shrinkwrap.json
+++ b/cordova-lib/npm-shrinkwrap.json
@@ -464,6 +464,9 @@
         }
       }
     },
+    "properties-parser": {
+      "from": "git://github.com/mbektchiev/node-properties-parser#cordova-lib"
+    },
     "q": {
       "version": "0.9.7",
       "from": "q@~0.9"

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/package.json
----------------------------------------------------------------------
diff --git a/cordova-lib/package.json b/cordova-lib/package.json
index 77344bd..fda29d6 100644
--- a/cordova-lib/package.json
+++ b/cordova-lib/package.json
@@ -8,36 +8,37 @@
     "url": "git://git-wip-us.apache.org/repos/asf/cordova-lib.git"
   },
   "bugs": {
-    "url" : "https://issues.apache.org/jira/browse/CB",
-    "email" : "dev@cordova.apache.org"
+    "url": "https://issues.apache.org/jira/browse/CB",
+    "email": "dev@cordova.apache.org"
   },
   "main": "cordova-lib.js",
   "engines": {
     "node": ">=0.9.9"
   },
-  "engineStrict":true,
+  "engineStrict": true,
   "dependencies": {
-    "glob": "3.2.x",
+    "bplist-parser": "0.0.x",
+    "dep-graph": "1.1.0",
     "elementtree": "0.1.5",
-    "xcode": "0.6.6",
+    "glob": "3.2.x",
+    "mime": "~1.2.11",
+    "npm": "1.3.4",
+    "npmconf": "0.1.x",
+    "osenv": "0.0.x",
     "plist-with-patches": "0.5.x",
-    "bplist-parser": "0.0.x",
-    "shelljs": "0.1.x",
-    "underscore":"1.4.4",
-    "dep-graph":"1.1.0",
-    "semver": "2.0.x",
+    "properties-parser": "git://github.com/mbektchiev/node-properties-parser",
     "q": "~0.9",
-    "npm": "1.3.4",
     "rc": "0.3.0",
-    "tar": "0.1.x",
     "request": "2.22.0",
-    "npmconf": "0.1.x",
-    "mime": "~1.2.11",
-    "osenv": "0.0.x"
+    "semver": "2.0.x",
+    "shelljs": "0.1.x",
+    "tar": "0.1.x",
+    "underscore": "1.4.4",
+    "xcode": "0.6.6"
   },
   "devDependencies": {
     "temp": "0.6.x",
-    "jasmine-node": "~1"  
+    "jasmine-node": "~1"
   },
   "scripts": {
     "test": "jasmine-node --color spec-plugman spec-cordova"
@@ -136,26 +137,26 @@
       "email": "stevengill97@gmail.com"
     },
     {
-      "name":"Jesse",
-      "email":"purplecabbage@gmail.com"
+      "name": "Jesse",
+      "email": "purplecabbage@gmail.com"
     },
     {
-        "name":"Anis Kadri"
+      "name": "Anis Kadri"
     },
     {
-        "name":"Ryan Willoughby"
+      "name": "Ryan Willoughby"
     },
     {
-        "name":"Brett Rudd"
+      "name": "Brett Rudd"
     },
     {
-        "name":"Shazron Abdullah"
+      "name": "Shazron Abdullah"
     },
     {
-        "name":"Steve Gill"
+      "name": "Steve Gill"
     },
     {
-        "name":"Jesse MacFadyen"
+      "name": "Jesse MacFadyen"
     }
   ]
 }

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/spec-plugman/platforms/android.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/platforms/android.spec.js b/cordova-lib/spec-plugman/platforms/android.spec.js
index 1bacc27..df11ec7 100644
--- a/cordova-lib/spec-plugman/platforms/android.spec.js
+++ b/cordova-lib/spec-plugman/platforms/android.spec.js
@@ -6,6 +6,7 @@ var android = require('../../src/plugman/platforms/android'),
     shell   = require('shelljs'),
     et      = require('elementtree'),
     os      = require('osenv'),
+    _       = require('underscore'),
     temp    = path.join(os.tmpdir(), 'plugman'),
     plugins_dir = path.join(temp, 'cordova', 'plugins'),
     xml_helpers = require('../../src/util/xml-helpers'),
@@ -113,6 +114,75 @@ describe('android project handler', function() {
                 }).toThrow('"' + target + '" already exists!');
             });
         });
+        describe('of <framework> elements', function() {
+            afterEach(function() {
+                android.purgeProjectFileCache(temp);
+            });
+            it('should update the main and library projects', function() {
+                var frameworkElement = { attrib: { src: "LibraryPath", custom: true } };
+                var subDir = path.resolve(temp, frameworkElement.attrib.src);
+                var mainProjectPropsFile = path.resolve(temp, "project.properties");
+                var subProjectPropsFile = path.resolve(subDir, "project.properties");
+
+                var existsSync = spyOn( fs, 'existsSync').andReturn(true);
+                var writeFileSync = spyOn(fs, 'writeFileSync');
+                var readFileSync = spyOn(fs, 'readFileSync').andCallFake(function (file) {
+                    if (path.normalize(file) === mainProjectPropsFile) {
+                        return '#Some comment\ntarget=android-19\nandroid.library.reference.1=ExistingLibRef1\nandroid.library.reference.2=ExistingLibRef2';
+                    } else if (path.normalize(file) === subProjectPropsFile) {
+                        return '#Some comment\ntarget=android-17\nandroid.library=true';
+                    } else {
+                        throw new Error("Trying to read from an unexpected file " + file);
+                    }
+                })
+                var exec = spyOn(shell, 'exec');
+
+                android['framework'].install(frameworkElement, dummyplugin, temp);
+                android.parseProjectFile(temp).write();
+
+                expect(_.any(writeFileSync.argsForCall, function (callArgs) {
+                    return callArgs[0] === mainProjectPropsFile && callArgs[1].indexOf('\nandroid.library.reference.3=LibraryPath\n') > -1;
+                })).toBe(true, 'Reference to library not added');
+                expect(_.any(writeFileSync.argsForCall, function (callArgs) {
+                    return callArgs[0] === subProjectPropsFile && callArgs[1].indexOf('\ntarget=android-19\n') > -1;
+                })).toBe(true, 'target SDK version not copied to library');
+                expect(exec).toHaveBeenCalledWith('android update lib-project --path ' + subDir);
+            });
+            it('with custom=false should update the main and library projects', function() {
+                var frameworkElement = { attrib: { src: "extras/android/support/v7/appcompat" } };
+                var subDir = path.resolve("~/android-sdk", frameworkElement.attrib.src);
+                var localPropsFile = path.resolve(temp, "local.properties");
+                var mainProjectPropsFile = path.resolve(temp, "project.properties");
+                var subProjectPropsFile = path.resolve(subDir, "project.properties");
+
+                var existsSync = spyOn( fs, 'existsSync').andReturn(true);
+                var writeFileSync = spyOn(fs, 'writeFileSync');
+                var readFileSync = spyOn(fs, 'readFileSync').andCallFake(function (file) {
+                    if (path.normalize(file) === mainProjectPropsFile) {
+                        return '#Some comment\ntarget=android-19\nandroid.library.reference.1=ExistingLibRef1\nandroid.library.reference.2=ExistingLibRef2';
+                    } else if (path.normalize(file) === subProjectPropsFile) {
+                        return '#Some comment\ntarget=android-17\nandroid.library=true';
+                    } else if (path.normalize(file) === localPropsFile) {
+                        return "sdk.dir=~/android-sdk";
+                    } else {
+                        throw new Error("Trying to read from an unexpected file " + file);
+                    }
+                })
+                var exec = spyOn(shell, 'exec');
+
+                android['framework'].install(frameworkElement, dummyplugin, temp);
+                android.parseProjectFile(temp).write();
+
+                var relativePath = android.getRelativeLibraryPath(temp, subDir);
+                expect(_.any(writeFileSync.argsForCall, function (callArgs) {
+                    return callArgs[0] === mainProjectPropsFile && callArgs[1].indexOf('\nandroid.library.reference.3=' + relativePath + '\n') > -1;
+                })).toBe(true, 'Reference to library not added');
+                expect(_.any(writeFileSync.argsForCall, function (callArgs) {
+                    return callArgs[0] === subProjectPropsFile && callArgs[1].indexOf('\ntarget=android-19\n') > -1;
+                })).toBe(true, 'target SDK version not copied to library');
+                expect(exec).toHaveBeenCalledWith('android update lib-project --path ' + subDir);
+            });
+        });
     });
 
     describe('uninstallation', function() {
@@ -152,5 +222,26 @@ describe('android project handler', function() {
                 });
             });
         });
+        describe('of <framework> elements', function() {
+            it('should remove library reference from the main project', function() {
+                var frameworkElement = { attrib: { src: "LibraryPath" } };
+                var sub_dir = path.resolve(temp, frameworkElement.attrib.src);
+                var mainProjectProps = path.resolve(temp, "project.properties");
+                var existsSync = spyOn( fs, 'existsSync').andReturn(true);
+                var writeFileSync = spyOn(fs, 'writeFileSync');
+                var readFileSync = spyOn(fs, 'readFileSync').andCallFake(function (file) {
+                    if (path.normalize(file) === mainProjectProps)
+                        return '#Some comment\ntarget=android-19\nandroid.library.reference.1=ExistingLibRef1\nandroid.library.reference.2=LibraryPath\nandroid.library.reference.3=ExistingLibRef2\n';
+                })
+                var exec = spyOn(shell, 'exec');
+
+                android['framework'].uninstall(frameworkElement, temp);
+                android.parseProjectFile(temp).write();
+
+                expect(_.any(writeFileSync.argsForCall, function (callArgs) {
+                    return callArgs[0] === mainProjectProps && callArgs[1].indexOf('\nandroid.library.reference.2=ExistingLibRef2\n') > -1;
+                })).toBe(true, 'Reference to library not removed');
+            });
+        });
     });
 });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/spec-plugman/util/action-stack.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/util/action-stack.spec.js b/cordova-lib/spec-plugman/util/action-stack.spec.js
index ef59164..b55ce73 100644
--- a/cordova-lib/spec-plugman/util/action-stack.spec.js
+++ b/cordova-lib/spec-plugman/util/action-stack.spec.js
@@ -18,9 +18,9 @@ describe('action-stack', function() {
             stack.push(stack.createAction(second_spy, second_args, function(){}, []));
             stack.push(stack.createAction(third_spy, third_args, function(){}, []));
             stack.process('android', 'blah');
-            expect(first_spy).toHaveBeenCalledWith(first_args[0]);
-            expect(second_spy).toHaveBeenCalledWith(second_args[0]);
-            expect(third_spy).toHaveBeenCalledWith(third_args[0]);
+            expect(first_spy).toHaveBeenCalledWith(first_args[0], jasmine.any(Object));
+            expect(second_spy).toHaveBeenCalledWith(second_args[0], jasmine.any(Object));
+            expect(third_spy).toHaveBeenCalledWith(third_args[0], jasmine.any(Object));
         });
         it('should revert processed actions if an exception occurs', function() {
             spyOn(console, 'log');
@@ -47,11 +47,11 @@ describe('action-stack', function() {
             runs(function() {
                 expect(error).toEqual(process_err);
                 // first two actions should have been called, but not the third
-                expect(first_spy).toHaveBeenCalledWith(first_args[0]);
-                expect(second_spy).toHaveBeenCalledWith(second_args[0]);
-                expect(third_spy).not.toHaveBeenCalledWith(third_args[0]);
+                expect(first_spy).toHaveBeenCalledWith(first_args[0], jasmine.any(Object));
+                expect(second_spy).toHaveBeenCalledWith(second_args[0], jasmine.any(Object));
+                expect(third_spy).not.toHaveBeenCalledWith(third_args[0], jasmine.any(Object));
                 // first reverter should have been called after second action exploded
-                expect(first_reverter).toHaveBeenCalledWith(first_reverter_args[0]);
+                expect(first_reverter).toHaveBeenCalledWith(first_reverter_args[0], jasmine.any(Object));
             });
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/src/plugman/install.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/install.js b/cordova-lib/src/plugman/install.js
index d779989..2fbbe50 100644
--- a/cordova-lib/src/plugman/install.js
+++ b/cordova-lib/src/plugman/install.js
@@ -493,7 +493,7 @@ function handleInstall(actions, pluginInfo, platform, project_dir, plugins_dir,
         var sourceFiles = platformTag.findall('./source-file'),
             headerFiles = platformTag.findall('./header-file'),
             resourceFiles = platformTag.findall('./resource-file'),
-            frameworkFiles = platformTag.findall('./framework[@custom="true"]'), // CB-5238 adding only custom frameworks
+            frameworkFiles = platformTag.findall('./framework'),
             libFiles = platformTag.findall('./lib-file');
 
 

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/src/plugman/platforms/android.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/platforms/android.js b/cordova-lib/src/plugman/platforms/android.js
index 0147d08..e105c5b 100644
--- a/cordova-lib/src/plugman/platforms/android.js
+++ b/cordova-lib/src/plugman/platforms/android.js
@@ -21,7 +21,11 @@ var fs = require('fs')  // use existsSync in 0.6.x
    , path = require('path')
    , common = require('./common')
    , events = require('../events')
-   , xml_helpers = require(path.join(__dirname, '..', '..', 'util', 'xml-helpers'));
+   , xml_helpers = require(path.join(__dirname, '..', '..', 'util', 'xml-helpers'))
+   , properties_parser = require('properties-parser')
+   , shell = require('shelljs');
+
+var projectFileCache = {};
 
 module.exports = {
     www_dir:function(project_dir) {
@@ -80,10 +84,115 @@ module.exports = {
     },
     "framework": {
         install:function(source_el, plugin_dir, project_dir, plugin_id) {
-            events.emit('verbose', 'framework.install is not supported for android');
+            var src = source_el.attrib.src;
+            var custom = source_el.attrib.custom;
+            if (!src) throw new Error('src not specified in framework element');
+
+            events.emit('verbose', "Installing Android library: " + src);
+            var parent = source_el.attrib.parent;
+            var parentDir = parent ? path.resolve(project_dir, parent) : project_dir;
+            var subDir;
+            if (custom) {
+                subDir = path.resolve(project_dir, src);
+            } else {
+                var localProperties = properties_parser.createEditor(path.resolve(project_dir, "local.properties"));
+                subDir = path.resolve(localProperties.get("sdk.dir"), src);
+            }
+            var projectConfig = module.exports.parseProjectFile(project_dir);
+            projectConfig.addSubProject(parentDir, subDir);
         },
         uninstall:function(source_el, project_dir, plugin_id) {
-            events.emit('verbose', 'framework.uninstall is not supported for android');
+            var src = source_el.attrib.src;
+            if (!src) throw new Error('src not specified in framework element');
+
+            events.emit('verbose', "Uninstalling Android library: " + src);
+            var parent = source_el.attrib.parent;
+            var parentDir = parent ? path.resolve(project_dir, parent) : project_dir;
+            var subDir = path.resolve(project_dir, src);
+            var projectConfig = module.exports.parseProjectFile(project_dir);
+            projectConfig.removeSubProject(parentDir, subDir);
         }
+    },
+    parseProjectFile: function(project_dir){
+        if (!projectFileCache[project_dir]) {
+            projectFileCache[project_dir] = {
+                propertiesEditors: {},
+                subProjectDirs : {},
+                addSubProject: function(parentDir, subDir) {
+                    var subProjectFile = path.resolve(subDir, "project.properties");
+                    if (!fs.existsSync(subProjectFile)) throw new Error('cannot find "' + subProjectFile + '" referenced in <framework>');
+
+                    var parentProjectFile = path.resolve(parentDir, "project.properties");
+                    var parentProperties = this._getPropertiesFile(parentProjectFile);
+                    addLibraryReference(parentProperties, module.exports.getRelativeLibraryPath(parentDir, subDir));
+
+                    var subProperties = this._getPropertiesFile(subProjectFile);
+                    subProperties.set("target", parentProperties.get("target"));
+
+                    this.subProjectDirs[subDir] = true;
+                    this._dirty = true;
+                },
+                removeSubProject: function(parentDir, subDir) {
+                    var parentProjectFile = path.resolve(parentDir, "project.properties");
+                    var parentProperties = this._getPropertiesFile(parentProjectFile);
+                    removeLibraryReference(parentProperties, module.exports.getRelativeLibraryPath(parentDir, subDir));
+                    delete this.subProjectDirs[subDir];
+                    this._dirty = true;
+                },
+                write: function () {
+                    if (!this._dirty) return;
+
+                    for (var filename in this.propertiesEditors) {
+                        fs.writeFileSync(filename, this.propertiesEditors[filename].toString());
+                    }
+
+                    for (var sub_dir in this.subProjectDirs)
+                    {
+                        shell.exec("android update lib-project --path " + sub_dir);
+                    }
+                    this._dirty = false;
+                },
+                _dirty : false,
+                _getPropertiesFile: function (filename) {
+                    if (!this.propertiesEditors[filename])
+                        this.propertiesEditors[filename] = properties_parser.createEditor(filename);
+
+                    return this.propertiesEditors[filename];
+                }
+            };
+        }
+
+        return projectFileCache[project_dir];
+    },
+    purgeProjectFileCache:function(project_dir) {
+        delete projectFileCache[project_dir];
+    },
+    getRelativeLibraryPath: function (parentDir, subDir) {
+        var libraryPath = path.relative(parentDir, subDir);
+        return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
     }
 };
+
+function addLibraryReference(projectProperties, libraryPath) {
+    var i = 1;
+    while (projectProperties.get("android.library.reference." + i))
+        i++;
+
+    projectProperties.set("android.library.reference." + i, libraryPath);
+}
+
+function removeLibraryReference(projectProperties, libraryPath) {
+    var i = 1;
+    var currentLib;
+    while (currentLib = projectProperties.get("android.library.reference." + i)) {
+        if (currentLib === libraryPath) {
+            while (currentLib = projectProperties.get("android.library.reference." + (i + 1))) {
+                projectProperties.set("android.library.reference." + i, currentLib);
+                i++;
+            }
+            projectProperties.set("android.library.reference." + i);
+            break;
+        }
+        i++;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/src/plugman/platforms/ios.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/platforms/ios.js b/cordova-lib/src/plugman/platforms/ios.js
index 4f570c3..1c5d8ea 100644
--- a/cordova-lib/src/plugman/platforms/ios.js
+++ b/cordova-lib/src/plugman/platforms/ios.js
@@ -125,7 +125,7 @@ module.exports = {
                 custom = framework_el.attrib['custom'],
                 srcFile = path.resolve(plugin_dir, src),
                 targetDir = path.resolve(project.plugins_dir, plugin_id, path.basename(src));
-            if (!custom) throw new Error('cannot add non custom frameworks.');
+            if (!custom) return; //non-custom frameworks are processed in config-changes.js
             if (!fs.existsSync(srcFile)) throw new Error('cannot find "' + srcFile + '" ios <framework>');
             if (fs.existsSync(targetDir)) throw new Error('target destination "' + targetDir + '" already exists');
             shell.mkdir('-p', path.dirname(targetDir));

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/513967db/cordova-lib/src/plugman/util/config-changes.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/plugman/util/config-changes.js b/cordova-lib/src/plugman/util/config-changes.js
index bc24a7f..8e3b614 100644
--- a/cordova-lib/src/plugman/util/config-changes.js
+++ b/cordova-lib/src/plugman/util/config-changes.js
@@ -305,16 +305,18 @@ function generate_plugin_config_munge(plugin_dir, vars) {
 
         // note down pbxproj framework munges in special section of munge obj
         // CB-5238 this is only for systems frameworks
-        var frameworks = platformTag.findall('framework');
-        frameworks.forEach(function(f) {
-            var custom = f.attrib['custom'];
-            if(!custom) {
-                var file = f.attrib['src'];
-                var weak = ('true' == f.attrib['weak']).toString();
-
-                deep_add(munge, 'framework', file, { xml: weak, count: 1 });
-            }
-        });
+        if (self.platform === 'ios') {
+            var frameworks = platformTag.findall('framework');
+            frameworks.forEach(function (f) {
+                var custom = f.attrib['custom'];
+                if (!custom) {
+                    var file = f.attrib['src'];
+                    var weak = ('true' == f.attrib['weak']).toString();
+
+                    deep_add(munge, 'framework', file, { xml: weak, count: 1 });
+                }
+            });
+        }
     }
 
     changes.forEach(function(change) {