You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2012/08/27 23:32:44 UTC
[7/7] git commit: First cordova-client commit
First cordova-client commit
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/commit/bbf207f0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/tree/bbf207f0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/diff/bbf207f0
Branch: refs/heads/cordova-client
Commit: bbf207f0a27bc0b3adee3d045210e6ae2a540898
Parents: 68340ce
Author: Anis Kadri <an...@gmail.com>
Authored: Thu Jul 26 11:50:38 2012 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu Jul 26 11:50:38 2012 -0700
----------------------------------------------------------------------
README.md | 149 +++++++++++++++++++++++++++++++++++----
bin/cordova | 18 +++++
cordova.js | 91 ++++++++++++++++++++++++
doc/help.txt | 24 ++++++
package.json | 37 ++++++++++
platforms.js | 1 +
spec/_platform.spec.js | 135 +++++++++++++++++++++++++++++++++++
spec/config_parser.spec.js | 86 ++++++++++++++++++++++
spec/create.spec.js | 39 ++++++++++
src/build.js | 57 +++++++++++++++
src/config_parser.js | 42 +++++++++++
src/emulate.js | 27 +++++++
src/platform.js | 91 ++++++++++++++++++++++++
src/plugin.js | 67 +++++++++++++++++
src/util.js | 34 +++++++++
templates/www/config.xml | 58 +++++++++++++++
templates/www/index.html | 10 +++
17 files changed, 952 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 2d78d3a..3e6883f 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,143 @@
-# Cordova Laboratory
+# cordova-client
-> Caution: Safety Goggles are Recommended!
+> Build, deploy and manage [Cordova](http://cordova.io)-based applications.
-## Purpose
+## Supported Platforms
-The purpose of this repo is for experimental code. Examples include demo apps,
-native api explorations, or anything really that does not fit in an existing Cordova platform.
+- iOS
+- Android
-## Project Organization
+# Requirements
-> Everyone works on a branch
+Cordova client requires [nodejs](http://nodejs.org/).
-`master` branch should *never* have content.
+For every platform that Cordova supports and you want to use with
+cordova-client, you will need to install the SDK for that platform. See:
-Each project should create a separate branch to work on. There are major benefits
-to this practice:
+- [iOS SDK](http://developer.apple.com)
+- [Android SDK](http://developer.android.com)
+- [BlackBerry WebWorks SDK](http://developer.blackberry.com)
-- Each project has an isolate git history, which allows for easy migration to
- a new git repository;
-- Working directory is not polluted with the files of other projects.
-- Projects will not step on each others toes.
+Cordova client has been tested on Windows, Linux and Mas OS X.
+
+# Getting Started
+
+You should (eventually) be able to `npm install cordova-client -g`.
+Until then, after you clone this code, run `npm install` from inside this
+directory. After that you will be able to access the client interface
+via:
+
+ $ ./bin/cordova
+
+## Creating A Cordova-Based Project
+
+ $ cordova create [directory]
+
+Creates a Cordova application. When called with no arguments, `cordova create` will generate a Cordova-based project in the current directory.
+
+A Cordova application built with cordova-client will have the following
+directory structure:
+
+ myApp
+ |-.cordova
+ |- platforms
+ |- plugins
+ `- www
+
+- `.cordova`: contains meta-data related to your application
+- `platforms`: platforms added to your application will have the native
+ application project structures laid out within this directory
+- `plugins`: any added plugins will be extracted into this directory
+- `www`: your main application assets
+
+From here, you have a Cordova-based project whose state you can
+manipulate using the below project-level commands.
+
+## Project-Level Commands
+
+Inside a Cordova-based project, you can use `cordova` with the
+`platform`, `plugin`, `build` and `emulate` sub-commands.
+
+### Managing Platforms
+
+#### Listing All Platforms
+
+ $ cordova platform [ls]
+
+Lists out all platforms that the Cordova-based project is currently
+being built to.
+
+#### Adding A Platform
+
+ $ cordova platform add [platform]
+
+Adds the platform as a build target for the current Cordova-based
+project.
+
+#### Removing A Platform
+
+ $ cordova platform remove [platform]
+
+Removes the platform as a build target from the current Cordova-based
+project.
+
+### Building Your Project
+
+ $ cordova build
+
+You can call `cordova build` with no arguments if you are inside a cordova based project. This will compile your app for all platforms added to your Cordova project.
+
+### Emulating Your Project
+
+ $ cordova emulate
+
+Will launch emulators for all platforms added to your
+Cordova project.
+
+### Managing Plugins
+
+Plugin integration hinges on:
+
+- You having the plugin code locally on your computer
+- The plugin code adheres to the [Cordova Plugin Specification](https://github.com/alunny/cordova-plugin-spec)
+
+#### Listing All Plugins
+
+ $ cordova plugin [ls]
+
+Lists out all plugins added to the current Cordova-based project.
+
+#### Adding A Plugin
+
+ $ cordova plugin add [path-to-plugin]
+
+Adds the platform as a build target for the current Cordova-based
+project.
+
+#### Removing A Plugin
+
+ $ cordova plugin remove [plugin]
+
+**NOT IMPLEMENTED!**
+
+# Examples
+
+## Creating a sample project
+
+ $ cordova create
+
+# Contributing
+
+## Running Tests
+
+ $ npm test
+
+**WARNING**: If you run tests and don't have any sub-directories under
+`./lib`, be prepared to see some failing tests as then this project will
+start cloning any necessary Cordova libraries (which may take a while).
+
+## TO-DO
+
+- `grep` through this project for 'TODO'
+- blackberry support
+- moar tests
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/bin/cordova
----------------------------------------------------------------------
diff --git a/bin/cordova b/bin/cordova
new file mode 100755
index 0000000..439ea35
--- /dev/null
+++ b/bin/cordova
@@ -0,0 +1,18 @@
+#!/usr/bin/env node
+var cordova = require('./../cordova')
+, cmd = process.argv[2]
+, opts = process.argv.slice(3, process.argv.length)
+
+if (cmd === undefined) {
+ console.log(cordova.help());
+} else if (cordova.hasOwnProperty(cmd)) {
+ try {
+ var r = cordova[cmd].apply(this, opts);
+ if (r) console.log(r);
+ } catch(e) {
+ console.error(e);
+ }
+}
+else {
+ console.error('Cordova does not know ' + cmd + '; try help for a list of all the available commands.')
+}
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/cordova.js
----------------------------------------------------------------------
diff --git a/cordova.js b/cordova.js
new file mode 100755
index 0000000..e29bd53
--- /dev/null
+++ b/cordova.js
@@ -0,0 +1,91 @@
+var fs = require('fs')
+, path = require('path')
+, util = require('util')
+, exec = require('child_process').exec
+, dist = process.env.CORDOVA_HOME != undefined ? process.env.CORDOVA_HOME : path.join(__dirname, 'lib', 'cordova-1.9.0')
+, colors = require('colors')
+, wrench = require('wrench')
+, config_parser = require('./src/config_parser')
+
+
+module.exports = {
+ help: function help () {
+ var raw = fs.readFileSync(path.join(__dirname, 'doc', 'help.txt')).toString('utf8').split("\n");
+ return raw.map(function(line) {
+ if (line.match(' ')) {
+ var prompt = ' $ '
+ , isPromptLine = !!(line.indexOf(prompt) != -1);
+ if (isPromptLine) {
+ return prompt.green + line.replace(prompt, '');
+ }
+ else {
+ return line.split(/\./g).map( function(char) {
+ if (char === '') {
+ return '.'.grey;
+ }
+ else {
+ return char;
+ }
+ }).join('');
+ }
+ }
+ else {
+ return line.magenta;
+ }
+ }).join("\n");
+ },
+ docs: function docs () {
+
+ var express = require('express')
+ , port = 2222
+ , static = path.join(dist, 'doc')
+ , server = express.createServer();
+
+ server.configure(function() {
+ server.use(express.static(static));
+ server.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+ });
+
+ server.get('/', function(req, res) {
+ return res.render('index.html');
+ });
+
+ console.log("\nServing Cordova/Docs at: ".grey + 'http://localhost:2222'.blue.underline + "\n");
+ console.log('Hit ctrl + c to terminate the process.'.cyan);
+ server.listen(parseInt(port, 10));
+ },
+ create: function create (dir) {
+ if (dir === undefined) {
+ return module.exports.help();
+ }
+
+
+ var mkdirp = wrench.mkdirSyncRecursive,
+ cpr = wrench.copyDirSyncRecursive;
+ if (dir && (dir[0] == '~' || dir[0] == '/')) {
+ } else {
+ dir = dir ? path.join(process.cwd(), dir) : process.cwd();
+ }
+
+ // Check for existing cordova project
+ try {
+ if (fs.lstatSync(path.join(dir, '.cordova')).isDirectory()) {
+ console.error('Cordova project already exists at ' + dir + ', aborting.');
+ return;
+ }
+ } catch(e) { /* no dirs, we're fine */ }
+
+ // Create basic project structure.
+ mkdirp(path.join(dir, '.cordova'));
+ mkdirp(path.join(dir, 'platforms'));
+ mkdirp(path.join(dir, 'plugins'));
+ mkdirp(path.join(dir, 'www'));
+
+ // Copy in base template
+ cpr(path.join(__dirname, 'templates', 'www'), path.join(dir, 'www'));
+ },
+ platform:require('./src/platform'),
+ build:require('./src/build'),
+ emulate:require('./src/emulate'),
+ plugin:require('./src/plugin')
+};
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/doc/help.txt
----------------------------------------------------------------------
diff --git a/doc/help.txt b/doc/help.txt
new file mode 100644
index 0000000..fdc2cba
--- /dev/null
+++ b/doc/help.txt
@@ -0,0 +1,24 @@
+
+Synopsis
+
+ cordova command [options]
+
+Global Commands
+
+ create [path]...................... creates a cordova project in the specified directory
+
+Project-Level Commands
+
+ platform [add|remove|ls [name]] ... adds or removes a platform, or lists all currently-added platforms
+ plugin [add|remove|ls [path]] ..... adds or removes a plugin (from the specified path), or lists all currently-added plugins
+ build ............................. builds a cordova project
+ emulate ........................... starts emulator for cordova project
+ docs .............................. serves docs at http://localhost:2222
+
+Example usage
+
+ $ cordova create Baz
+ $ cd Baz
+ $ cordova platform add android
+ $ codova build && cordova emulate
+
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6b0205c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "cordova",
+ "version": "0.0.2",
+ "preferGlobal": "true",
+ "description": "Cordova client tool",
+ "main": "cordova",
+ "bin": {
+ "cordova": "./bin/cordova"
+ },
+ "scripts": {
+ "test": "./node_modules/jasmine-node/bin/jasmine-node --color spec"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/imhotep/cordova-client.git"
+ },
+ "keywords": [
+ "cordova",
+ "client",
+ "cli"
+ ],
+ "dependencies": {
+ "colors":">=0.6.0",
+ "wrench":"",
+ "elementtree":"",
+ "pluginstall":"git+https://github.com/filmaj/pluginstall.git"
+ },
+ "devDependencies": {
+ "jasmine-node":">=1.0.0"
+ },
+ "author": "Anis Kadri",
+ "contributors": [
+ {"name": "Brian LeRoux","email": "b@brian.io"},
+ {"name": "Fil Maj", "email": "filmaj@apache.org"}
+ ],
+ "license": "Apache version 2.0"
+}
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/platforms.js
----------------------------------------------------------------------
diff --git a/platforms.js b/platforms.js
new file mode 100644
index 0000000..c6c5601
--- /dev/null
+++ b/platforms.js
@@ -0,0 +1 @@
+module.exports = ['ios','android'];
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/spec/_platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/_platform.spec.js b/spec/_platform.spec.js
new file mode 100644
index 0000000..378d705
--- /dev/null
+++ b/spec/_platform.spec.js
@@ -0,0 +1,135 @@
+// Spy on exec so we can mock out certain CLI calls (and speed up
+// testing)
+var _exec = require('child_process').exec;
+require('child_process').exec = function(cmd, cb){
+ var space = cmd.indexOf(' ');
+ // Just invoke callback for create calls.
+ if (Array.prototype.slice.call(cmd, space-6, space).join('') == 'create') {
+ cb();
+ } else {
+ _exec(cmd, cb);
+ }
+};
+
+var cordova = require('../cordova'),
+ wrench = require('wrench'),
+ mkdirp = wrench.mkdirSyncRecursive,
+ path = require('path'),
+ rmrf = wrench.rmdirSyncRecursive,
+ fs = require('fs'),
+ tempDir = path.join(__dirname, '..', 'temp');
+
+
+describe('platform command', function() {
+ beforeEach(function() {
+ // Make a temp directory
+ try { rmrf(tempDir); } catch(e) {}
+ mkdirp(tempDir);
+ });
+
+ it('should run inside a Cordova-based project', function() {
+ var cwd = process.cwd();
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.platform();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ var cwd = process.cwd();
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.platform();
+ }).toThrow();
+ });
+
+ describe('ls', function() {
+ var cwd = process.cwd();
+
+ beforeEach(function() {
+ cordova.create(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should list out no platforms for a fresh project', function() {
+ process.chdir(tempDir);
+
+ expect(cordova.platform('ls')).toEqual('No platforms added. Use `cordova platform add <platform>`.');
+ });
+
+ it('should list out added platforms in a project', function() {
+ var cb = jasmine.createSpy().andCallFake(function() {
+ expect(cordova.platform('ls')).toEqual('android');
+ });
+
+ process.chdir(tempDir);
+ runs(function() {
+ cordova.platform('add', 'android', cb);
+ });
+ waitsFor(function() { return cb.wasCalled; }, "create callback", 17500);
+ });
+ });
+
+ describe('add', function() {
+ var cwd = process.cwd();
+
+ beforeEach(function() {
+ cordova.create(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should add a supported platform', function() {
+ var cb = jasmine.createSpy().andCallFake(function() {
+ expect(cordova.platform('ls')).toEqual('android');
+ });
+
+ process.chdir(tempDir);
+ runs(function() {
+ cordova.platform('add', 'android', cb);
+ });
+ waitsFor(function() { return cb.wasCalled; }, "create callback", 17500);
+ });
+ });
+
+ describe('remove', function() {
+ var cwd = process.cwd();
+
+ beforeEach(function() {
+ cordova.create(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should remove a supported and added platform', function() {
+ var cb = jasmine.createSpy().andCallFake(function() {
+ cordova.platform('remove', 'android');
+ expect(cordova.platform('ls')).toEqual('No platforms added. Use `cordova platform add <platform>`.');
+ });
+
+ process.chdir(tempDir);
+ runs(function() {
+ cordova.platform('add', 'android', cb);
+ });
+ waitsFor(function() { return cb.wasCalled; }, "create callback", 17500);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/spec/config_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/config_parser.spec.js b/spec/config_parser.spec.js
new file mode 100644
index 0000000..ba39e0a
--- /dev/null
+++ b/spec/config_parser.spec.js
@@ -0,0 +1,86 @@
+var cordova = require('../cordova'),
+ wrench = require('wrench'),
+ mkdirp = wrench.mkdirSyncRecursive,
+ path = require('path'),
+ rmrf = wrench.rmdirSyncRecursive,
+ fs = require('fs'),
+ config_parser = require('../src/config_parser'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ et = require('elementtree'),
+ xml = path.join(tempDir, 'www', 'config.xml');
+
+describe('config parser', function () {
+ beforeEach(function() {
+ // Make a temp directory
+ try { rmrf(tempDir); } catch(e) {}
+ mkdirp(tempDir);
+ cordova.create(tempDir);
+ });
+
+ it('should create an instance based on an xml file', function() {
+ var cfg;
+ expect(function () {
+ cfg = new config_parser(xml);
+ }).not.toThrow();
+ expect(cfg).toBeDefined();
+ expect(cfg.doc).toBeDefined();
+ });
+
+ describe('platforms', function() {
+ describe('ls command', function() {
+ it('should return an empty array if there are no platforms specified in the document', function() {
+ var cfg = new config_parser(xml);
+
+ expect(cfg.ls_platforms().length).toBe(0);
+ });
+ it('should return a populated array if there are platforms specified in the document', function() {
+ var doc = new et.ElementTree(et.XML(fs.readFileSync(xml, 'utf-8')));
+ var p = new et.Element('platform');
+ p.attrib['name'] = 'android';
+ doc.find('platforms').append(p);
+ fs.writeFileSync(xml, doc.write(), 'utf-8');
+
+ var cfg = new config_parser(xml);
+ expect(cfg.ls_platforms().length).toBe(1);
+ expect(cfg.ls_platforms()[0]).toEqual('android');
+ });
+ });
+
+ describe('add command', function() {
+ it('should add a platform element to the platforms element', function() {
+ var cfg = new config_parser(xml);
+ cfg.add_platform('android');
+
+ var doc = new et.ElementTree(et.XML(fs.readFileSync(xml, 'utf-8')));
+ expect(doc.find('platforms').getchildren()[0].attrib['name']).toEqual('android');
+ });
+ it('should ignore existing platforms', function() {
+ var cfg = new config_parser(xml);
+ cfg.add_platform('android');
+ cfg.add_platform('android');
+
+ var doc = new et.ElementTree(et.XML(fs.readFileSync(xml, 'utf-8')));
+ expect(doc.find('platforms').getchildren().length).toEqual(1);
+ });
+ it('should ignore garbage platforms', function() {
+ var cfg = new config_parser(xml);
+ cfg.add_platform('bat country');
+
+ var doc = new et.ElementTree(et.XML(fs.readFileSync(xml, 'utf-8')));
+ expect(doc.find('platforms').getchildren().length).toEqual(0);
+ });
+ });
+
+ describe('remove command', function() {
+ it('should remove a platform element from the platforms element', function() {
+ var cfg = new config_parser(xml);
+ cfg.add_platform('ios');
+
+ cfg.remove_platform('ios');
+
+ var doc = new et.ElementTree(et.XML(fs.readFileSync(xml, 'utf-8')));
+ expect(doc.find('platforms').getchildren().length).toEqual(0);
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
new file mode 100644
index 0000000..bdd2ceb
--- /dev/null
+++ b/spec/create.spec.js
@@ -0,0 +1,39 @@
+var cordova = require('../cordova'),
+ wrench = require('wrench'),
+ mkdirp = wrench.mkdirSyncRecursive,
+ path = require('path'),
+ rmrf = wrench.rmdirSyncRecursive,
+ fs = require('fs'),
+ tempDir = path.join(__dirname, '..', 'temp');
+
+describe('create command', function () {
+ beforeEach(function() {
+ // Make a temp directory
+ try { rmrf(tempDir); } catch(e) {}
+ mkdirp(tempDir);
+ });
+
+ it('should print out help txt if no directory is provided', function() {
+ var cwd = process.cwd();
+ this.after(function() {
+ process.chdir(cwd);
+ });
+ process.chdir(tempDir);
+ expect(cordova.create()).toMatch(/synopsis/i);
+ });
+ it('should create a cordova project in the specified directory if parameter is provided', function() {
+ cordova.create(tempDir);
+ expect(fs.lstatSync(path.join(tempDir, '.cordova')).isDirectory()).toBe(true);
+ });
+ it('should warn if the directory is already a cordova project', function() {
+ spyOn(console, 'error');
+
+ var cb = jasmine.createSpy();
+
+ mkdirp(path.join(tempDir, '.cordova'));
+
+ cordova.create(tempDir);
+
+ expect(console.error).toHaveBeenCalled();
+ });
+});
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/build.js
----------------------------------------------------------------------
diff --git a/src/build.js b/src/build.js
new file mode 100644
index 0000000..fc9453e
--- /dev/null
+++ b/src/build.js
@@ -0,0 +1,57 @@
+var cordova_util = require('./util'),
+ path = require('path'),
+ exec = require('child_process').exec,
+ wrench = require('wrench'),
+ rmrf = wrench.rmdirSyncRecursive,
+ cpr = wrench.copyDirSyncRecursive,
+ config_parser = require('./config_parser'),
+ fs = require('fs'),
+ util = require('util');
+
+module.exports = function build () {
+ var projectRoot = cordova_util.isCordova(process.cwd());
+
+ if (!projectRoot) {
+ throw 'Current working directory is not a Cordova-based project.';
+ }
+
+ var xml = path.join(projectRoot, 'www', 'config.xml');
+ var assets = path.join(projectRoot, 'www');
+ var cfg = new config_parser(xml);
+ var platforms = cfg.ls_platforms();
+
+ // Iterate over each added platform
+ platforms.map(function(platform) {
+ // Copy in latest www assets.
+ var assetsPath;
+ switch (platform) {
+ // First clean out the existing www.
+ case 'android':
+ assetsPath = path.join(projectRoot, 'platforms', 'android', 'assets', 'www');
+ break;
+ case 'ios':
+ assetsPath = path.join(projectRoot, 'platforms', 'ios', 'www');
+ break;
+ }
+ rmrf(assetsPath);
+ cpr(assets, assetsPath);
+ // Copy in the appropriate JS
+ var js;
+ var jsPath = path.join(assetsPath, 'cordova.js');
+ switch (platform) {
+ case 'android':
+ js = path.join(__dirname, '..', 'lib', 'android', 'framework', 'assets', 'js', 'cordova.android.js');
+ break;
+ case 'ios':
+ js = path.join(__dirname, '..', 'lib', 'ios', 'CordovaLib', 'javascript', 'cordova.ios.js');
+ break;
+ }
+ fs.writeFileSync(jsPath, fs.readFileSync(js));
+
+ // shell out to debug command
+ var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'debug > /dev/null');
+ exec(cmd, function(err, stderr, stdout) {
+ if (err) throw 'An error occurred while building the ' + platform + ' project. ' + err;
+ });
+ });
+};
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/config_parser.js
----------------------------------------------------------------------
diff --git a/src/config_parser.js b/src/config_parser.js
new file mode 100644
index 0000000..979e71f
--- /dev/null
+++ b/src/config_parser.js
@@ -0,0 +1,42 @@
+var et = require('elementtree'),
+ platforms = require('./../platforms'),
+ fs = require('fs');
+
+function config_parser(xmlPath) {
+ this.path = xmlPath;
+ this.doc = new et.ElementTree(et.XML(fs.readFileSync(xmlPath, 'utf-8')));
+}
+
+config_parser.prototype = {
+ ls_platforms:function() {
+ return this.doc.find('platforms').getchildren().map(function(p) {
+ return p.attrib['name'];
+ });
+ },
+ add_platform:function(platform) {
+ if ((platforms.indexOf(platform) == -1) || this.doc.find('platforms/platform[@name="' + platform + '"]')) return;
+ else {
+ var p = new et.Element('platform');
+ p.attrib['name'] = platform;
+ this.doc.find('platforms').append(p);
+ fs.writeFileSync(this.path, this.doc.write(), 'utf-8');
+ }
+ },
+ remove_platform:function(platform) {
+ if ((platforms.indexOf(platform) == -1) || !(this.doc.find('platforms/platform[@name="' + platform + '"]'))) return;
+ else {
+ var psEl = this.doc.find('platforms');
+ var pEl = psEl.find('platform[@name="' + platform + '"]');
+ psEl.remove(null, pEl);
+ fs.writeFileSync(this.path, this.doc.write(), 'utf-8');
+ }
+ },
+ packageName:function() {
+ return this.doc.getroot().attrib.id;
+ },
+ name:function() {
+ return this.doc.find('name').text;
+ }
+};
+
+module.exports = config_parser;
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/emulate.js
----------------------------------------------------------------------
diff --git a/src/emulate.js b/src/emulate.js
new file mode 100644
index 0000000..a7825c1
--- /dev/null
+++ b/src/emulate.js
@@ -0,0 +1,27 @@
+var cordova_util = require('./util'),
+ path = require('path'),
+ exec = require('child_process').exec,
+ config_parser = require('./config_parser'),
+ fs = require('fs'),
+ util = require('util');
+
+module.exports = function emulate () {
+ var projectRoot = cordova_util.isCordova(process.cwd());
+
+ if (!projectRoot) {
+ throw 'Current working directory is not a Cordova-based project.';
+ }
+
+ var xml = path.join(projectRoot, 'www', 'config.xml');
+ var cfg = new config_parser(xml);
+ var platforms = cfg.ls_platforms();
+
+ // Iterate over each added platform and shell out to debug command
+ platforms.map(function(platform) {
+ var cmd = path.join(projectRoot, 'platforms', platform, 'cordova', 'emulate');
+ exec(cmd, function(err, stderr, stdout) {
+ if (err) throw 'An error occurred while emulating/deploying the ' + platform + ' project.' + err;
+ });
+ });
+};
+
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
new file mode 100644
index 0000000..16da06b
--- /dev/null
+++ b/src/platform.js
@@ -0,0 +1,91 @@
+var config_parser = require('./config_parser'),
+ cordova_util = require('./util'),
+ util = require('util'),
+ fs = require('fs'),
+ wrench = require('wrench'),
+ rmrf = wrench.rmdirSyncRecursive,
+ exec = require('child_process').exec,
+ path = require('path');
+
+var repos = {
+ ios:'https://git-wip-us.apache.org/repos/asf/incubator-cordova-ios.git',
+ android:'https://git-wip-us.apache.org/repos/asf/incubator-cordova-android.git'
+};
+
+// Creates a platform app using the ./bin/create scripts that exist in
+// each repo.
+// TODO: eventually refactor to allow multiple versions to be created.
+// Currently only checks out HEAD.
+function create(target, dir, cfg, callback) {
+ // Check if it already exists.
+ try {
+ fs.lstatSync(dir);
+ } catch(e) {
+ // Doesn't exist, continue.
+ var bin = path.join(__dirname, '..', 'lib', target, 'bin', 'create');
+ var pkg = cfg.packageName();
+ var name = cfg.name().replace(/\W/g,'_');
+ var cmd = util.format('%s "%s" "%s" "%s"', bin, dir, pkg, name);
+ exec(cmd, function(err, stderr, stdout) {
+ if (err) {
+ cfg.remove_platform(target);
+ throw 'An error occured during creation of ' + target + ' sub-project. ' + err;
+ } else if (callback) callback();
+ });
+ }
+}
+
+module.exports = function platform(command, target, callback) {
+ var projectRoot = cordova_util.isCordova(process.cwd());
+
+ if (!projectRoot) {
+ throw 'Current working directory is not a Cordova-based project.';
+ }
+ if (arguments.length === 0) command = 'ls';
+
+ var xml = path.join(projectRoot, 'www', 'config.xml');
+ var cfg = new config_parser(xml);
+
+ switch(command) {
+ case 'ls':
+ var platforms = cfg.ls_platforms();
+ if (platforms.length) {
+ return platforms.join('\n');
+ } else return 'No platforms added. Use `cordova platform add <platform>`.';
+ break;
+ case 'add':
+ // Add the platform to the config.xml
+ cfg.add_platform(target);
+
+ var output = path.join(projectRoot, 'platforms', target);
+
+ // Do we have the cordova library for this platform?
+ if (!cordova_util.havePlatformLib(target)) {
+ // Shell out to git.
+ var outPath = path.join(__dirname, '..', 'lib', target);
+ var cmd = util.format('git clone %s %s', repos[target], outPath);
+ console.log('Cloning ' + repos[target] + ', this may take a while...');
+ exec(cmd, function(err, stderr, stdout) {
+ if (err) {
+ cfg.remove_platform(target);
+ throw 'An error occured during git-clone of ' + repos[target] + '. ' + err;
+ }
+ create(target, output, cfg, callback);
+ });
+ } else {
+ create(target, output, cfg, callback);
+ }
+ break;
+ case 'remove':
+ // Remove the platform from the config.xml
+ cfg.remove_platform(target);
+
+ // Remove the Cordova project for the platform.
+ try {
+ rmrf(path.join(projectRoot, 'platforms', target));
+ } catch(e) {}
+ break;
+ default:
+ throw 'Unrecognized command "' + command + '". Use either `add`, `remove`, or `ls`.';
+ }
+};
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
new file mode 100644
index 0000000..f5acc4b
--- /dev/null
+++ b/src/plugin.js
@@ -0,0 +1,67 @@
+var cordova_util = require('./util'),
+ util = require('util'),
+ wrench = require('wrench'),
+ fs = require('fs'),
+ path = require('path'),
+ config_parser = require('./config_parser'),
+ exec = require('child_process').exec,
+ ls = fs.readdirSync;
+
+module.exports = function plugin(command, target) {
+ var projectRoot = cordova_util.isCordova(process.cwd());
+
+ if (!projectRoot) {
+ throw 'Current working directory is not a Cordova-based project.';
+ }
+ if (arguments.length === 0) command = 'ls';
+
+ // Grab config info for the project
+ var xml = path.join(projectRoot, 'www', 'config.xml');
+ var cfg = new config_parser(xml);
+ var platforms = cfg.ls_platforms();
+
+ // Massage plugin name / path
+ var pluginPath = path.join(projectRoot, 'plugins');
+ var plugins = ls(pluginPath);
+ var targetName = target.substr(target.lastIndexOf('/') + 1);
+ if (targetName[targetName.length-1] == '/') targetName = targetName.substr(0, targetName.length-1);
+
+ switch(command) {
+ case 'ls':
+ if (plugins.length) {
+ return plugins.join('\n');
+ } else return 'No plugins added. Use `cordova plugin add <plugin>.';
+ break;
+ case 'add':
+ // Check if we already have the plugin.
+ if (plugins.indexOf(targetName) > -1) {
+ throw 'Plugin "' + targetName + '" already added to project.';
+ }
+
+ // Check if the plugin has a plugin.xml in the root of the
+ // specified dir.
+ var pluginContents = ls(target);
+ if (pluginContents.indexOf('plugin.xml') == -1) {
+ throw 'Plugin "' + targetName + '" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec';
+ }
+
+ // Iterate over all platforms in the project and install the
+ // plugin.
+ var cli = path.join(__dirname, '..', 'node_modules', 'pluginstall', 'cli.js');
+ platforms.map(function(platform) {
+ var cmd = util.format('%s %s "%s" "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
+ exec(cmd, function(err, stderr, stdout) {
+ if (err) {
+ console.error(stderr);
+ throw 'An error occured during plugin installation. ' + err;
+ }
+ });
+ });
+
+ break;
+ case 'remove':
+ throw 'Plugin removal not supported yet! sadface';
+ default:
+ throw 'Unrecognized command "' + command + '". Use either `add`, `remove`, or `ls`.';
+ }
+};
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
new file mode 100644
index 0000000..b4c7b8f
--- /dev/null
+++ b/src/util.js
@@ -0,0 +1,34 @@
+var fs = require('fs'),
+ path = require('path');
+
+module.exports = {
+ // Runs up the directory chain looking for a .cordova directory.
+ // IF it is found we are in a Cordova project.
+ // If not.. we're not.
+ isCordova: function isCordova(dir) {
+ if (dir) {
+ var contents = fs.readdirSync(dir);
+ if (contents && contents.length && (contents.indexOf('.cordova') > -1)) {
+ return dir;
+ } else {
+ var parent = path.join(dir, '..');
+ if (parent && parent.length > 1) {
+ return isCordova(parent);
+ } else return false;
+ }
+ } else return false;
+ },
+ // Determines whether the library has a copy of the specified
+ // Cordova implementation
+ havePlatformLib: function havePlatformLib(platform) {
+ var dir = path.join(__dirname, '..', 'lib', platform);
+ try {
+ fs.lstatSync(dir);
+ // Have it!
+ return true;
+ } catch(e) {
+ // Don't have it.
+ return false;
+ }
+ }
+};
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/templates/www/config.xml
----------------------------------------------------------------------
diff --git a/templates/www/config.xml b/templates/www/config.xml
new file mode 100644
index 0000000..400c377
--- /dev/null
+++ b/templates/www/config.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets"
+ xmlns:rim="http://www.blackberry.com/ns/widgets"
+ id="org.apache.cordova.sampleapp"
+ version="1.0.0">
+
+ <name>Cordova Sample Application</name>
+
+ <description>
+ Mind-blowing Sample Application
+ </description>
+
+ <author>
+ Anonymous
+ </author>
+
+ <platforms>
+ </platforms>
+
+ <!-- Cordova API -->
+ <feature id="org.apache.cordova" required="true" version="1.0.0" />
+ <!-- BlackBerry-specific -->
+ <feature id="blackberry.system" required="true" version="1.0.0.0" />
+ <feature id="blackberry.find" required="true" version="1.0.0.0" />
+ <feature id="blackberry.identity" required="true" version="1.0.0.0" />
+ <feature id="blackberry.pim.Address" required="true" version="1.0.0.0" />
+ <feature id="blackberry.pim.Contact" required="true" version="1.0.0.0" />
+ <feature id="blackberry.io.file" required="true" version="1.0.0.0" />
+ <feature id="blackberry.utils" required="true" version="1.0.0.0" />
+ <feature id="blackberry.io.dir" required="true" version="1.0.0.0" />
+ <feature id="blackberry.app" required="true" version="1.0.0.0" />
+ <feature id="blackberry.app.event" required="true" version="1.0.0.0" />
+ <feature id="blackberry.system.event" required="true" version="1.0.0.0"/>
+ <feature id="blackberry.widgetcache" required="true" version="1.0.0.0"/>
+ <feature id="blackberry.media.camera" />
+ <feature id="blackberry.ui.dialog" />
+ <feature id="blackberry.media.microphone" required="true" version="1.0.0.0"/>
+
+ <!-- Cordova API -->
+ <access subdomains="true" uri="file:///store/home" />
+ <access subdomains="true" uri="file:///SDCard" />
+ <!-- Expose access to all URIs, including the file and http protocols -->
+ <access subdomains="true" uri="*" />
+
+ <!-- potential icon stuff
+ <icon src="blurry.png" /> -->
+
+ <!-- Starting Page -->
+ <content src="index.html" />
+
+ <rim:permissions>
+ <rim:permit>use_camera</rim:permit>
+ <rim:permit>read_device_identifying_information</rim:permit>
+ <rim:permit>access_shared</rim:permit>
+ <rim:permit>read_geolocation</rim:permit>
+ <rim:permit>record_audio</rim:permit>
+ </rim:permissions>
+</widget>
http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/bbf207f0/templates/www/index.html
----------------------------------------------------------------------
diff --git a/templates/www/index.html b/templates/www/index.html
new file mode 100644
index 0000000..51661b3
--- /dev/null
+++ b/templates/www/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Sample Cordova Project</title>
+ <script src="cordova.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <h1>Hello Cordova</h1>
+ </body>
+</html>