You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2013/03/20 23:55:52 UTC

[4/6] git commit: Variable substitution on standard config files

Variable substitution on standard config files


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/7ef9b8fe
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/7ef9b8fe
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/7ef9b8fe

Branch: refs/heads/master
Commit: 7ef9b8fead89be6c3b1055bc1c4d860cbbf2997c
Parents: 49a231e
Author: Brett Rudd <br...@gmail.com>
Authored: Tue Mar 12 21:50:28 2013 -0700
Committer: Brett Rudd <br...@gmail.com>
Committed: Tue Mar 19 16:36:09 2013 -0700

----------------------------------------------------------------------
 platforms/android.js                               |   21 +++--
 platforms/ios.js                                   |   48 +++++++---
 plugman.js                                         |   14 ++-
 test/projects/FriendSting-Info.plist               |   78 +++++++++++++++
 test/projects/ios-config-xml/SampleApp-Info.plist  |   78 +++++++++++++++
 .../ios-config-xml/SampleApp/SampleApp-Info.plist  |   78 +++++++++++++++
 test/projects/ios/SampleApp/SampleApp-Info.plist   |   78 +++++++++++++++
 util/search-and-replace.js                         |   37 +++++++
 8 files changed, 405 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/platforms/android.js
----------------------------------------------------------------------
diff --git a/platforms/android.js b/platforms/android.js
index 892f7b0..2f78bf4 100644
--- a/platforms/android.js
+++ b/platforms/android.js
@@ -23,13 +23,13 @@ var fs = require('fs')  // use existsSync in 0.6.x
    , shell = require('shelljs')
    , et = require('elementtree')
    , getConfigChanges = require('../util/config-changes')
+   , searchAndReplace = require('../util/search-and-replace')
+   , xml_helpers = require('../util/xml-helpers')
+   , assetsDir = 'assets/www'
+   , sourceDir = 'src';
 
-   , assetsDir = 'assets/www'  // relative path to project's web assets
-   , sourceDir = 'src'
-   , xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'));
 
-
-exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
+exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et, variables) {
     var plugin_id = plugin_et._root.attrib['id']
       , version = plugin_et._root.attrib['version']
       , external_hosts = []
@@ -39,9 +39,10 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
       , platformTag = plugin_et.find('./platform[@name="android"]')
       , sourceFiles = platformTag.findall('./source-file')
       , libFiles = platformTag.findall('./library-file')
-      , PACKAGE_NAME = androidPackageName(project_dir)
       , configChanges = getConfigChanges(platformTag);
 
+    variables = variables || {}
+
 	// get config.xml filename
 	var config_xml_filename = 'res/xml/config.xml';
     if(fs.existsSync(path.resolve(project_dir, 'res/xml/plugins.xml'))) {
@@ -173,9 +174,15 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
         });
 
         output = xmlDoc.write({indent: 4});
-        output = output.replace(/\$PACKAGE_NAME/g, PACKAGE_NAME);
         fs.writeFileSync(filepath, output);
     });
+    
+    if (action == 'install') {
+        variables['PACKAGE_NAME'] = androidPackageName(project_dir);
+        searchAndReplace(path.resolve(project_dir, config_xml_filename), variables);
+        searchAndReplace(path.resolve(project_dir, 'AndroidManifest.xml'), variables);
+    }
+    
 }
 
 

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/platforms/ios.js
----------------------------------------------------------------------
diff --git a/platforms/ios.js b/platforms/ios.js
index b0cec42..6290ebc 100644
--- a/platforms/ios.js
+++ b/platforms/ios.js
@@ -25,20 +25,24 @@ var path = require('path')
   , plist = require('plist')
   , bplist = require('bplist-parser')
   , shell = require('shelljs')
-  , xml_helpers = require(path.join(__dirname, '..', 'util', 'xml-helpers'))
-  , getConfigChanges = require(path.join(__dirname, '..', 'util', 'config-changes'))
+  , xml_helpers = require('../util/xml-helpers')
+  , searchAndReplace = require('../util/search-and-replace')
+  , getConfigChanges = require('../util/config-changes')
   , assetsDir = 'www';    // relative path to project's web assets
 
-exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
+exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et, variables) {
     var plugin_id = plugin_et._root.attrib['id']
       , version = plugin_et._root.attrib['version']
       , i = 0
       , matched;
+
+    variables = variables || {}
+
     // grab and parse pbxproj
     // we don't want CordovaLib's xcode project
     var project_files = glob.sync(project_dir + '/*.xcodeproj/project.pbxproj');
     
-    if (!project_files.length) throw "does not appear to be an xcode project";
+    if (!project_files.length) throw "does not appear to be an xcode project (no xcode project file)";
     var pbxPath = project_files[0];
 
     var xcodeproj = xcode.project(project_files[0]);
@@ -50,23 +54,30 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
                         glob.sync(project_dir + '/**/{PhoneGap,Cordova}.plist')
                        );
 
