Updated Branches: refs/heads/master e3592a1fe -> 43fbb2807
[ios] add custom config-file support Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/375459c3 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/375459c3 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/375459c3 Branch: refs/heads/master Commit: 375459c39bd28916a63841907ad30c707b8d1d3f Parents: e3592a1 Author: Brett Rudd <[email protected]> Authored: Fri Apr 19 15:28:21 2013 -0700 Committer: Brett Rudd <[email protected]> Committed: Mon Apr 22 11:42:01 2013 -0700 ---------------------------------------------------------------------- platforms/ios.js | 71 +++++++++++++++++++- test/ios-config-xml-uninstall.js | 20 ++++++ test/plugins/ChildBrowser/plugin-old.xml | 13 ++++ test/plugins/ChildBrowser/plugin.xml | 13 ++++ util/plist-helpers.js | 90 +++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/375459c3/platforms/ios.js ---------------------------------------------------------------------- diff --git a/platforms/ios.js b/platforms/ios.js index 6473936..8b13d4a 100644 --- a/platforms/ios.js +++ b/platforms/ios.js @@ -26,6 +26,8 @@ var path = require('path') , bplist = require('bplist-parser') , shell = require('shelljs') , xml_helpers = require('../util/xml-helpers') + , plist_helpers = require('../util/plist-helpers') + , getConfigChanges = require('../util/config-changes') , searchAndReplace = require('../util/search-and-replace') , getConfigChanges = require('../util/config-changes') , assetsDir = 'www'; // relative path to project's web assets @@ -86,7 +88,8 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et, var sourceFiles = platformTag.findall('./source-file'), headerFiles = platformTag.findall('./header-file'), resourceFiles = platformTag.findall('./resource-file'), - frameworks = platformTag.findall('./framework'); + frameworks = platformTag.findall('./framework'), + configChanges = getConfigChanges(platformTag); // move asset files into www assets && assets.forEach(function (asset) { @@ -193,9 +196,17 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et, var // write out xcodeproj file fs.writeFileSync(pbxPath, xcodeproj.writeSync()); - // add plugin and whitelisted hosts try { + // add plugin and whitelisted hosts updateConfig(action, config_file, plugin_et); + + // edit custom configuration items + Object.keys(configChanges).forEach(function (filename) { + var filepaths = glob.sync(path.resolve(xcode_dir, filename)); + for (var i in filepaths) { + updateCustomConfig(action, filepaths[i], configChanges[filename]); + } + }); } catch(e) { throw { name: "ConfigurationError", @@ -352,7 +363,8 @@ function updateConfigXml(action, config_path, plugin_et) { throw new Error('failed to remove children from ' + selector + ' in ' + config_path); } } - }); + delete configChanges[base_config_path][configNode]; + }); } output = xmlDoc.write({indent: 4}); @@ -367,7 +379,60 @@ function updateConfig(action, config_path, plugin_et) { updatePlistFile(action, config_path, plugin_et); } } + // throws error if last command returns code != 0 function checkLastCommand() { if(shell.error() != null) throw {name: "ShellError", message: shell.error()}; } + +// updates plist file and/or config.xml +function updateCustomConfig(action, filepath, configNodes) { + + if (path.extname(filepath) == ".xml") { + var xmlDoc = xml_helpers.parseElementtreeSync(filepath), + output; + + configNodes.forEach(function (configNode) { + var selector = configNode.attrib["parent"], + children = configNode.findall('*'); + + if( action == 'install') { + if (!xml_helpers.graftXML(xmlDoc, children, selector)) { + throw new Error('failed to add children to ' + filepath); + } + } else { + if (!xml_helpers.pruneXML(xmlDoc, children, selector)) { + throw new Error('failed to remove children from' + filepath); + } + } + }); + + output = xmlDoc.write({indent: 4}); + fs.writeFileSync(filepath, output); + + } + else { // PLIST + var pl = (isBinaryPlist(filepath) ? bplist : plist), + plistObj = pl.parseFileSync(filepath); + + configNodes.forEach(function (configNode) { + + var selector = configNode.attrib["parent"], + children = configNode.find("./*"); + + if( action == 'install') { + if (!plist_helpers.graftPLIST(plistObj, children, selector)) { + throw new Error('failed to add children to ' + filepath); + } + } else { + if (!plist_helpers.prunePLIST(plistObj, children, selector)) { + throw new Error('failed to remove children from' + filepath); + } + } + + }); + + // write out plist + fs.writeFileSync(filepath, plist.build(plistObj)); + } +} http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/375459c3/test/ios-config-xml-uninstall.js ---------------------------------------------------------------------- diff --git a/test/ios-config-xml-uninstall.js b/test/ios-config-xml-uninstall.js index a2b5885..6b2674e 100644 --- a/test/ios-config-xml-uninstall.js +++ b/test/ios-config-xml-uninstall.js @@ -175,6 +175,26 @@ exports['should edit config.xml'] = function (test) { test.done(); } +exports['should remove custom config-file elements'] = function (test) { + // setting up WebNotification (with config.xml) + var dummy_plugin_dir = path.join(test_dir, 'plugins', 'ChildBrowser') + var dummy_xml_path = path.join(test_dir, 'plugins', 'ChildBrowser', 'plugin.xml') + + // overriding some params + var dummy_plugin_et = new et.ElementTree(et.XML(fs.readFileSync(dummy_xml_path, 'utf-8'))); + + // run the platform-specific function + ios.handlePlugin('install', test_project_dir, dummy_plugin_dir, dummy_plugin_et, { APP_ID: '1234' }); + ios.handlePlugin('uninstall', test_project_dir, dummy_plugin_dir, dummy_plugin_et); + + var configPath = path.join(test_project_dir, 'SampleApp', 'SampleApp-Info.plist'); + var configPList = plist.parseFileSync(configPath); + + test.equal(configPList['AppId'], null); + test.equal(configPList['CFBundleURLTypes'], null); + test.done(); +} + exports['should edit the pbxproj file'] = function (test) { // run the platform-specific function ios.handlePlugin('install', test_project_dir, test_plugin_dir, plugin_et); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/375459c3/test/plugins/ChildBrowser/plugin-old.xml ---------------------------------------------------------------------- diff --git a/test/plugins/ChildBrowser/plugin-old.xml b/test/plugins/ChildBrowser/plugin-old.xml index a3d7643..d145839 100644 --- a/test/plugins/ChildBrowser/plugin-old.xml +++ b/test/plugins/ChildBrowser/plugin-old.xml @@ -65,6 +65,19 @@ <resource-file src="ChildBrowser.bundle" /> <resource-file src="ChildBrowserViewController.xib" /> + <config-file target="*-Info.plist" parent="AppId"> + <string>$APP_ID</string> + </config-file> + + <config-file target="*-Info.plist" parent="CFBundleURLTypes"> + <array> + <dict> + <key>PackageName</key> + <string>$PACKAGE_NAME</string> + </dict> + </array> + </config-file> + <header-file src="ChildBrowserCommand.h" /> <header-file src="ChildBrowserViewController.h" /> <header-file src="preserveDirs/PreserveDirsTest.h" preserve-dirs="true" /> http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/375459c3/test/plugins/ChildBrowser/plugin.xml ---------------------------------------------------------------------- diff --git a/test/plugins/ChildBrowser/plugin.xml b/test/plugins/ChildBrowser/plugin.xml index 7641ec0..fef4bdd 100644 --- a/test/plugins/ChildBrowser/plugin.xml +++ b/test/plugins/ChildBrowser/plugin.xml @@ -70,6 +70,19 @@ value="ChildBrowserCommand" /> </config-file> + <config-file target="*-Info.plist" parent="AppId"> + <string>$APP_ID</string> + </config-file> + + <config-file target="*-Info.plist" parent="CFBundleURLTypes"> + <array> + <dict> + <key>PackageName</key> + <string>$PACKAGE_NAME</string> + </dict> + </array> + </config-file> + <resource-file src="ChildBrowser.bundle" /> <resource-file src="ChildBrowserViewController.xib" /> http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/375459c3/util/plist-helpers.js ---------------------------------------------------------------------- diff --git a/util/plist-helpers.js b/util/plist-helpers.js new file mode 100644 index 0000000..9a49feb --- /dev/null +++ b/util/plist-helpers.js @@ -0,0 +1,90 @@ +/* + * + * Copyright 2013 Brett Rudd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +// contains PLIST utility functions + +var et = require('elementtree'), + plist = require('plist'); + +// adds node to doc at selector +exports.graftPLIST = function (doc, nodes, selector) { + var text = et.tostring(nodes, { xml_declaration: false }); + obj = plist.parseStringSync("<plist>"+text+"</plist>"); + + var node = doc[selector]; + if (node && Array.isArray(node) && Array.isArray(obj)) + doc[selector] = node.concat(obj); + else + doc[selector] = obj; + + return true; +} + +// removes node from doc at selector +exports.prunePLIST = function(doc, nodes, selector) { + var text = et.tostring(nodes, { xml_declaration: false }), + obj = plist.parseStringSync("<plist>"+text+"</plist>"); + + pruneOBJECT(doc, selector, obj); + + return true; +} + +function pruneOBJECT(doc, selector, fragment) { + if (Array.isArray(fragment) && Array.isArray(doc[selector])) { + var empty = true; + for (i in fragment) { + for (j in doc[selector]) { + empty = pruneOBJECT(doc[selector], j, fragment[i]) && empty; + } + } + if (empty) + { + delete doc[selector]; + return true; + } + } + else if (nodeEqual(doc[selector], fragment)) { + delete doc[selector]; + return true; + } + + return false; +} + +function nodeEqual(node1, node2) { + if (typeof node1 != typeof node2) + return false; + else if (typeof node1 == 'string') { + node2 = escapeRE(node2).replace(new RegExp("\\$[a-zA-Z0-9-_]+","gm"),"(.*?)"); + return new RegExp('^' + node2 + '$').test(node1); + } + else { + for (var key in node2) { + if (!nodeEqual(node1[key], node2[key])) return false; + } + return true; + } +} + +// escape string for use in regex +function escapeRE(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\$&"); +}; +
