cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bra...@apache.org
Subject [1/4] git commit: Automatic Javascript installation on prepare
Date Mon, 25 Mar 2013 17:21:12 GMT
Updated Branches:
  refs/heads/master 6c844bc80 -> 50e8e4ece


Automatic Javascript installation on prepare

Uses <js-module> tags to automatically inject code into the
platform-specific cordova.js.

Also the CLI now uses <asset> tags properly, rather than blindly copying
the entire www/ directory. This copying is done on prepare, since we're
trying to avoid touching the user's top-level www/.


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/964e3248
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/964e3248
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/964e3248

Branch: refs/heads/master
Commit: 964e3248704c35f5a2a948accb6226728cf35a1b
Parents: 29a3d24
Author: Braden Shepherdson <braden.shepherdson@gmail.com>
Authored: Wed Feb 20 18:10:25 2013 -0500
Committer: Braden Shepherdson <braden.shepherdson@gmail.com>
Committed: Tue Mar 12 10:30:50 2013 -0400

----------------------------------------------------------------------
 src/plugin.js        |   34 ++++----
 src/plugin_loader.js |  193 +++++++++++++++++++++++++++++++++++++++++++++
 src/prepare.js       |    7 +-
 3 files changed, 216 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/964e3248/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index d914df2..04e64f6 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -101,8 +101,6 @@ module.exports = function plugin(command, targets, callback) {
 
                 hooks.fire('before_plugin_add');
 
-                var pluginWww = path.join(target, 'www');
-                var wwwContents = ls(pluginWww);
                 var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
 
                 // Iterate over all matchin app-plugin platforms in the project and install
the
@@ -112,12 +110,11 @@ module.exports = function plugin(command, targets, callback) {
                     var plugin_cli = shell.exec(cmd, {silent:true});
                     if (plugin_cli.code > 0) throw new Error('An error occured during
plugin installation for ' + platform + '. ' + plugin_cli.output);
                 });
-                
-                // Add the plugin web assets to the www folder as well
-                // TODO: assumption that web assets go under www folder
-                // inside plugin dir; instead should read plugin.xml
-                wwwContents.forEach(function(asset) {
-                    asset = path.resolve(path.join(pluginWww, asset));
+
+                // Add the plugin web assets to the www folder as well.
+                var assets = pluginXml.doc.findall('plugin/asset');
+                assets.forEach(function(asset) {
+                    asset = path.resolve(path.join(target, asset.attrib.src));
                     var info = fs.lstatSync(asset);
                     var name = asset.substr(asset.lastIndexOf('/')+1);
                     var wwwPath = path.join(projectWww, name);
@@ -148,8 +145,6 @@ module.exports = function plugin(command, targets, callback) {
                 if (plugins.indexOf(targetName) > -1) {
                     var targetPath = path.join(pluginPath, targetName);
                     hooks.fire('before_plugin_rm');
-                    var pluginWww = path.join(targetPath, 'www');
-                    var wwwContents = ls(pluginWww);
                     var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
 
                     // Check if there is at least one match between plugin
@@ -167,12 +162,11 @@ module.exports = function plugin(command, targets, callback) {
                         var plugin_cli = shell.exec(cmd, {silent:true});
                         if (plugin_cli.code > 0) throw new Error('An error occured during
plugin uninstallation for ' + platform + '. ' + plugin_cli.output);
                     });
-                    
-                    // Remove the plugin web assets to the www folder as well
-                    // TODO: assumption that web assets go under www folder
-                    // inside plugin dir; instead should read plugin.xml
-                    wwwContents.forEach(function(asset) {
-                        asset = path.resolve(path.join(projectWww, asset));
+
+                    // Remove the plugin web assets from the www folder as well.
+                    var assets = pluginXml.doc.findall('plugin/asset');
+                    assets.forEach(function(asset) {
+                        asset = path.resolve(path.join(projectWww, asset.attrib.src));
                         var info = fs.lstatSync(asset);
                         if (info.isDirectory()) {
                             shell.rm('-rf', asset);
@@ -181,6 +175,14 @@ module.exports = function plugin(command, targets, callback) {
                         }
                     });
 
+                    // Remove the plugin web assets to the www folder as well
+                    // TODO: assumption that web assets go under www folder
+                    // inside plugin dir; instead should read plugin.xml
+                    wwwContents.forEach(function(asset) {
+                        asset = path.resolve(path.join(projectWww, asset));
+                        var info = fs.lstatSync(asset);
+                    });
+
                     // Finally remove the plugin dir from plugins/
                     shell.rm('-rf', targetPath);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/964e3248/src/plugin_loader.js
----------------------------------------------------------------------
diff --git a/src/plugin_loader.js b/src/plugin_loader.js
new file mode 100644
index 0000000..1733e97
--- /dev/null
+++ b/src/plugin_loader.js
@@ -0,0 +1,193 @@
+/**
+    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.
+*/
+
+var path            = require('path'),
+    fs              = require('fs'),
+    shell           = require('shelljs'),
+    ls              = fs.readdirSync,
+    cordova_util    = require('./util'),
+    util            = require('util'),
+    android_parser  = require('./metadata/android_parser'),
+    blackberry_parser= require('./metadata/blackberry_parser'),
+    ios_parser      = require('./metadata/ios_parser'),
+    exec            = require('child_process').exec,
+    et              = require('elementtree');
+
+
+// Called during cordova prepare.
+// Sets up each plugin's Javascript code to be loaded properly.
+module.exports = function plugin_loader(platform) {
+    // Process:
+    // - List all plugins in plugins/.
+    // - Load and parse their plugin.xml files.
+    // - Skip those without support for this platform.
+    // - Build a list of all their js-modules, and platform-specific js-modules.
+    // - For each js-module (general first, then platform):
+    //   - Generate JS code to load it.
+    //   - For each <clobbers>, <merges> or <runs>, generate JS code to
perform it.
+    //   - Copy the file, having slapped the cordova.define onto it on the way.
+    // - Append all of this code to the platform's cordova.js
+
+    var projectRoot = cordova_util.isCordova(process.cwd());
+    var plugins_dir = path.join(projectRoot, 'plugins');
+    var plugins = ls(plugins_dir);
+
+
+    // Placed at the top of cordova.js to delay onDeviceReady until all the plugins
+    // are actually loaded. This is a temporary hack that can be removed once this
+    // prototype is rolled into the main code.
+    var topJS = 'window.__onPluginsLoadedHack = true;\n';
+
+    // The main injected JS, used to inject <script> tags.
+    var js = '';
+
+    // The last part of the injected JS, which runs after all plugins are loaded and
+    // registers the clobbers, merges and runs.
+    var lateJS = '';
+
+    // Add the callback function.
+    js += 'var mapper = cordova.require("cordova/modulemapper");\n';
+    js += 'var scriptCounter = 0;\n';
+    js += 'var scriptCallback = function() {\n';
+    js += 'scriptCounter--;\n';
+    js += 'if (scriptCounter == 0) { scriptsLoaded(); } };\n';
+
+    // <script> tag injection function
+    js += 'function injectScript(path) {\n';
+        js += 'scriptCounter++;\n';
+        js += 'var script = document.createElement("script");\n';
+        js += 'script.onload = scriptCallback;\n';
+        js += 'script.src = path;\n';
+        js += 'document.querySelector("head").appendChild(script);\n';
+    js += '}\n\n';
+
+
+    // Acquire the platform's parser.
+    var parser;
+    switch(platform) {
+        case 'android':
+            parser = new android_parser(path.join(projectRoot, 'platforms', 'android'));
+            break;
+        case 'ios':
+            parser = new ios_parser(path.join(projectRoot, 'platforms', 'ios'));
+            break;
+        case 'blackberry':
+            parser = new blackberry_parser(path.join(projectRoot, 'platforms', 'blackberry'));
+            break;
+    }
+
+    plugins && plugins.forEach(function(plugin) {
+        var pluginDir = path.join(projectRoot, 'plugins', plugin);
+        var xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(pluginDir, 'plugin.xml'),
'utf-8')));
+
+        var plugin_id = xml.getroot().attrib.id;
+
+        // Copy all the <asset>s into the platform's www/
+        var assets = xml.findall('./asset');
+        assets && assets.forEach(function(asset) {
+            var target = asset.attrib.target;
+            var lastSlash = target.lastIndexOf('/');
+            var dirname  = lastSlash < 0 ? ''     : target.substring(0, lastSlash);
+            var basename = lastSlash < 0 ? target : target.substring(lastSlash + 1);
+
+            var targetDir = path.join(parser.www_dir(), dirname);
+            shell.mkdir('-p', targetDir);
+
+            var srcFile = path.join(pluginDir, asset.attrib.src);
+            var targetFile = path.join(targetDir, basename);
+
+            var cpOptions = fs.statSync(srcFile).isDirectory() ? '-Rf' : '-f';
+            shell.cp(cpOptions, [srcFile], targetFile);
+        });
+
+        // And then add the plugins dir to the platform's www.
+        var platformPluginsDir = path.join(parser.www_dir(), 'plugins');
+        shell.mkdir('-p', platformPluginsDir);
+
+        var generalModules = xml.findall('./js-module');
+        var platformTag = xml.find(util.format('./platform[@name="%s"]', platform));
+        if (!platformTag) {
+            return; // Skip plugins that don't support this platform.
+        }
+
+        var platformModules = platformTag.findall('./js-module');
+        generalModules = generalModules || [];
+        var allModules = generalModules.concat(platformModules);
+
+
+        allModules.forEach(function(module) {
+            // Copy the plugin's files into the www directory.
+            var dirname = module.attrib.src;
+            var lastSlash = dirname.lastIndexOf('/');
+            if (lastSlash >= 0) {
+                dirname = dirname.substring(0, lastSlash);
+            } else {
+                dirname = ''; // Just the file, no subdir.
+            }
+
+            var dir = path.join(platformPluginsDir, plugin_id, dirname);
+            shell.mkdir('-p', dir);
+
+            // Read in the file, prepend the cordova.define, and write it back out.
+            var moduleName = plugin_id + '.';
+            if (module.attrib.name) {
+                moduleName += module.attrib.name;
+            } else {
+                var result = module.attrib.src.match(/([^\/]+)\.js/);
+                moduleName += result[1];
+            }
+
+            var scriptContent = fs.readFileSync(path.join(pluginDir, module.attrib.src),
'utf-8');
+            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports,
module) {' + scriptContent + '});\n';
+            fs.writeFileSync(path.join(platformPluginsDir, plugin_id, module.attrib.src),
scriptContent, 'utf-8');
+
+            // Prepare the injected Javascript code.
+            var jsFile = path.join('plugins', plugin_id, module.attrib.src);
+            js += 'injectScript("' + jsFile + '");\n';
+
+            // Loop over the children, injecting clobber, merge and run code for each.
+            module.getchildren().forEach(function(child) {
+                if (child.tag.toLowerCase() == 'clobbers') {
+                    lateJS += 'mapper.clobbers("' + moduleName + '", "' + child.attrib.target
+ '");\n';
+                } else if (child.tag.toLowerCase() == 'merges') {
+                    lateJS += 'mapper.merges("' + moduleName + '", "' + child.attrib.target
+ '");\n';
+                } else if (child.tag.toLowerCase() == 'runs') {
+                    lateJS += 'cordova.require("' + moduleName + '");\n';
+                }
+            });
+            lateJS += '\n\n\n';
+        });
+    });
+
+    // Last step in lateJS that runs after the <script> tags have all loaded and
+    // all modules are properly clobbered: fire onPluginsReady event.
+    lateJS += 'cordova.require("cordova/channel").onPluginsReady.fire();\n';
+
+    // Wrap lateJS into scriptsLoaded(), which will be called after the last <script>
+    // has finished loading.
+    lateJS = 'function scriptsLoaded() {\n' + lateJS + '\n}\n';
+
+    // Now write the generated JS to the platform's cordova.js
+    var cordovaJSPath = path.join(parser.www_dir(), 'cordova.js');
+    var cordovaJS = fs.readFileSync(cordovaJSPath, 'utf-8');
+    cordovaJS = topJS + cordovaJS + '(function() { ' + js + lateJS + '})();';
+    fs.writeFileSync(cordovaJSPath, cordovaJS, 'utf-8');
+};
+
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/964e3248/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index 7bb84d7..a5d3ee7 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -29,6 +29,7 @@ var cordova_util      = require('./util'),
     hooker            = require('./hooker'),
     n                 = require('ncallbacks'),
     prompt            = require('prompt'),
+    plugin_loader = require('./plugin_loader'),
     util              = require('util');
 
 var parsers = {
@@ -45,7 +46,6 @@ module.exports = function prepare(platforms, callback) {
     }
 
     var xml = path.join(projectRoot, 'www', 'config.xml');
-    var assets = path.join(projectRoot, 'www');
     var cfg = new config_parser(xml);
 
     if (arguments.length === 0 || (platforms instanceof Array && platforms.length
=== 0)) {
@@ -74,6 +74,9 @@ module.exports = function prepare(platforms, callback) {
     platforms.forEach(function(platform) {
         var platformPath = path.join(projectRoot, 'platforms', platform);
         var parser = new parsers[platform](platformPath);
-        parser.update_project(cfg, end);
+        parser.update_project(cfg, function() {
+            plugin_loader(platform);
+            end();
+        });
     });
 };


Mime
View raw message