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 <anis.ka...@gmail.com> Authored: Thu Jul 26 11:50:38 2012 -0700 Committer: Anis Kadri <anis.ka...@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": "fil...@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>