Return-Path: X-Original-To: apmail-cordova-commits-archive@www.apache.org Delivered-To: apmail-cordova-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7DC6A10BC3 for ; Mon, 15 Apr 2013 18:51:52 +0000 (UTC) Received: (qmail 84876 invoked by uid 500); 15 Apr 2013 18:51:50 -0000 Delivered-To: apmail-cordova-commits-archive@cordova.apache.org Received: (qmail 84800 invoked by uid 500); 15 Apr 2013 18:51:50 -0000 Mailing-List: contact commits-help@cordova.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: callback-dev@cordova.apache.org Delivered-To: mailing list commits@cordova.apache.org Received: (qmail 84039 invoked by uid 99); 15 Apr 2013 18:51:49 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 15 Apr 2013 18:51:49 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 90F871B5E0; Mon, 15 Apr 2013 18:51:49 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: timkim@apache.org To: commits@cordova.apache.org Date: Mon, 15 Apr 2013 18:52:17 -0000 Message-Id: <9496b4e63b9649ffaebd97addd64860c@git.apache.org> In-Reply-To: <9ce8167dc0c84a57a01fbbfad64cc72d@git.apache.org> References: <9ce8167dc0c84a57a01fbbfad64cc72d@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [30/54] [abbrv] git commit: --prepare with ported JS installation, cache plugins locally --prepare with ported JS installation, cache plugins locally NB: --plugins_dir argument and the --prepare command are completely untested. I'm just committing the skeleton of this change to unblock others. Project: http://git-wip-us.apache.org/repos/asf/cordova-plugman/repo Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugman/commit/9ed6d439 Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugman/tree/9ed6d439 Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugman/diff/9ed6d439 Branch: refs/heads/future Commit: 9ed6d439f37b30ac7c8689ad5aef8a66922d8406 Parents: 266ea55 Author: Braden Shepherdson Authored: Tue Mar 19 14:21:16 2013 -0400 Committer: Tim Kim Committed: Mon Apr 8 16:46:51 2013 -0700 ---------------------------------------------------------------------- FUTURE.md | 4 +- plugman.js | 44 +++++++++++++- util/plugin_loader.js | 141 ++++++++++++++++++++++++++++++++++++++++++++ util/plugins.js | 21 +++---- 4 files changed, 196 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/9ed6d439/FUTURE.md ---------------------------------------------------------------------- diff --git a/FUTURE.md b/FUTURE.md index 6ff6884..41c2c62 100644 --- a/FUTURE.md +++ b/FUTURE.md @@ -35,8 +35,8 @@ Care is required here not to remove permissions that are still needed by other p ### `--prepare` -Takes over part of cordova-cli's `prepare` command. Copies all plugins' Javascript files (more precisely, those specified in `` tags rather than `` tags) into `www/plugins/com.plugin.id/whatever/path/file.js` and constructs the `plugins.json` file. +Takes over part of cordova-cli's `prepare` command. Copies all plugins' Javascript files (more precisely, those specified in `` tags rather than `` tags) into `www/plugins/com.plugin.id/whatever/path/file.js` and constructs the `cordova_plugins.json` file. -`cordova.js` in this new model will have code that reads this `plugins.json` file via XHR, loads the JS files for the plugins, and does their clobbers and merges. +`cordova.js` in this new model will have code that reads this `cordova_plugins.json` file via XHR, loads the JS files for the plugins, and does their clobbers and merges. This is something of a change from the current cordova-cli method, but necessary because we won't be working with a fresh `cordova.js` file on each run anymore. http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/9ed6d439/plugman.js ---------------------------------------------------------------------- diff --git a/plugman.js b/plugman.js index a422dab..514952e 100755 --- a/plugman.js +++ b/plugman.js @@ -26,6 +26,8 @@ var fs = require('fs') , et = require('elementtree') , nopt = require('nopt') , plugins = require('./util/plugins') + , shell = require('shelljs') + , plugin_loader = require('./util/plugin_loader') , platform_modules = { 'android': require('./platforms/android'), 'ios': require('./platforms/ios'), @@ -40,11 +42,24 @@ var known_opts = { 'platform' : [ 'ios', 'android', 'blackberry' ,'www' ] , 'list' : Boolean , 'v' : Boolean , 'debug' : Boolean + , 'prepare' : Boolean + , 'plugins': path + , 'www': path , 'variable' : Array }, shortHands = { 'var' : 'variable' }; var cli_opts = nopt(known_opts); +// Default the plugins_dir to './cordova/plugins'. +var plugins_dir; + +// Without these arguments, the commands will fail and print the usage anyway. +if (cli_opts.plugins_dir || cli_opts.project) { + plugins_dir = typeof cli_opts.plugins_dir == 'string' ? + cli_opts.plugins_dir : + path.join(cli_opts.project, 'cordova', 'plugins'); +} + // only dump stack traces in debug mode, otherwise show error message and exit if (!cli_opts.debug) { // provide clean output on exceptions rather than dumping a stack trace @@ -64,6 +79,9 @@ else if (cli_opts.list) { } }); } +else if (cli_opts.prepare && cli_opts.project && cli_opts.www) { + util.handlePrepare(cli_opts.project, plugins_dir, cli_opts.www, cli_opts.platform); +} else if (!cli_opts.platform || !cli_opts.project || !cli_opts.plugin) { printUsage(); } @@ -84,11 +102,20 @@ else { function printUsage() { platforms = known_opts.platform.join('|'); +<<<<<<< HEAD console.error('Usage\n---------'); console.error('Add a plugin:\n\t' + package.name + ' --platform <'+ platforms +'> --project --variable ="" --plugin \n'); console.error('Remove a plugin:\n\t' + package.name + ' --remove --platform <'+ platforms +'> --project --plugin \n'); console.error('List plugins:\n\t' + package.name + ' --list\n'); process.exit(1); +======= + console.log('Usage\n---------'); + console.log('Add a plugin:\n\t' + package.name + ' --platform <'+ platforms +'> --project --plugin \n'); + console.log('Remove a plugin:\n\t' + package.name + ' --remove --platform <'+ platforms +'> --project --plugin \n'); + console.log('List plugins:\n\t' + package.name + ' --list\n'); + console.log('Prepare project:\n\t' + package.name + ' --prepare --platform --project --www [--plugins_dir ]'); + console.log('\n\t--plugins_dir defaults to /cordova/plugins, but can be any directory containing a subdirectory for each plugin'); +>>>>>>> --prepare with ported JS installation, cache plugins locally } function execAction(action, platform, project_dir, plugin_dir, cli_variables) { @@ -137,9 +164,24 @@ function execAction(action, platform, project_dir, plugin_dir, cli_variables) { function handlePlugin(action, platform, project_dir, plugin_dir, cli_variables) { var plugin_xml_path, async = false; + // Ensure the containing directory exists. + shell.mkdir('-p', plugins_dir); + // clone from git repository if(plugin_dir.indexOf('https://') == 0 || plugin_dir.indexOf('git://') == 0) { - plugin_dir = plugins.clonePluginGitRepo(plugin_dir); + plugin_dir = plugins.clonePluginGitRepo(plugin_dir, plugins_dir); + } else { // Copy from the local filesystem. + var lastSlash = plugin_dir.lastIndexOf(path.sep); + var dest = plugin_dir; + if (lastSlash >= 0) { + dest = dest.substring(lastSlash+1); + } + dest = path.join(plugins_dir, dest); + + shell.rm('-rf', dest); + shell.cp('-R', plugin_dir, plugins_dir); // Yes, not dest. + + plugin_dir = dest; } plugin_xml_path = path.join(plugin_dir, 'plugin.xml'); http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/9ed6d439/util/plugin_loader.js ---------------------------------------------------------------------- diff --git a/util/plugin_loader.js b/util/plugin_loader.js new file mode 100644 index 0000000..6d55694 --- /dev/null +++ b/util/plugin_loader.js @@ -0,0 +1,141 @@ +/** + 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, + util = require('util'), + exec = require('child_process').exec, + et = require('elementtree'); + + +// Called on --prepare. +// Sets up each plugin's Javascript code to be loaded properly. +// Expects a path to the project (platforms/android in CLI, . in plugman-only), +// a path to where the plugins are downloaded, the www dir, and the platform ('android', 'ios', etc.). +exports.handlePrepare = function(projectRoot, plugins_dir, wwwDir, platform) { + // Process: + // - List all plugins in plugins_dir + // - Load and parse their plugin.xml files. + // - Skip those without support for this platform. (No tags means JS-only!) + // - Build a list of all their js-modules, including platform-specific js-modules. + // - For each js-module (general first, then platform) build up an object storing the path and any clobbers, merges and runs for it. + // - Write this object into www/plugins.json. + // - Cordova.js contains code to load them at runtime from that file. + + var plugins = ls(plugins_dir); + + // This array holds all the metadata for each module and ends up in cordova_plugins.json + var moduleObjects = []; + + + plugins && plugins.forEach(function(plugin) { + var pluginDir = path.join(plugins_dir, 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 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(wwwDir, 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(wwwDir, 'plugins'); + shell.mkdir('-p', platformPluginsDir); + + var generalModules = xml.findall('./js-module'); + var platformTag = xml.find(util.format('./platform[@name="%s"]', platform)); + + generalModules = generalModules || []; + var platformModules = platformTag ? platformTag.findall('./js-module') : []; + 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 object for cordova_plugins.json. + var obj = { + file: path.join('plugins', plugin_id, module.attrib.src), + id: moduleName + }; + + // Loop over the children of the js-module tag, collecting clobbers, merges and runs. + module.getchildren().forEach(function(child) { + if (child.tag.toLowerCase() == 'clobbers') { + if (!obj.clobbers) { + obj.clobbers = []; + } + obj.clobbers.push(child.attrib.target); + } else if (child.tag.toLowerCase() == 'merges') { + if (!obj.merges) { + obj.merges = []; + } + obj.merges.push(child.attrib.target); + } else if (child.tag.toLowerCase() == 'runs') { + obj.runs = true; + } + }); + + // Add it to the list of module objects bound for cordova_plugins.json + moduleObjects.push(obj); + }); + }); + + // Write out moduleObjects as JSON to cordova_plugins.json + fs.writeFileSync(path.join(wwwDir, 'cordova_plugins.json'), JSON.stringify(moduleObjects), 'utf-8'); +}; + http://git-wip-us.apache.org/repos/asf/cordova-plugman/blob/9ed6d439/util/plugins.js ---------------------------------------------------------------------- diff --git a/util/plugins.js b/util/plugins.js index 19e97a8..333fd92 100644 --- a/util/plugins.js +++ b/util/plugins.js @@ -66,13 +66,20 @@ exports.listAllPlugins = function(success, error) { }); } -exports.clonePluginGitRepo = function(plugin_git_url) { +exports.clonePluginGitRepo = function(plugin_git_url, plugins_dir) { if(!shell.which('git')) { throw new Error('git command line is not installed'); } // use osenv to get a temp directory in a portable way - plugin_dir = path.join(osenv.tmpdir(), 'plugin'); - + var lastSlash = plugin_git_url.lastIndexOf('/'); + var basename = plugin_git_url.substring(lastSlash+1); + var dotGitIndex = basename.lastIndexOf('.git'); + if (dotGitIndex >= 0) { + basename = basename.substring(0, dotGitIndex); + } + + var plugin_dir = path.join(plugins_dir, basename); + // trash it if it already exists (something went wrong before probably) if(fs.existsSync(plugin_dir)) { shell.rm('-rf', plugin_dir); @@ -82,14 +89,6 @@ exports.clonePluginGitRepo = function(plugin_git_url) { throw new Error('failed to get the plugin via git URL '+ plugin_git_url); } - process.on('exit', function() { - console.log('cleaning up...'); - // clean up - if(fs.existsSync(plugin_dir)) { - shell.rm('-rf', plugin_dir); - } - }); - return plugin_dir; }