-    if (!config_files.length) {
-        throw "does not appear to be a PhoneGap project";
-    }
-
     config_files = config_files.filter(function (val) {
         return !(/^build\//.test(val));
     });
 
-    var pluginsDir = path.resolve(config_files[0], '..', 'Plugins');
-    var resourcesDir = path.resolve(config_files[0], '..', 'Resources');
+    if (!config_files.length) {
+        throw "does not appear to be a PhoneGap project";
+    }
 
+    var config_file = config_files[0];
+    var xcode_dir = path.dirname(config_file);
+    var pluginsDir = path.resolve(xcode_dir, 'Plugins');
+    var resourcesDir = path.resolve(xcode_dir, 'Resources');
+    
+    // get project plist for package name
+    var project_plists = glob.sync(xcode_dir + '/*-Info.plist');
+    var projectPListPath = project_plists[0];
+    
     // collision detection 
-    if(action == "install" && pluginInstalled(plugin_et, config_files[0])) {
+    if(action == "install" && pluginInstalled(plugin_et, config_file)) {
         throw "Plugin "+plugin_id+" already installed"
-    } else if(action == "uninstall" && !pluginInstalled(plugin_et, config_files[0])) {
+    } else if(action == "uninstall" && !pluginInstalled(plugin_et, config_file)) {
         throw "Plugin "+plugin_id+" not installed"
     }
+    
     var assets = plugin_et.findall('./asset'),
         platformTag = plugin_et.find('./platform[@name="ios"]'),
         sourceFiles = platformTag.findall('./source-file'),
@@ -161,10 +172,19 @@ exports.handlePlugin = function (action, project_dir, plugin_dir, plugin_et) {
         }
     });
 
-    updateConfig(action, config_files[0], plugin_et);
-
     // write out xcodeproj file
     fs.writeFileSync(pbxPath, xcodeproj.writeSync());
