You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mw...@apache.org on 2013/05/15 22:36:10 UTC

[31/37] Add WP7 and WP8 support to cordova-cli.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp8/wp8.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp8/wp8.spec.js b/spec/platform-script/wp8/wp8.spec.js
new file mode 100644
index 0000000..998094c
--- /dev/null
+++ b/spec/platform-script/wp8/wp8.spec.js
@@ -0,0 +1,99 @@
+var cordova = require('../../../cordova'),
+    shell = require('shelljs'),
+    path = require('path'),
+    fs = require('fs'),
+    wp8_parser = require('../../../src/metadata/wp8_parser'),
+    tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+    fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+    cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+    afterEach(function() {
+        process.chdir(cwd);
+    });
+
+    describe('\'platform add wp8\'', function() {
+        var sh, cr;
+        var fake_reqs_check = function() {
+            expect(cr.mostRecentCall.args).toBeDefined();
+            cr.mostRecentCall.args[0](false);
+        };
+        var fake_create = function(a_path) {
+            shell.mkdir('-p', a_path);
+            fs.writeFileSync(path.join(a_path, 'wp7Project.csproj'), 'hi', 'utf-8');
+            fs.writeFileSync(path.join(a_path, 'wp7Project.sln'), 'hi', 'utf-8');
+            sh.mostRecentCall.args[2](0, '');
+        };
+        beforeEach(function() {
+            sh = spyOn(shell, 'exec');
+            cr = spyOn(wp8_parser, 'check_requirements');
+            shell.rm('-rf', tempDir);
+            cordova.create(tempDir);
+            process.chdir(tempDir);
+        });
+        afterEach(function() {
+            process.chdir(cwd);
+        });
+        it('should shell out to wp8 /bin/create', function() {
+            cordova.platform('add', 'wp8');
+            fake_reqs_check();
+            var shell_cmd = sh.mostRecentCall.args[0];
+            var create_cmd = path.join('wp8', 'bin', 'create');
+            expect(shell_cmd).toContain(create_cmd);
+        });
+        it('should call wp8_parser\'s update_project', function() {
+            spyOn(wp8_parser.prototype, 'update_project');
+            cordova.platform('add', 'wp8');
+            fake_reqs_check();
+            fake_create(path.join(tempDir, 'platforms', 'wp8'));
+            expect(wp8_parser.prototype.update_project).toHaveBeenCalled();
+        });
+    });
+
+    describe('\'emulate wp8\'', function() {
+        beforeEach(function() {
+            process.chdir(tempDir);
+        });
+        afterEach(function() {
+            process.chdir(cwd);
+        });
+        shell.rm('-rf', tempDir);
+        cordova.create(tempDir);
+        shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp8'), path.join(tempDir, 'platforms'));
+        it('should shell out to run command on wp8', function() {
+            var proj_spy = spyOn(wp8_parser.prototype, 'update_project');
+            var s = spyOn(require('shelljs'), 'exec');
+            cordova.emulate('wp8');
+            proj_spy.mostRecentCall.args[1](); // update_project fake
+            expect(s).toHaveBeenCalled();
+            var emulate_cmd = path.join('wp8', 'cordova', 'run');
+            expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
+        });
+        it('should call wp8_parser\'s update_project', function() {
+            spyOn(require('shelljs'), 'exec');
+            spyOn(wp8_parser.prototype, 'update_project');
+            cordova.emulate('wp8');
+            expect(wp8_parser.prototype.update_project).toHaveBeenCalled();
+        });
+    });
+
+    describe('\'compile wp8\'', function() {
+        beforeEach(function() {
+            process.chdir(tempDir);
+        });
+        afterEach(function() {
+            process.chdir(cwd);
+        });
+        shell.rm('-rf', tempDir);
+        cordova.create(tempDir);
+        shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp8'), path.join(tempDir, 'platforms'));
+        it('should shell out to build command', function() {
+            var build_cmd = path.join('wp8', 'cordova', 'build');
+            var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+            cordova.compile('wp8');
+            expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+        });
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp8/wp8_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp8/wp8_parser.spec.js b/spec/platform-script/wp8/wp8_parser.spec.js
new file mode 100644
index 0000000..5669e02
--- /dev/null
+++ b/spec/platform-script/wp8/wp8_parser.spec.js
@@ -0,0 +1,249 @@
+
+/**
+    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 wp8_parser = require('../../../src/metadata/wp8_parser'),
+    config_parser = require('../../../src/config_parser'),
+    util = require('../../../src/util'),
+    path = require('path'),
+    shell = require('shelljs'),
+    fs = require('fs'),
+    os = require('os'),
+    et = require('elementtree'),
+    cordova = require('../../../cordova'),
+    projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects'),
+    wp8_path = path.join(projects_path, 'native', 'wp8_fixture'),
+    project_path = path.join(projects_path, 'cordova'),
+    wp8_project_path = path.join(project_path, 'platforms', 'wp8');
+
+var www_config = util.projectConfig(project_path);
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('wp8 project parser', function() {
+    it('should throw an exception with a path that is not a native wp8 project', function() {
+        expect(function() {
+            var project = new wp8_parser(process.cwd());
+        }).toThrow();
+    });
+    it('should accept a proper native wp8 project path as construction parameter', function() {
+        expect(function() {
+            var project = new wp8_parser(wp8_path);
+            expect(project).toBeDefined();
+        }).not.toThrow();
+    });
+
+    describe('update_from_config method', function() {
+        var config;
+        var project = new wp8_parser(wp8_path);
+
+        var manifest_path  = path.join(wp8_path, 'Properties', 'WMAppManifest.xml');
+        var csproj_path    = project.csproj_path;
+        var sln_path       = project.sln_path;
+        var app_xaml_path  = path.join(wp8_path, 'App.xaml');
+        var app_cs_path    = path.join(wp8_path, 'App.xaml.cs');
+        var main_xaml_path = path.join(wp8_path, 'MainPage.xaml');
+        var main_cs_path   = path.join(wp8_path, 'MainPage.xaml.cs');
+
+
+        var original_manifest  = fs.readFileSync(manifest_path, 'utf-8');
+        var original_csproj    = fs.readFileSync(csproj_path, 'utf-8');
+        var original_sln       = fs.readFileSync(sln_path, 'utf-8');
+        var original_app_xaml  = fs.readFileSync(app_xaml_path, 'utf-8');
+        var original_app_cs    = fs.readFileSync(app_cs_path, 'utf-8');
+        var original_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+        var original_main_cs   = fs.readFileSync(main_cs_path, 'utf-8');
+
+        beforeEach(function() {
+            project = new wp8_parser(wp8_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+            fs.writeFileSync(manifest_path, original_manifest, 'utf-8');
+            // csproj file changes name if app changes name
+            fs.unlinkSync(project.csproj_path);
+            fs.unlinkSync(project.sln_path);
+            fs.writeFileSync(csproj_path, original_csproj, 'utf-8');
+            fs.writeFileSync(sln_path, original_sln, 'utf-8');
+            fs.writeFileSync(app_xaml_path, original_app_xaml, 'utf-8');
+            fs.writeFileSync(app_cs_path, original_app_cs, 'utf-8');
+            fs.writeFileSync(main_xaml_path, original_main_xaml, 'utf-8');
+            fs.writeFileSync(main_cs_path, original_main_cs, 'utf-8');
+        });
+        it('should throw an exception if a non config_parser object is passed into it', function() {
+            expect(function() {
+                project.update_from_config({});
+            }).toThrow();
+        });
+        it('should update the application name properly', function() {
+            var test_name = 'bond. james bond.';
+            config.name(test_name);
+            project.update_from_config(config);
+            var raw_manifest = fs.readFileSync(manifest_path, 'utf-8');
+            //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851)
+            var cleaned_manifest = raw_manifest.replace('\ufeff', '');
+            var manifest = new et.ElementTree(et.XML(cleaned_manifest));
+            var app_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+            expect(app_name).toBe(test_name);
+
+            //check for the proper name of csproj and solution files
+            test_name = test_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+            expect(project.csproj_path).toContain(test_name);
+            expect(project.sln_path).toContain(test_name);
+        });
+        it('should update the application package name properly', function() {
+            var test_package = 'ca.filmaj.dewd'
+            config.packageName(test_package);
+            project.update_from_config(config);
+
+            // check csproj file (use regex instead of elementtree?)
+            var raw_csproj = fs.readFileSync(project.csproj_path, 'utf-8');
+            var cleaned_csproj = raw_csproj.replace(/^\uFEFF/i, '');
+            var csproj = new et.ElementTree(et.XML(cleaned_csproj));
+            expect(csproj.find('.//RootNamespace').text).toEqual(test_package);
+            expect(csproj.find('.//AssemblyName').text).toEqual(test_package);
+            expect(csproj.find('.//XapFilename').text).toEqual(test_package + '.xap');
+            expect(csproj.find('.//SilverlightAppEntry').text).toEqual(test_package + '.App');
+
+            // check app.xaml (use regex instead of elementtree?)
+            var new_app_xaml = fs.readFileSync(app_xaml_path, 'utf-8');
+            var cleaned_app_xaml = new_app_xaml.replace(/^\uFEFF/i, '');
+            var app_xaml = new et.ElementTree(et.XML(cleaned_app_xaml));
+            expect(app_xaml._root.attrib['x:Class']).toEqual(test_package + '.App');
+
+            // check app.xaml.cs
+            var new_app_cs = fs.readFileSync(app_cs_path, 'utf-8');
+            expect(new_app_cs).toContain('namespace ' + test_package);
+
+            // check MainPage.xaml (use regex instead of elementtree?)
+            var new_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+            var cleaned_main_xaml = new_main_xaml.replace(/^\uFEFF/i, '');
+            var main_xaml = new et.ElementTree(et.XML(cleaned_main_xaml));
+            expect(main_xaml._root.attrib['x:Class']).toEqual(test_package + '.MainPage');
+
+            //check MainPage.xaml.cs
+            var new_main_cs = fs.readFileSync(main_cs_path, 'utf-8');
+            expect(new_main_cs).toContain('namespace ' + test_package);
+        });
+        xdescribe('preferences', function() {
+            it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
+                /*config.preference.add({name:'henrik',value:'sedin'});
+                project.update_from_config(config);
+
+                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+                var ps = native_config.findall('preference');
+                expect(ps.length).toEqual(7);
+                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+                expect(ps[0].attrib.value).toEqual('true');
+                expect(ps[6].attrib.name).toEqual('henrik');
+                expect(ps[6].attrib.value).toEqual('sedin');*/
+
+                // TODO : figure out if this is supported
+                //expect(true).toBe(false);
+            });
+            it('should override a default project preference if applicable', function() {
+                /*config.preference.add({name:'useBrowserHistory',value:'false'});
+                project.update_from_config(config);
+
+                var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+                var ps = native_config.findall('preference');
+                expect(ps.length).toEqual(6);
+                expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+                expect(ps[0].attrib.value).toEqual('false');*/
+
+                // TODO : figure out if this is supported
+                //expect(true).toBe(false);
+            });
+        });
+    });
+
+    describe('cross-platform project level methods', function() {
+        var parser, config;
+
+        beforeEach(function() {
+            parser = new wp8_parser(wp8_project_path);
+            config = new config_parser(www_config);
+        });
+        afterEach(function() {
+        });
+        describe('update_www method', function() {
+            it('should update all www assets', function() {
+                var newFile = path.join(util.projectWww(project_path), 'somescript.js');
+                this.after(function() {
+                    shell.rm('-f', newFile);
+                });
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+                parser.update_www();
+                expect(fs.existsSync(path.join(wp8_project_path, 'www', 'somescript.js'))).toBe(true);
+            });
+            it('should write out windows-phone js to cordova.js', function() {
+                parser.update_www();
+                var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'VERSION'), 'utf-8');
+                var wp8_version = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+                expect(fs.readFileSync(path.join(wp8_project_path, 'www', 'cordova.js'),'utf-8')).toEqual(fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'templates', 'standalone', 'www', 'cordova-' + wp8_version + '.js'), 'utf-8'));
+            });
+        });
+
+        xdescribe('update_overrides method',function() {
+            /*var mergesPath = path.join(util.appDir(project_path), 'merges', 'android');
+            var newFile = path.join(mergesPath, 'merge.js');
+            beforeEach(function() {
+                shell.mkdir('-p', mergesPath);
+                fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+            });
+            afterEach(function() {
+                shell.rm('-rf', mergesPath);
+            });
+            it('should copy a new file from merges into www', function() {
+                parser.update_overrides();
+                expect(fs.existsSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+            });
+
+            it('should copy a file from merges over a file in www', function() {
+                var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
+                fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+                this.after(function() {
+                    shell.rm('-rf', newFileWWW);
+                });
+                parser.update_overrides();
+                expect(fs.existsSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+                expect(fs.readFileSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+            });*/
+
+            // TODO : figure out if this is supported
+            //expect(true).toBe(false);
+        });
+
+        describe('update_project method', function() {
+            it('should invoke update_www', function() {
+                var spyWww = spyOn(parser, 'update_www');
+                parser.update_project(config);
+                expect(spyWww).toHaveBeenCalled();
+            });
+            it('should invoke update_from_config', function() {
+                var spyConfig = spyOn(parser, 'update_from_config');
+                parser.update_project(config);
+                expect(spyConfig).toHaveBeenCalled();
+            });
+            it('should call out to util.deleteSvnFolders', function() {
+                var spy = spyOn(util, 'deleteSvnFolders');
+                parser.update_project(config);
+                expect(spy).toHaveBeenCalled();
+            });
+        });
+    });
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/compile.js
----------------------------------------------------------------------
diff --git a/src/compile.js b/src/compile.js
index 4efbd6b..c88c36e 100644
--- a/src/compile.js
+++ b/src/compile.js
@@ -19,14 +19,11 @@
 var cordova_util      = require('./util'),
     path              = require('path'),
     config_parser     = require('./config_parser'),
