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/05/30 04:46:10 UTC

git commit: Extend PluginInfo to parse more of plugin.xml

Repository: cordova-lib
Updated Branches:
  refs/heads/master 39327db7d -> 24bf10d52


Extend PluginInfo to parse more of plugin.xml


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

Branch: refs/heads/master
Commit: 24bf10d52c53fd2cd8eb6acdac715aa1a77a5024
Parents: 39327db
Author: Mark Koudritsky <ka...@gmail.com>
Authored: Thu May 22 16:23:14 2014 -0400
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Thu May 29 22:39:44 2014 -0400

----------------------------------------------------------------------
 cordova-lib/spec-cordova/PluginInfo.spec.js |  13 +-
 cordova-lib/src/PluginInfo.js               | 237 +++++++++++++++++++++--
 2 files changed, 229 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/24bf10d5/cordova-lib/spec-cordova/PluginInfo.spec.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-cordova/PluginInfo.spec.js b/cordova-lib/spec-cordova/PluginInfo.spec.js
index 4bc16bb..239d4fa 100644
--- a/cordova-lib/spec-cordova/PluginInfo.spec.js
+++ b/cordova-lib/spec-cordova/PluginInfo.spec.js
@@ -27,12 +27,23 @@ var pluginsDir = path.join(__dirname, 'fixtures', 'plugins');
 
 describe('PluginInfo', function () {
     it('should read a plugin.xml file', function () {
-        var p;
+        var p, prefs, assets, deps, configFiles, infos, srcFiles;
+        var headerFiles, libFiles, resourceFiles;
         expect(function () {
             p = new PluginInfo.PluginInfo(path.join(pluginsDir, 'ChildBrowser'));
+            prefs = p.getPreferences('android');
+            assets = p.getAssets('android');
+            deps = p.getDependencies('android');
+            configFiles = p.getConfigFiles('android');
+            infos = p.getInfo('android');
+            srcFiles = p.getSourceFiles('android');
+            headerFiles = p.getHeaderFiles('android');
+            libFiles = p.getLibFiles('android');
+            resourceFiles = p.getResourceFiles('android');
         }).not.toThrow();
         expect(p).toBeDefined();
         expect(p.name).toEqual('Child Browser');
+        // TODO: Add some expectations for results of getSomething.
     });
     it('should throw when there is no plugin.xml file', function () {
         expect(function () {

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/24bf10d5/cordova-lib/src/PluginInfo.js
----------------------------------------------------------------------
diff --git a/cordova-lib/src/PluginInfo.js b/cordova-lib/src/PluginInfo.js
index 95a579c..1a2fc8d 100644
--- a/cordova-lib/src/PluginInfo.js
+++ b/cordova-lib/src/PluginInfo.js
@@ -22,16 +22,17 @@ A class for holidng the information currently stored in plugin.xml
 It should also be able to answer questions like whether the plugin
 is compatible with a given engine version.
 
-For now it's a stub to be gradually extended.
 TODO (kamrik): refactor this to use no fs sync fnctions and return promises.
 */
 
-/* jshint node:true, laxcomma:true  */
+/* jshint node:true, laxcomma:true, laxbreak:true, sub:true, strict: false  */
 
-var path = require('path'),
-    fs = require('fs'),
-    _ = require('underscore'),
-    xml_helpers = require('./util/xml-helpers');
+var path = require('path')
+  , fs = require('fs')
+  , _ = require('underscore')
+  , xml_helpers = require('./util/xml-helpers')
+  , CordovaError = require('./CordovaError')
+  ;
 
 // Exports
 exports.PluginInfo = PluginInfo;
@@ -41,13 +42,178 @@ exports.loadPluginsDir = loadPluginsDir;
 function PluginInfo(dirname) {
     var self = this;
 
-    var filepath = path.join(dirname, 'plugin.xml');
-    if (!fs.existsSync(filepath)) {
+    // METHODS
+    // Defined inside the constructor to avoid the "this" binding problems.
+
+    // <preference> tag
+    // Example: <preference name="API_KEY" />
+    // Used to require a variable to be specified via --variable when installing the plugin.
+    self.getPreferences = getPreferences;
+    function getPreferences(platform) {
+        var prefs = _getTags(self._et, 'preference', platform, _parsePreference);
+        return prefs;
+    }
+
+    function _parsePreference(prefTag) {
+        var pref = prefTag.attrib.name.toUpperCase();
+        return pref;
+    }
+
+    // <asset>
+    self.getAssets = getAssets;
+    function getAssets(platform) {
+        var assets = _getTags(self._et, 'asset', platform, _parseAsset);
+        return assets;
+    }
+
+    function _parseAsset(tag) {
+        var src = tag.attrib.src;
+        var target = tag.attrib.target;
+
+        if ( !src || !target) {
+            var msg =
+                'Malformed <asset> tag. Both "src" and "target" attributes'
+                + 'must be specified in\n'
+                + self.filepath
+                ;
+            throw new Error(msg);
+        }
+
+        var asset = { src: src, target: target };
+        return asset;
+    }
+
+
+    // <dependency>
+    // Example:
+    // <dependency id="com.plugin.id"
+    //     url="https://github.com/myuser/someplugin"
+    //     commit="428931ada3891801"
+    //     subdir="some/path/here" />
+    self.getDependencies = getDependencies;
+    function getDependencies(platform) {
+        var deps = _getTags(
+                self._et,
+                'dependency',
+                platform,
+                _parseDependency
+        );
+        return deps;
+    }
+
+    function _parseDependency(tag) {
+        var dep =
+            { id : tag.attrib.id
+            , url : tag.attrib.url || ''
+            , subdir : tag.attrib.subdir || ''
+            , commit : tag.attrib.commit
+            };
+
+        dep.git_ref = dep.commit;
+
+        if ( !dep.id ) {
+            var msg =
+                '<dependency> tag is missing id attribute in '
+                + self.filepath
+                ;
+            throw new CordovaError(msg);
+        }
+        return dep;
+    }
+
+
+    // <config-file> tag
+    self.getConfigFiles = getConfigFiles;
+    function getConfigFiles(platform) {
+        var configFiles = _getTags(self._et, 'config-file', platform, _parseConfigFile);
+        return configFiles;
+    }
+
+    function _parseConfigFile(tag) {
+        var configFile =
+            { target : tag.attrib['target']
+            , parent : tag.attrib['parent']
+            , after : tag.attrib['after']
+            , xmls : tag.getchildren()
+            };
+        return configFile;
+    }
+
+    // <info> tags, both global and within a <platform>
+    // TODO (kamrik): Do we ever use <info> under <platform>? Example wanted.
+    self.getInfo = getInfo;
+    function getInfo(platform) {
+        var infos = _getTags(
+                self._et,
+                'info',
+                platform,
+                function(elem) { return elem.text; }
+        );
+        // Filter out any undefined or empty strings.
+        infos = infos.filter(Boolean);
+        return infos;
+    }
+
+    // <source-file>
+    // Examples:
+    // <source-file src="src/ios/someLib.a" framework="true" />
+    // <source-file src="src/ios/someLib.a" compiler-flags="-fno-objc-arc" />
+    self.getSourceFiles = getSourceFiles;
+    function getSourceFiles(platform) {
+        var sourceFiles = _getTagsInPlatform(self._et, 'source-file', platform, _parseSourceFile);
+        return sourceFiles;
+    }
+
+    function _parseSourceFile(tag) {
+        var srcFile = _.clone(tag.attrib);
+        srcFile.framework = isStrTrue(srcFile.framework);
+        return srcFile;
+    }
+
+    // <header-file>
+    // Example:
+    // <header-file src="CDVFoo.h" />
+    self.getHeaderFiles = getHeaderFiles;
+    function getHeaderFiles(platform) {
+        var headerFiles = _getTagsInPlatform(self._et, 'header-file', platform, cloneAttribs);
+        return headerFiles;
+    }
+
+    // <resource-file>
+    // Example:
+    // <resource-file src="FooPluginStrings.xml" target="res/values/FooPluginStrings.xml" />
+    self.getResourceFiles = getResourceFiles;
+    function getResourceFiles(platform) {
+        var resourceFiles = _getTagsInPlatform(self._et, 'resource-file', platform, cloneAttribs);
+        return resourceFiles;
+    }
+
+    // <lib-file>
+    // Example:
+    // <lib-file src="src/BlackBerry10/native/device/libfoo.so" arch="device" />
+    self.getLibFiles = getLibFiles;
+    function getLibFiles(platform) {
+        var libFiles = _getTagsInPlatform(self._et, 'lib-file', platform, cloneAttribs);
+        return libFiles;
+    }
+
+    // Tell whether there is a <platform> section for the given platform.
+    self.hasPlatformSection = hasPlatformSection;
+    function hasPlatformSection(platform) {
+        var platformTag = pelem.find('./platform[@name="' + platform + '"]');
+        return !!platformTag;
+    }
+    ///// End of PluginInfo methods /////
+
+
+    ///// PluginInfo Constructor logic  /////
+    self.filepath = path.join(dirname, 'plugin.xml');
+    if (!fs.existsSync(self.filepath)) {
         throw new Error('Could not find plugin info in ' + dirname);
     }
 
-    self.path = dirname;
-    var et = self._et = xml_helpers.parseElementtreeSync(filepath);
+    self.dir = dirname;
+    var et = self._et = xml_helpers.parseElementtreeSync(self.filepath);
     var pelem = et.getroot();
     self.id = pelem.attrib.id;
     self.version = pelem.attrib.version;
@@ -59,18 +225,38 @@ function PluginInfo(dirname) {
     self.repo = pelem.findtext('repo');
     self.issue = pelem.findtext('issue');
     self.keywords = pelem.findtext('keywords');
-    if (self.keywords)
-        self.keywords = self.keywords.split(',').map( function(s) { return s.trim() } );
-
-    self.deps = {};
-    et.findall('dependency').forEach(function (d) {
-        self.deps[d.attrib.id] = _.clone(d.attrib);
-        // If version is not specified we want '' as default.
-        // semver.satisifies(x, '') -> true.
-        self.deps[d.attrib.id].version = self.deps[d.attrib.id].version || '';
-    });
+    self.info = pelem.findtext('info');
+    if (self.keywords) {
+        self.keywords = self.keywords.split(',').map( function(s) { return s.trim(); } );
+    }
+}  // End of PluginInfo constructor.
+
+
+// Helper function used by most of the getSomething methods of PluginInfo.
+// Get all elements of a given name. Both in root and in platform sections
+// for the given platform. If transform is given and is a function, it is
+// applied to each element.
+function _getTags(pelem, tag, platform, transform) {
+    var platformTag = pelem.find('./platform[@name="' + platform + '"]');
+    var tagsInRoot = pelem.findall(tag);
+    tagsInRoot = tagsInRoot || [];
+    var tagsInPlatform = platformTag ? platformTag.findall(tag) : [];
+    var tags = tagsInRoot.concat(tagsInPlatform);
+    if ( typeof transform === 'function' ) {
+        tags = tags.map(transform);
+    }
+    return tags;
 }
 
+// Same as _getTags() but only looks inside a platfrom section.
+function _getTagsInPlatform(pelem, tag, platform, transform) {
+    var platformTag = pelem.find('./platform[@name="' + platform + '"]');
+    var tags = platformTag ? platformTag.findall(tag) : [];
+    if ( typeof transform === 'function' ) {
+        tags = tags.map(transform);
+    }
+    return tags;
+}
 
 // Given a dir containing multiple plugins, create a PluginInfo objec for
 // each of them and return as array.
@@ -89,4 +275,15 @@ function loadPluginsDir(dirname) {
         plugins.push(p);
     });
     return plugins;
+}
+
+// Used as the default parser for some elements in plugin.xml
+function cloneAttribs(tag) {
+    return _.clone(tag.attrib);
+}
+
+// Check if x is a string 'true'. Allows for variations in case and
+// leading/trailing white space.
+function isStrTrue(x) {
+    return (typeof x === 'string') && (x.trim().toLowerCase() == 'true');
 }
\ No newline at end of file