Most of the way there for #2 (config.xml as user endpoint for modifying app metadata). Fixes #6: can specify app name at create time (and optionally id/package name as well).
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/a40a01c3 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/tree/a40a01c3 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/diff/a40a01c3 Branch: refs/heads/cordova-client Commit: a40a01c308f58e3580560f24b4de4e386dfe56b6 Parents: 52f12bb Author: Fil Maj <maj....@gmail.com> Authored: Thu Jul 26 01:28:54 2012 -0700 Committer: Fil Maj <maj....@gmail.com> Committed: Thu Jul 26 01:28:54 2012 -0700 ---------------------------------------------------------------------- README.md | 11 +++++--- spec/config_parser.spec.js | 44 ++++++++++++++++++++++++++++++++- spec/create.spec.js | 26 ++++++++++++++++++- src/build.js | 45 +++++++++++++++++++--------------- src/config_parser.js | 25 +++++++++++++------ src/create.js | 50 +++++++++++++++++++++++++++++--------- 6 files changed, 153 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md index 23cdfe2..667c4cd 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Cordova client has been tested on Windows, Linux and Mas OS X. 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 +directory (you may want to run that with `sudo`). After that you will be able to access the client interface via: $ ./bin/cordova @@ -32,8 +32,12 @@ via: ## Creating A Cordova-Based Project $ cordova create [directory] + $ cordova create [directory name] + $ cordova create [directory id name] -Creates a Cordova application. When called with no arguments, `cordova create` will generate a Cordova-based project in the current directory. +Creates a Cordova application. You can optionally specify just a name +for your application, or both an id (package name or reverse-domain +style id) and a name. A Cordova application built with cordova-client will have the following directory structure: @@ -124,7 +128,7 @@ project. ## Creating a sample project - $ cordova create + $ cordova create ~/src/myNewApp # Contributing @@ -139,7 +143,6 @@ start cloning any necessary Cordova libraries (which may take a while). ## TO-DO - fix pluginstall for ios 2.0 -- interpolating proper app name and shit from config.xml - `grep` through this project for 'TODO' - blackberry support - moar tests http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/spec/config_parser.spec.js ---------------------------------------------------------------------- diff --git a/spec/config_parser.spec.js b/spec/config_parser.spec.js index ba39e0a..e26d170 100644 --- a/spec/config_parser.spec.js +++ b/spec/config_parser.spec.js @@ -26,6 +26,46 @@ describe('config parser', function () { expect(cfg.doc).toBeDefined(); }); + describe('package name / id', function() { + var cfg; + + beforeEach(function() { + cfg = new config_parser(xml); + }); + + it('should get the packagename', function() { + expect(cfg.packageName()).toEqual('io.cordova.hello-cordova'); + }); + it('should allow setting the packagename', function() { + cfg.packageName('this.is.bat.country'); + expect(cfg.packageName()).toEqual('this.is.bat.country'); + }); + it('should write to disk after setting the packagename', function() { + cfg.packageName('this.is.bat.country'); + expect(fs.readFileSync(xml, 'utf-8')).toMatch(/id="this\.is\.bat\.country"/); + }); + }); + + describe('app name', function() { + var cfg; + + beforeEach(function() { + cfg = new config_parser(xml); + }); + + it('should get the app name', function() { + expect(cfg.packageName()).toEqual('io.cordova.hello-cordova'); + }); + it('should allow setting the app name', function() { + cfg.name('this.is.bat.country'); + expect(cfg.name()).toEqual('this.is.bat.country'); + }); + it('should write to disk after setting the name', function() { + cfg.name('one toke over the line'); + expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<name>one toke over the line<\/name>/); + }); + }); + describe('platforms', function() { describe('ls command', function() { it('should return an empty array if there are no platforms specified in the document', function() { @@ -36,7 +76,7 @@ describe('config parser', function () { 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'; + p.attrib.name = 'android'; doc.find('platforms').append(p); fs.writeFileSync(xml, doc.write(), 'utf-8'); @@ -52,7 +92,7 @@ describe('config parser', function () { 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'); + expect(doc.find('platforms').getchildren()[0].attrib.name).toEqual('android'); }); it('should ignore existing platforms', function() { var cfg = new config_parser(xml); http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/spec/create.spec.js ---------------------------------------------------------------------- diff --git a/spec/create.spec.js b/spec/create.spec.js index 173c63a..cbe8951 100644 --- a/spec/create.spec.js +++ b/spec/create.spec.js @@ -23,13 +23,35 @@ describe('create command', function () { }); 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); + expect(fs.lstatSync(path.join(tempDir, '.cordova')).isFile()).toBe(true); }); - it('should warn if the directory is already a cordova project', function() { + it('should throw if the directory is already a cordova project', function() { mkdirp(path.join(tempDir, '.cordova')); expect(function() { cordova.create(tempDir); }).toThrow(); }); + it('should create a cordova project in the specified dir with specified name if provided', function() { + cordova.create(tempDir, "balls"); + + expect(fs.lstatSync(path.join(tempDir, '.cordova')).isFile()).toBe(true); + + expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/); + + expect(JSON.parse(fs.readFileSync(path.join(tempDir, '.cordova')).toString('utf8')).name).toEqual("balls"); + }); + it('should create a cordova project in the specified dir with specified name and id if provided', function() { + cordova.create(tempDir, "birdy.nam.nam", "numnum"); + + expect(fs.lstatSync(path.join(tempDir, '.cordova')).isFile()).toBe(true); + + var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8'); + expect(config).toMatch(/<name>numnum<\/name>/); + expect(config).toMatch(/id="birdy\.nam\.nam"/); + + var metadata = JSON.parse(fs.readFileSync(path.join(tempDir, '.cordova')).toString('utf8')); + expect(metadata.name).toEqual("numnum"); + expect(metadata.id).toEqual("birdy.nam.nam"); + }); }); http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/src/build.js ---------------------------------------------------------------------- diff --git a/src/build.js b/src/build.js index fc9453e..acfeecb 100644 --- a/src/build.js +++ b/src/build.js @@ -1,12 +1,12 @@ -var cordova_util = require('./util'), - path = require('path'), - exec = require('child_process').exec, - wrench = require('wrench'), - rmrf = wrench.rmdirSyncRecursive, - cpr = wrench.copyDirSyncRecursive, +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'); + fs = require('fs'), + util = require('util'); module.exports = function build () { var projectRoot = cordova_util.isCordova(process.cwd()); @@ -18,34 +18,39 @@ module.exports = function build () { var xml = path.join(projectRoot, 'www', 'config.xml'); var assets = path.join(projectRoot, 'www'); var cfg = new config_parser(xml); + var name = cfg.name(); + var id = cfg.packageName(); var platforms = cfg.ls_platforms(); // Iterate over each added platform platforms.map(function(platform) { - // Copy in latest www assets. - var assetsPath; + // Figure out paths based on platform + var assetsPath, js; switch (platform) { - // First clean out the existing www. case 'android': assetsPath = path.join(projectRoot, 'platforms', 'android', 'assets', 'www'); + js = path.join(__dirname, '..', 'lib', 'android', 'framework', 'assets', 'js', 'cordova.android.js'); + + // TODO: drop activity name and package name into + // appropriate places in android break; case 'ios': assetsPath = path.join(projectRoot, 'platforms', 'ios', 'www'); + js = path.join(__dirname, '..', 'lib', 'ios', 'CordovaLib', 'javascript', 'cordova.ios.js'); + + // TODO: drop app name and id into + // appropriate places in ios break; } + + // Clean out the existing www. rmrf(assetsPath); + + // Copy app assets into native package 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 http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/src/config_parser.js ---------------------------------------------------------------------- diff --git a/src/config_parser.js b/src/config_parser.js index 979e71f..ec21814 100644 --- a/src/config_parser.js +++ b/src/config_parser.js @@ -10,16 +10,16 @@ function config_parser(xmlPath) { config_parser.prototype = { ls_platforms:function() { return this.doc.find('platforms').getchildren().map(function(p) { - return p.attrib['name']; + 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; + p.attrib.name = platform; this.doc.find('platforms').append(p); - fs.writeFileSync(this.path, this.doc.write(), 'utf-8'); + this.update(); } }, remove_platform:function(platform) { @@ -28,14 +28,23 @@ config_parser.prototype = { 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'); + this.update(); } }, - packageName:function() { - return this.doc.getroot().attrib.id; + packageName:function(id) { + if (id) { + this.doc.getroot().attrib.id = id; + this.update(); + } else return this.doc.getroot().attrib.id; }, - name:function() { - return this.doc.find('name').text; + name:function(name) { + if (name) { + this.doc.find('name').text = name; + this.update(); + } else return this.doc.find('name').text; + }, + update:function() { + fs.writeFileSync(this.path, this.doc.write(), 'utf-8'); } }; http://git-wip-us.apache.org/repos/asf/incubator-cordova-labs/blob/a40a01c3/src/create.js ---------------------------------------------------------------------- diff --git a/src/create.js b/src/create.js index 98dd0cf..d2a7892 100644 --- a/src/create.js +++ b/src/create.js @@ -1,31 +1,57 @@ -var wrench = require('wrench'), - path = require('path'), - fs = require('fs'), - help = require('./help'), - mkdirp = wrench.mkdirSyncRecursive, - cpr = wrench.copyDirSyncRecursive; - -module.exports = function create (dir) { +var wrench = require('wrench'), + path = require('path'), + fs = require('fs'), + help = require('./help'), + config_parser = require('./config_parser'), + mkdirp = wrench.mkdirSyncRecursive, + cpr = wrench.copyDirSyncRecursive; + +var DEFAULT_NAME = "Hello Cordova", + DEFAULT_ID = "io.cordova.hello-cordova"; + +/** + * Usage: + * create(dir) - creates in the specified directory + * create(dir, name) - as above, but with specified name + * create(dir, id, name) - you get the gist + **/ +module.exports = function create (dir, id, name) { if (dir === undefined) { return help(); } - if (dir && (dir[0] == '~' || dir[0] == '/')) { - } else { + // Massage parameters a bit. + if (id && name === undefined) { + name = id; + id = undefined; + } + id = id || DEFAULT_ID; + name = name || DEFAULT_NAME; + + if (!(dir && (dir[0] == '~' || dir[0] == '/'))) { dir = dir ? path.join(process.cwd(), dir) : process.cwd(); } + var dotCordova = path.join(dir, '.cordova'); + // Check for existing cordova project - if (fs.existsSync(path.join(dir, '.cordova'))) { + if (fs.existsSync(dotCordova)) { throw 'Cordova project already exists at ' + dir + ', aborting.'; } // Create basic project structure. - mkdirp(path.join(dir, '.cordova')); mkdirp(path.join(dir, 'platforms')); mkdirp(path.join(dir, 'plugins')); mkdirp(path.join(dir, 'www')); + fs.writeFileSync(dotCordova, 'do or do not. there is no try.'); + // Copy in base template cpr(path.join(__dirname, '..', 'templates', 'www'), path.join(dir, 'www')); + + // Write out id and name to config.xml + var configPath = path.join(dir, 'www', 'config.xml'); + var config = new config_parser(configPath); + config.packageName(id); + config.name(name); };