-    platform          = require('./platform'),
     fs                = require('fs'),
     shell             = require('shelljs'),
     et                = require('elementtree'),
     hooker            = require('./hooker'),
-    n                 = require('ncallbacks'),
-    prompt            = require('prompt'),
-    util              = require('util');
+    n                 = require('ncallbacks');
 
 
 function shell_out_to_debug(projectRoot, platform, callback) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/create.js
----------------------------------------------------------------------
diff --git a/src/create.js b/src/create.js
index 0f7c8a6..f1d1792 100644
--- a/src/create.js
+++ b/src/create.js
@@ -45,7 +45,7 @@ module.exports = function create (dir, id, name) {
     id = id || DEFAULT_ID;
     name = name || DEFAULT_NAME;
 
-    if (!(dir && (dir[0] == '~' || dir[0] == '/'))) {
+    if (!(dir && (dir[0] == '~' || dir[0] == '/' || dir[0] + dir[1] == 'C:'))) {
         dir = dir ? path.join(process.cwd(), dir) : process.cwd();
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/emulate.js
----------------------------------------------------------------------
diff --git a/src/emulate.js b/src/emulate.js
index 7acb441..b396eeb 100644
--- a/src/emulate.js
+++ b/src/emulate.js
@@ -23,6 +23,8 @@ var cordova_util      = require('./util'),
     android_parser    = require('./metadata/android_parser'),
     ios_parser        = require('./metadata/ios_parser'),
     blackberry_parser = require('./metadata/blackberry_parser'),
+    wp7_parser      = require('./metadata/wp7_parser'),
+    wp8_parser      = require('./metadata/wp8_parser'),
     platform          = require('./platform'),
     fs                = require('fs'),
     ls                = fs.readdirSync,
@@ -33,16 +35,16 @@ var cordova_util      = require('./util'),
 var parsers = {
     "android":android_parser,
     "ios":ios_parser,
-    "blackberry":blackberry_parser
+    "blackberry":blackberry_parser,
+    "wp7":wp7_parser,
+    "wp8":wp8_parser
 };
 
 function shell_out_to_emulate(root, platform, callback) {
-    var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'emulate') + '"';
+    var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'run') + '"';
     // TODO: PLATFORM LIBRARY INCONSISTENCY 
     if (platform == 'blackberry') {
         cmd = 'ant -f "' + path.join(root, 'platforms', platform, 'build.xml') + '" qnx load-simulator';
-    } else if (platform.indexOf('android') > -1) {
-        cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'run') + '"';
     }
     shell.exec(cmd, {silent:true, async:true}, function(code, output) {
         if (code > 0) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/metadata/wp7_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp7_parser.js b/src/metadata/wp7_parser.js
new file mode 100644
index 0000000..289eca0
--- /dev/null
+++ b/src/metadata/wp7_parser.js
@@ -0,0 +1,160 @@
+
+/**
+    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 fs            = require('fs'),
+    path          = require('path'),
+    et            = require('elementtree'),
+    util          = require('../util'),
+    shell         = require('shelljs'),
+    config_parser = require('../config_parser');
+
+module.exports = function wp7_parser(project) {
+    try {
+        // TODO : Check that it's not a wp7 project?
+        var csproj_file   = fs.readdirSync(project).filter(function(e) { return e.match(/\.csproj$/i); })[0];
+        if (!csproj_file) throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.');
+        this.wp7_proj_dir = project;
+        this.csproj_path  = path.join(this.wp7_proj_dir, csproj_file);
+        this.sln_path     = path.join(this.wp7_proj_dir, csproj_file.replace(/\.csproj/, '.sln'));
+    } catch(e) {
+        throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.' + e);
+    }
+    this.manifest_path  = path.join(this.wp7_proj_dir, 'Properties', 'WMAppManifest.xml');
+};
+
+module.exports.check_requirements = function(callback) {
+    shell.exec(path.join(util.libDirectory, 'cordova-wp7', 'bin', 'check_reqs'), {silent:true, async:true}, function(code, output) {
+        if (code != 0) {
+            callback(output);
+        } else {
+                callback(false);
+        }
+    });
+};
+
+module.exports.prototype = {
+    update_from_config:function(config) {
+        //check config parser
+        if (config instanceof config_parser) {
+        } else throw new Error('update_from_config requires a config_parser object');
+
+        // Update app name by editing app title in Properties\WMAppManifest.xml
+        var name = config.name();
+        var man = fs.readFileSync(this.manifest_path, 'utf-8');
+        //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851/)
+        var cleanedMan = man.replace('\ufeff', '');
+        var manifest = new et.ElementTree(et.XML(cleanedMan));
+        var prev_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+        if(prev_name != name)
+        {
+            //console.log("Updating app name from " + prev_name + " to " + name);
+            manifest.find('.//App').attrib.Title = name;
+            manifest.find('.//Title').text = name;
+            fs.writeFileSync(this.manifest_path, manifest.write({indent: 4}), 'utf-8');
+
+            //update name of sln and csproj.
+            name = name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+            prev_name = prev_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); 
+            // TODO: might return .sln.user? (generated file)
+            var sln_name = fs.readdirSync(this.wp7_proj_dir).filter(function(e) { return e.match(/\.sln$/i); })[0];
+            var sln_path = path.join(this.wp7_proj_dir, sln_name);
+            var sln_file = fs.readFileSync(sln_path, 'utf-8');
+            var name_regex = new RegExp(prev_name, "g");
+            fs.writeFileSync(sln_path, sln_file.replace(name_regex, name), 'utf-8');
+            shell.mv('-f', this.csproj_path, path.join(this.wp7_proj_dir, name + '.csproj'));
+            this.csproj_path = path.join(this.wp7_proj_dir, name + '.csproj');
+            shell.mv('-f', sln_path, path.join(this.wp7_proj_dir, name + '.sln'));
+            this.sln_path    = path.join(this.wp7_proj_dir, name + '.sln');
+        }
+
+        // Update package name by changing:
+        /*  - CordovaAppProj.csproj
+         *  - MainPage.xaml
+         *  - MainPage.xaml.cs
+         *  - App.xaml
+         *  - App.xaml.cs
+         */
+         var pkg = config.packageName();
+         var raw = fs.readFileSync(this.csproj_path, 'utf-8');
+         var cleanedPage = raw.replace(/^\uFEFF/i, '');
+         var csproj = new et.ElementTree(et.XML(cleanedPage));
+         prev_name = csproj.find('.//RootNamespace').text;
+         if(prev_name != pkg)
+         {
+            //console.log("Updating package name from " + prev_name + " to " + pkg);
+            //CordovaAppProj.csproj
+            csproj.find('.//RootNamespace').text = pkg;
+            csproj.find('.//AssemblyName').text = pkg;
+            csproj.find('.//XapFilename').text = pkg + '.xap';
+            csproj.find('.//SilverlightAppEntry').text = pkg + '.App';
+            fs.writeFileSync(this.csproj_path, csproj.write({indent: 4}), 'utf-8');
+            //MainPage.xaml
+            raw = fs.readFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml'), 'utf-8');
+            // Remove potential UTF Byte Order Mark
+            cleanedPage = raw.replace(/^\uFEFF/i, '');
+            var mainPageXAML = new et.ElementTree(et.XML(cleanedPage));
+            mainPageXAML._root.attrib['x:Class'] = pkg + '.MainPage';
+            fs.writeFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml'), mainPageXAML.write({indent: 4}), 'utf-8');
+            //MainPage.xaml.cs
+            var mainPageCS = fs.readFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml.cs'), 'utf-8');
+            var namespaceRegEx = new RegExp('namespace ' + prev_name);
+            fs.writeFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml.cs'), mainPageCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+            //App.xaml
+            raw = fs.readFileSync(path.join(this.wp7_proj_dir, 'App.xaml'), 'utf-8');
+            cleanedPage = raw.replace(/^\uFEFF/i, '');
+            var appXAML = new et.ElementTree(et.XML(cleanedPage));
+            appXAML._root.attrib['x:Class'] = pkg + '.App';
+            fs.writeFileSync(path.join(this.wp7_proj_dir, 'App.xaml'), appXAML.write({indent: 4}), 'utf-8');
+            //App.xaml.cs
+            var appCS = fs.readFileSync(path.join(this.wp7_proj_dir, 'App.xaml.cs'), 'utf-8');
+            fs.writeFileSync(path.join(this.wp7_proj_dir, 'App.xaml.cs'), appCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+         }
+    },
+    // Returns the platform-specific www directory.
+    www_dir:function() {
+        return path.join(this.wp7_proj_dir, 'www');
+    },
+    // copyies the app www folder into the wp7 project's www folder
+    update_www:function() {
+        var project_www = path.join(this.wp7_proj_dir, '..', '..', util.projectWww());
+        // remove stock platform assets
+        shell.rm('-rf', this.www_dir());
+        // copy over all app www assets
+        shell.cp('-rf', project_www, this.wp7_proj_dir);
+
+        // copy over wp7 lib's cordova.js
+        var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp7', 'VERSION'), 'utf-8')
+        var VERSION = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp7', 'templates', 'standalone', 'www', 'cordova-' + VERSION + '.js');
+        fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
+    },
+    // calls the nessesary functions to update the wp7 project 
+    update_project:function(cfg, callback) {
+        //console.log("Updating wp7 project...");
+
+        this.update_from_config(cfg);
+        this.update_www();
+        util.deleteSvnFolders(this.www_dir());
+
+        //console.log("Done updating.");
+
+        if (callback) callback();
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/metadata/wp8_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp8_parser.js b/src/metadata/wp8_parser.js
new file mode 100644
index 0000000..5ecb6dc
--- /dev/null
+++ b/src/metadata/wp8_parser.js
@@ -0,0 +1,158 @@
+
+/**
+    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 fs            = require('fs'),
+    path          = require('path'),
+    et            = require('elementtree'),
+    util          = require('../util'),
+    shell         = require('shelljs'),
+    config_parser = require('../config_parser');
+
+module.exports = function wp8_parser(project) {
+    try {
+        // TODO : Check that it's not a wp7 project?
+        var csproj_file   = fs.readdirSync(project).filter(function(e) { return e.match(/\.csproj$/i); })[0];
+        if (!csproj_file) throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.');
+        this.wp8_proj_dir = project;
+        this.csproj_path  = path.join(this.wp8_proj_dir, csproj_file);
+        this.sln_path     = path.join(this.wp8_proj_dir, csproj_file.replace(/\.csproj/, '.sln'));
+    } catch(e) {
+        throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.' + e);
+    }
+    this.manifest_path  = path.join(this.wp8_proj_dir, 'Properties', 'WMAppManifest.xml');
+};
+
+module.exports.check_requirements = function(callback) {
+    shell.exec(path.join(util.libDirectory, 'cordova-wp8', 'bin', 'check_reqs'), {silent:true, async:true}, function(code, output) {
+        if (code != 0) {
+            callback(output);
+        } else {
+                callback(false);
+        }
+    });
+};
+
+module.exports.prototype = {
+    update_from_config:function(config) {
+        //check config parser
+        if (config instanceof config_parser) {
+        } else throw new Error('update_from_config requires a config_parser object');
+
+        // Update app name by editing app title in Properties\WMAppManifest.xml
+        var name = config.name();
+        var man = fs.readFileSync(this.manifest_path, 'utf-8');
+        //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851/)
+        var cleanedMan = man.replace('\ufeff', '');
+        var manifest = new et.ElementTree(et.XML(cleanedMan));
+        var prev_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+        if(prev_name != name)
+        {
+            //console.log("Updating app name from " + prev_name + " to " + name);
+            manifest.find('.//App').attrib.Title = name;
+            manifest.find('.//Title').text = name;
+            fs.writeFileSync(this.manifest_path, manifest.write({indent: 4}), 'utf-8');
+
+            //update name of sln and csproj.
+            name = name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+            prev_name = prev_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); 
+            var sln_path = path.join(this.wp8_proj_dir, prev_name + '.sln');
+            var sln_file = fs.readFileSync(sln_path, 'utf-8');
+            var name_regex = new RegExp(prev_name, "g");
+            fs.writeFileSync(sln_path, sln_file.replace(name_regex, name), 'utf-8');
+            shell.mv('-f', this.csproj_path, path.join(this.wp8_proj_dir, name + '.csproj'));
+            this.csproj_path = path.join(this.wp8_proj_dir, name + '.csproj');
+            shell.mv('-f', sln_path, path.join(this.wp8_proj_dir, name + '.sln'));
+            this.sln_path    = path.join(this.wp8_proj_dir, name + '.sln');
+        }
+
+        // Update package name by changing:
+        /*  - CordovaAppProj.csproj
+         *  - MainPage.xaml
+         *  - MainPage.xaml.cs
+         *  - App.xaml
+         *  - App.xaml.cs
+         */
+         var pkg = config.packageName();
+         var raw = fs.readFileSync(this.csproj_path, 'utf-8');
+         var cleanedPage = raw.replace(/^\uFEFF/i, '');
+         var csproj = new et.ElementTree(et.XML(cleanedPage));
+         prev_name = csproj.find('.//RootNamespace').text;
+         if(prev_name != pkg)
+         {
+            //console.log("Updating package name from " + prev_name + " to " + pkg);
+            //CordovaAppProj.csproj
+            csproj.find('.//RootNamespace').text = pkg;
+            csproj.find('.//AssemblyName').text = pkg;
+            csproj.find('.//XapFilename').text = pkg + '.xap';
+            csproj.find('.//SilverlightAppEntry').text = pkg + '.App';
+            fs.writeFileSync(this.csproj_path, csproj.write({indent: 4}), 'utf-8');
+            //MainPage.xaml
+            raw = fs.readFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml'), 'utf-8');
+            // Remove potential UTF Byte Order Mark
+            cleanedPage = raw.replace(/^\uFEFF/i, '');
+            var mainPageXAML = new et.ElementTree(et.XML(cleanedPage));
+            mainPageXAML._root.attrib['x:Class'] = pkg + '.MainPage';
+            fs.writeFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml'), mainPageXAML.write({indent: 4}), 'utf-8');
+            //MainPage.xaml.cs
+            var mainPageCS = fs.readFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml.cs'), 'utf-8');
+            var namespaceRegEx = new RegExp('namespace ' + prev_name);
+            fs.writeFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml.cs'), mainPageCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+            //App.xaml
+            raw = fs.readFileSync(path.join(this.wp8_proj_dir, 'App.xaml'), 'utf-8');
+            cleanedPage = raw.replace(/^\uFEFF/i, '');
+            var appXAML = new et.ElementTree(et.XML(cleanedPage));
+            appXAML._root.attrib['x:Class'] = pkg + '.App';
+            fs.writeFileSync(path.join(this.wp8_proj_dir, 'App.xaml'), appXAML.write({indent: 4}), 'utf-8');
+            //App.xaml.cs
+            var appCS = fs.readFileSync(path.join(this.wp8_proj_dir, 'App.xaml.cs'), 'utf-8');
+            fs.writeFileSync(path.join(this.wp8_proj_dir, 'App.xaml.cs'), appCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+         }
+    },
+    // Returns the platform-specific www directory.
+    www_dir:function() {
+        return path.join(this.wp8_proj_dir, 'www');
+    },
+    // copyies the app www folder into the wp8 project's www folder
+    update_www:function() {
+        var project_www = path.join(this.wp8_proj_dir, '..', '..', util.projectWww());
+        // remove stock platform assets
+        shell.rm('-rf', this.www_dir());
+        // copy over all app www assets
+        shell.cp('-rf', project_www, this.wp8_proj_dir);
+
+        // copy over wp8 lib's cordova.js
+        var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'VERSION'), 'utf-8')
+        var VERSION = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+        var cordovajs_path = path.join(util.libDirectory, 'cordova-wp8', 'templates', 'standalone', 'www', 'cordova-' + VERSION + '.js');
+        fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
+    },
+    // calls the nessesary functions to update the wp8 project 
+    update_project:function(cfg, callback) {
+        //console.log("Updating wp8 project...");
+
+        this.update_from_config(cfg);
+        this.update_www();
+        util.deleteSvnFolders(this.www_dir());
+
+        //console.log("Done updating.");
+
+        if (callback) callback();
+    }
+};
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 00f2157..15285fb 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -26,12 +26,16 @@ var config_parser     = require('./config_parser'),
     android_parser    = require('./metadata/android_parser'),
     ios_parser        = require('./metadata/ios_parser'),
     blackberry_parser = require('./metadata/blackberry_parser'),
+    wp7_parser      = require('./metadata/wp7_parser'),
+    wp8_parser      = require('./metadata/wp8_parser'),
     shell             = require('shelljs');
 
 var parsers = {
     "android":android_parser,
     "ios":ios_parser,
-    "blackberry":blackberry_parser
+    "blackberry":blackberry_parser,
+    "wp7":wp7_parser,
+    "wp8":wp8_parser
 };
 
 module.exports = function platform(command, targets, callback) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 8997f97..b6d9911 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -108,6 +108,7 @@ module.exports = function plugin(command, targets, callback) {
                 intersection.forEach(function(platform) {
                     var cmd = util.format('%s --platform %s --project "%s" --plugin "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
                     var plugin_cli = shell.exec(cmd, {silent:true});
+                    if(!plugin_cli) throw new Error('Plugman command failed to execute for ' + platform + '.');
                     if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + '. ' + plugin_cli.output);
                 });
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/plugin_loader.js
----------------------------------------------------------------------
diff --git a/src/plugin_loader.js b/src/plugin_loader.js
index 3798e2f..b4730b4 100644
--- a/src/plugin_loader.js
+++ b/src/plugin_loader.js
@@ -25,6 +25,8 @@ var path            = require('path'),
     android_parser  = require('./metadata/android_parser'),
     blackberry_parser= require('./metadata/blackberry_parser'),
     ios_parser      = require('./metadata/ios_parser'),
+    wp7_parser      = require('./metadata/wp7_parser'),
+    wp8_parser      = require('./metadata/wp8_parser'),
     exec            = require('child_process').exec,
     et              = require('elementtree');
 
@@ -88,6 +90,13 @@ module.exports = function plugin_loader(platform) {
         case 'blackberry':
             parser = new blackberry_parser(path.join(projectRoot, 'platforms', 'blackberry'));
             break;
+        case 'wp7':
+            parser = new wp7_parser(path.join(projectRoot, 'platforms', 'wp7'));
+            break;
+        case 'wp8':
+            parser = new wp8_parser(path.join(projectRoot, 'platforms', 'wp8'));
+            break;
+
     }
 
     plugins && plugins.forEach(function(plugin) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
index 7ebbb17..cd34533 100644
--- a/src/util.js
+++ b/src/util.js
@@ -76,5 +76,11 @@ module.exports = {
         }
 
         return plugins;
+    },
+    projectWww: function(projectDir) {
+        return path.join(projectDir, 'www');
+    },
+    projectConfig: function(projectDir) {
+        return path.join(projectDir, 'www', 'config.xml');
     }
 };