+
+    // add plugin and whitelisted hosts
+    updateConfig(action, config_file, plugin_et);
+    
+    if (action == 'install') {
+        variables['PACKAGE_NAME'] = plist.parseFileSync(projectPListPath).CFBundleIdentifier;
+        searchAndReplace(pbxPath, variables);
+        searchAndReplace(projectPListPath, variables);
+        searchAndReplace(config_file, variables);
+    }
+    
 }
 
 function getRelativeDir(file) {

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/plugman.js
----------------------------------------------------------------------
diff --git a/plugman.js b/plugman.js
index d0cee33..a38b76e 100755
--- a/plugman.js
+++ b/plugman.js
@@ -85,7 +85,7 @@ else {
 function printUsage() {
     platforms = known_opts.platform.join('|');
     console.log('Usage\n---------');
-    console.log('Add a plugin:\n\t' + package.name + ' --platform <'+ platforms +'> --project <directory> --plugin <directory|git-url|name>\n');
+    console.log('Add a plugin:\n\t' + package.name + ' --platform <'+ platforms +'> --project <directory> --variable <preference_name>="<substituion>" --plugin <directory|git-url|name>\n');
     console.log('Remove a plugin:\n\t' + package.name + ' --remove --platform <'+ platforms +'> --project <directory> --plugin <directory|git-url|name>\n');
     console.log('List plugins:\n\t' + package.name + ' --list\n');
 }
@@ -93,26 +93,28 @@ function printUsage() {
 function execAction(action, platform, project_dir, plugin_dir, cli_variables) {
     var xml_path     = path.join(plugin_dir, 'plugin.xml')
       , xml_text     = fs.readFileSync(xml_path, 'utf-8')
-      , plugin_et   = new et.ElementTree(et.XML(xml_text));
-    
+      , plugin_et    = new et.ElementTree(et.XML(xml_text))
+      , filtered_variables = {};
 
     if (action == 'install') {
         prefs = plugin_et.findall('./preference') || [];
         prefs = prefs.concat(plugin_et.findall('./platform[@name="'+platform+'"]/preference'));
-        var missing_vars = []
+        var missing_vars = [];
         prefs.forEach(function (pref) {
             var key = pref.attrib["name"].toUpperCase();
             if (cli_variables[key] == undefined)
                 missing_vars.push(key)
+            else
+                filtered_variables[key] = cli_variables[key]
         })
         if (missing_vars.length > 0) {
             console.log('Variable missing: ' + missing_vars.join(", "));
             return;
         }
     }
-
+    
     // run the platform-specific function
-    platform_modules[platform].handlePlugin(action, project_dir, plugin_dir, plugin_et, cli_variables);
+    platform_modules[platform].handlePlugin(action, project_dir, plugin_dir, plugin_et, filtered_variables);
     
     console.log('plugin ' + action + 'ed');
 }

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/test/projects/FriendSting-Info.plist
----------------------------------------------------------------------
diff --git a/test/projects/FriendSting-Info.plist b/test/projects/FriendSting-Info.plist
new file mode 100644
index 0000000..6010b61
--- /dev/null
+++ b/test/projects/FriendSting-Info.plist
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+-->
+<plist version="1.0">
+<dict>
+	<key>CFBundleIcons</key>
+	<dict>
+		<key>CFBundlePrimaryIcon</key>
+		<dict>
+			<key>CFBundleIconFiles</key>
+			<array>
+                <string>icon.png</string>
+                <string>icon@2x.png</string>
+                <string>icon-72.png</string>
+                <string>icon-72@2x.png</string>
+			</array>
+			<key>UIPrerenderedIcon</key>
+			<false/>
+		</dict>
+	</dict>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.example.friendstring</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSMainNibFile</key>
+	<string></string>
+	<key>NSMainNibFile~ipad</key>
+	<string></string>
+</dict>
+</plist>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/test/projects/ios-config-xml/SampleApp-Info.plist
----------------------------------------------------------------------
diff --git a/test/projects/ios-config-xml/SampleApp-Info.plist b/test/projects/ios-config-xml/SampleApp-Info.plist
new file mode 100644
index 0000000..6010b61
--- /dev/null
+++ b/test/projects/ios-config-xml/SampleApp-Info.plist
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+-->
+<plist version="1.0">
+<dict>
+	<key>CFBundleIcons</key>
+	<dict>
+		<key>CFBundlePrimaryIcon</key>
+		<dict>
+			<key>CFBundleIconFiles</key>
+			<array>
+                <string>icon.png</string>
+                <string>icon@2x.png</string>
+                <string>icon-72.png</string>
+                <string>icon-72@2x.png</string>
+			</array>
+			<key>UIPrerenderedIcon</key>
+			<false/>
+		</dict>
+	</dict>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.example.friendstring</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSMainNibFile</key>
+	<string></string>
+	<key>NSMainNibFile~ipad</key>
+	<string></string>
+</dict>
+</plist>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/test/projects/ios-config-xml/SampleApp/SampleApp-Info.plist
----------------------------------------------------------------------
diff --git a/test/projects/ios-config-xml/SampleApp/SampleApp-Info.plist b/test/projects/ios-config-xml/SampleApp/SampleApp-Info.plist
new file mode 100644
index 0000000..6010b61
--- /dev/null
+++ b/test/projects/ios-config-xml/SampleApp/SampleApp-Info.plist
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+-->
+<plist version="1.0">
+<dict>
+	<key>CFBundleIcons</key>
+	<dict>
+		<key>CFBundlePrimaryIcon</key>
+		<dict>
+			<key>CFBundleIconFiles</key>
+			<array>
+                <string>icon.png</string>
+                <string>icon@2x.png</string>
+                <string>icon-72.png</string>
+                <string>icon-72@2x.png</string>
+			</array>
+			<key>UIPrerenderedIcon</key>
+			<false/>
+		</dict>
+	</dict>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.example.friendstring</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSMainNibFile</key>
+	<string></string>
+	<key>NSMainNibFile~ipad</key>
+	<string></string>
+</dict>
+</plist>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/test/projects/ios/SampleApp/SampleApp-Info.plist
----------------------------------------------------------------------
diff --git a/test/projects/ios/SampleApp/SampleApp-Info.plist b/test/projects/ios/SampleApp/SampleApp-Info.plist
new file mode 100644
index 0000000..6010b61
--- /dev/null
+++ b/test/projects/ios/SampleApp/SampleApp-Info.plist
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+-->
+<plist version="1.0">
+<dict>
+	<key>CFBundleIcons</key>
+	<dict>
+		<key>CFBundlePrimaryIcon</key>
+		<dict>
+			<key>CFBundleIconFiles</key>
+			<array>
+                <string>icon.png</string>
+                <string>icon@2x.png</string>
+                <string>icon-72.png</string>
+                <string>icon-72@2x.png</string>
+			</array>
+			<key>UIPrerenderedIcon</key>
+			<false/>
+		</dict>
+	</dict>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.example.friendstring</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSMainNibFile</key>
+	<string></string>
+	<key>NSMainNibFile~ipad</key>
+	<string></string>
+</dict>
+</plist>

http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/7ef9b8fe/util/search-and-replace.js
----------------------------------------------------------------------
diff --git a/util/search-and-replace.js b/util/search-and-replace.js
new file mode 100644
index 0000000..dc1f931
--- /dev/null
+++ b/util/search-and-replace.js
@@ -0,0 +1,37 @@
+#!/usr/bin/env node
+/*
+ *
+ * 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.
+ *
+*/
+
+var glob = require('glob'),
+    fs = require('fs');
+
+module.exports = function searchAndReplace(srcGlob, variables) {
+  var files = glob.sync(srcGlob);
+  for (var i in files) {
+    var file = files[i];
+    if (fs.lstatSync(file).isFile()) {
+      var contents = fs.readFileSync(file, "utf-8");
+      for (var key in variables) {
+          var regExp = new RegExp("\\$" + key, "g");
+          contents = contents.replace(regExp, variables[key]);
+      }
+      fs.writeFileSync(file, contents);
+    }
+  }
+}
\ No newline at end of file