You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2013/10/17 00:53:00 UTC

[07/16] git commit: CB-5066: merged in windows 8 support into master from cordova-3.1.x

CB-5066: merged in windows 8 support into master from cordova-3.1.x


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/a6929d1c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/a6929d1c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/a6929d1c

Branch: refs/heads/master
Commit: a6929d1c2f658f2a401d3284c3d18980be19ca2e
Parents: 3b1724d
Author: purplecabbage <pu...@gmail.com>
Authored: Wed Sep 25 18:33:31 2013 -0700
Committer: Steven Gill <st...@gmail.com>
Committed: Tue Oct 15 14:28:44 2013 -0700

----------------------------------------------------------------------
 platforms.js                          |   5 +
 spec/metadata/windows8_parser.spec.js | 247 +++++++++++++++++++++++++++
 spec/platform.spec.js                 |  34 ++--
 src/metadata/windows8_parser.js       | 262 +++++++++++++++++++++++++++++
 src/platform.js                       |  11 +-
 5 files changed, 544 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a6929d1c/platforms.js
----------------------------------------------------------------------
diff --git a/platforms.js b/platforms.js
index 724b3b8..ba96eb8 100644
--- a/platforms.js
+++ b/platforms.js
@@ -51,6 +51,11 @@ module.exports = {
         parser: './src/metadata/firefoxos_parser',
         url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-firefoxos.git',
         version: '3.1.0'
+    },
+    'windows8':{
+        parser: './src/metadata/windows8_parser',
+        url    : 'https://git-wip-us.apache.org/repos/asf?p=cordova-windows.git',
+        version: '3.1.0'
     }
 };
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a6929d1c/spec/metadata/windows8_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/windows8_parser.spec.js b/spec/metadata/windows8_parser.spec.js
new file mode 100644
index 0000000..f58f35e
--- /dev/null
+++ b/spec/metadata/windows8_parser.spec.js
@@ -0,0 +1,247 @@
+/**
+    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 platforms = require('../../platforms'),
+    util = require('../../src/util'),
+    path = require('path'),
+    shell = require('shelljs'),
+    fs = require('fs'),
+    ET = require('elementtree'),
+    config = require('../../src/config'),
+    config_parser = require('../../src/config_parser'),
+    cordova = require('../../cordova');
+
+describe('windows8 project parser', function() {
+
+    var proj = '/some/path';
+    var exists, exec, custom, readdir, cfg_parser;
+    beforeEach(function() {
+        exists = spyOn(fs, 'existsSync').andReturn(true);
+        exec = spyOn(shell, 'exec').andCallFake(function(cmd, opts, cb) {
+            cb(0, '');
+        });
+        custom = spyOn(config, 'has_custom_path').andReturn(false);
+        readdir = spyOn(fs, 'readdirSync').andReturn(['test.jsproj']);
+        cfg_parser = spyOn(util, 'config_parser');
+    });
+
+    describe('constructions', function() {
+        it('should throw if provided directory does not contain a jsproj file', function() {
+            readdir.andReturn([]);
+            expect(function() {
+                new platforms.windows8.parser(proj);
+            }).toThrow('The provided path "' + proj + '" is not a Windows 8 project. Error: No .jsproj file.');
+        });
+        it('should create an instance with path, manifest properties', function() {
+            expect(function() {
+                var p = new platforms.windows8.parser(proj);
+                expect(p.windows8_proj_dir).toEqual(proj);
+                expect(p.manifest_path).toEqual(path.join(proj, 'Properties', 'WMAppManifest.xml'));
+            }).not.toThrow();
+        });
+    });
+
+    describe('check_requirements', function() {
+        it('should fire a callback if there is an error during shelling out', function(done) {
+            exec.andCallFake(function(cmd, opts, cb) {
+                cb(50, 'there was an errorz!');
+            });
+            platforms.windows8.parser.check_requirements(proj, function(err) {
+                expect(err).toContain('there was an errorz!');
+                done();
+            });
+        });
+        it('should check by calling check_reqs on the stock lib path if no custom path is defined', function(done) {
+            platforms.windows8.parser.check_requirements(proj, function(err) {
+                expect(err).toEqual(false);
+                expect(exec.mostRecentCall.args[0]).toContain(util.libDirectory);
+                expect(exec.mostRecentCall.args[0]).toMatch(/check_reqs"$/);
+                done();
+            });
+        });
+        it('should check by calling check_reqs on a custom path if it is so defined', function(done) {
+            var custom_path = path.join('some','custom','path','to','windows8','lib');
+            custom.andReturn(custom_path);
+            platforms.windows8.parser.check_requirements(proj, function(err) {
+                expect(err).toEqual(false);
+                expect(exec.mostRecentCall.args[0]).toContain(custom_path);
+                expect(exec.mostRecentCall.args[0]).toMatch(/check_reqs"$/);
+                done();
+            });
+        });
+    });
+
+    describe('instance', function() {
+        var p, cp, rm, is_cordova, write, read, mv;
+        var windows8_proj = path.join(proj, 'platforms', 'windows8');
+        beforeEach(function() {
+            p = new platforms.windows8.parser(windows8_proj);
+            cp = spyOn(shell, 'cp');
+            rm = spyOn(shell, 'rm');
+            mv = spyOn(shell, 'mv');
+            is_cordova = spyOn(util, 'isCordova').andReturn(proj);
+            write = spyOn(fs, 'writeFileSync');
+            read = spyOn(fs, 'readFileSync').andReturn('');
+        });
+
+        describe('update_from_config method', function() {
+            var et, xml, find, write_xml, root, cfg, find_obj, root_obj, cfg_access_add, cfg_access_rm, cfg_pref_add, cfg_pref_rm, cfg_content;
+            beforeEach(function() {
+                find_obj = {
+                    text:'hi',
+                    attrib:{Title:'old'}
+                };
+                root_obj = {
+                    attrib:{
+                        package:'android_pkg'
+                    }
+                };
+                find = jasmine.createSpy('ElementTree find').andReturn(find_obj);
+                write_xml = jasmine.createSpy('ElementTree write');
+                root = jasmine.createSpy('ElementTree getroot').andReturn(root_obj);
+                et = spyOn(ET, 'ElementTree').andReturn({
+                    find:find,
+                    write:write_xml,
+                    getroot:root
+                });
+                xml = spyOn(ET, 'XML');
+                cfg = new config_parser();
+                cfg.name = function() { return 'testname' };
+                cfg.content = function() { return 'index.html' };
+                cfg.packageName = function() { return 'testpkg' };
+                cfg.version = function() { return 'one point oh' };
+                cfg.access.get = function() { return [] };
+                cfg.preference.get = function() { return [] };
+                cfg_access_add = jasmine.createSpy('config_parser access add');
+                cfg_access_rm = jasmine.createSpy('config_parser access rm');
+                cfg_pref_rm = jasmine.createSpy('config_parser pref rm');
+                cfg_pref_add = jasmine.createSpy('config_parser pref add');
+                cfg_content = jasmine.createSpy('config_parser content');
+                p.config = {
+                    access:{
+                        remove:cfg_access_rm,
+                        get:function(){},
+                        add:cfg_access_add
+                    },
+                    content:cfg_content,
+                    preference:{
+                        remove:cfg_pref_rm,
+                        get:function(){},
+                        add:cfg_pref_add
+                    }
+                };
+                readdir.andReturn(['test.sln']);
+            });
+
+            it('should write out the app name to wmappmanifest.xml', function() {
+                p.update_from_config(cfg);
+                expect(find_obj.attrib.Title).toEqual('testname');
+            });
+            it('should write out the app id to jsproj file', function() {
+                p.update_from_config(cfg);
+                expect(find_obj.text).toContain('testpkg');
+            });
+            it('should write out the app version to wmappmanifest.xml', function() {
+                p.update_from_config(cfg);
+                expect(find_obj.attrib.Version).toEqual('one point oh');
+            });
+            it('should update the content element (start page)', function() {
+                p.update_from_config(cfg);
+                expect(cfg_content).toHaveBeenCalledWith('index.html');
+            });
+        });
+        describe('www_dir method', function() {
+            it('should return www', function() {
+                expect(p.www_dir()).toEqual(path.join(windows8_proj, 'www'));
+            });
+        });
+        describe('staging_dir method', function() {
+            it('should return .staging/www', function() {
+                expect(p.staging_dir()).toEqual(path.join(windows8_proj, '.staging', 'www'));
+            });
+        });
+        describe('update_www method', function() {
+            var update_jsproj;
+            beforeEach(function() {
+                update_jsproj = spyOn(p, 'update_jsproj');
+            });
+            it('should rm project-level www and cp in platform agnostic www', function() {
+                p.update_www();
+                expect(rm).toHaveBeenCalled();
+                expect(cp).toHaveBeenCalled();
+            });
+            it('should copy in a fresh cordova.js from stock cordova lib if no custom lib is specified', function() {
+                p.update_www();
+                expect(write).toHaveBeenCalled();
+                expect(read.mostRecentCall.args[0]).toContain(util.libDirectory);
+            });
+            it('should copy in a fresh cordova.js from custom cordova lib if custom lib is specified', function() {
+                var custom_path = path.join('custom','path');
+                custom.andReturn(custom_path);
+                p.update_www();
+                expect(write).toHaveBeenCalled();
+                expect(read.mostRecentCall.args[0]).toContain(custom_path);
+            });
+        });
+        describe('update_staging method', function() {
+            it('should do nothing if staging dir does not exist', function() {
+                exists.andReturn(false);
+                p.update_staging();
+                expect(cp).not.toHaveBeenCalled();
+            });
+            it('should copy the staging dir into www if staging dir exists', function() {
+                p.update_staging();
+                expect(cp).toHaveBeenCalled();
+            });
+        });
+        describe('update_project method', function() {
+            var config, www, overrides, staging, svn;
+            beforeEach(function() {
+                config = spyOn(p, 'update_from_config');
+                www = spyOn(p, 'update_www');
+                staging = spyOn(p, 'update_staging');
+                svn = spyOn(util, 'deleteSvnFolders');
+            });
+            it('should call update_from_config', function() {
+                p.update_project();
+                expect(config).toHaveBeenCalled();
+            });
+            it('should throw if update_from_config throws', function(done) {
+                var err = new Error('uh oh!');
+                config.andCallFake(function() { throw err; });
+                p.update_project({}, function(err) {
+                    expect(err).toEqual(err);
+                    done();
+                });
+            });
+            it('should call update_www', function() {
+                p.update_project();
+                expect(www).toHaveBeenCalled();
+            });
+            it('should call update_staging', function() {
+                p.update_project();
+                expect(staging).toHaveBeenCalled();
+            });
+            it('should call deleteSvnFolders', function() {
+                p.update_project();
+                expect(svn).toHaveBeenCalled();
+            });
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a6929d1c/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
index a4ae605..cc89eb7 100644
--- a/spec/platform.spec.js
+++ b/spec/platform.spec.js
@@ -117,7 +117,7 @@ describe('platform command', function() {
 
             it('should list out added platforms in a project', function(done) {
                 cordova.on('results', function(res) {
-                    expect(res).toMatch(/^Installed platforms: ios, android, wp7, wp8, blackberry10, firefoxos\s*Available platforms:\s*$/);
+                    expect(res).toMatch(/^Installed platforms: ios, android, wp7, wp8, blackberry10, firefoxos, windows8\s*Available platforms:\s*$/);
                     done();
                 });
                 cordova.raw.platform('list');
@@ -133,6 +133,11 @@ describe('platform command', function() {
                 }).then(function() {
                     expect(exec.mostRecentCall.args[0]).toMatch(/lib.wp.cordova.\d.\d.\d[\d\w\-]*.wp8.bin.create/gi);
                     expect(exec.mostRecentCall.args[0]).toContain(project_dir);
+                }).then(function(){
+                    return cordova.raw.platform('add', 'windows8');
+                }).then(function(){
+                    expect(exec.mostRecentCall.args[0]).toMatch(/lib.windows8.cordova.\d.\d.\d[\d\w\-]*.windows8.bin.create/gi);
+                    expect(exec.mostRecentCall.args[0]).toContain(project_dir);
                     done();
                 });
             });
@@ -236,20 +241,23 @@ describe('platform command', function() {
                 });
             });
 
-            describe('success', function() {
-                it('should shell out to the platform update script', function(done) {
-                    var oldVersion = platforms['ios'].version;
-                    platforms['ios'].version = '1.0.0';
-                    cordova.raw.platform('update', ['ios']).then(function() {
-                        expect(exec).toHaveBeenCalledWith('HOMEDIR/.cordova/lib/ios/cordova/1.0.0/bin/update "some/path/platforms/ios"', jasmine.any(Function));
-                    }, function(err) {
-                        expect(err).toBeUndefined();
-                    }).fin(function() {
-                        platforms['ios'].version = oldVersion;
-                        done();
+            // Don't run this test on windows ... iOS will fail always
+            if(!require('os').platform().match(/^win/)) {
+                describe('success', function() {
+                    it('should shell out to the platform update script', function(done) {
+                        var oldVersion = platforms['ios'].version;
+                        platforms['ios'].version = '1.0.0';
+                        cordova.raw.platform('update', ['ios']).then(function() {
+                            expect(exec).toHaveBeenCalledWith('HOMEDIR/.cordova/lib/ios/cordova/1.0.0/bin/update "some/path/platforms/ios"', jasmine.any(Function));
+                        }, function(err) {
+                            expect(err).toBeUndefined();
+                        }).fin(function() {
+                            platforms['ios'].version = oldVersion;
+                            done();
+                        });
                     });
                 });
-            });
+            }
         });
     });
     describe('hooks', function() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a6929d1c/src/metadata/windows8_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/windows8_parser.js b/src/metadata/windows8_parser.js
new file mode 100644
index 0000000..208bec2
--- /dev/null
+++ b/src/metadata/windows8_parser.js
@@ -0,0 +1,262 @@
+/**
+    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'),
+    events        = require('../events'),
+    shell         = require('shelljs'),
+    events        = require('../events'),
+    config_parser = require('../config_parser'),
+    xml           = require('../xml-helpers'),
+    config        = require('../config');
+
+module.exports = function windows8_parser(project) {
+    try {
+        // TODO : Check that it's not a windows8 project?
+        var jsproj_file   = fs.readdirSync(project).filter(function(e) { return e.match(/\.jsproj$/i); })[0];
+        if (!jsproj_file) throw new Error('No .jsproj file.');
+        this.windows8_proj_dir = project;
+        this.jsproj_path  = path.join(this.windows8_proj_dir, jsproj_file);
+        this.sln_path     = path.join(this.windows8_proj_dir, jsproj_file.replace(/\.jsproj/, '.sln'));
+    } catch(e) {
+        throw new Error('The provided path "' + project + '" is not a Windows 8 project. ' + e);
+    }
+    this.manifest_path  = path.join(this.windows8_proj_dir, 'Properties', 'WMAppManifest.xml');
+    this.config_path = path.join(this.windows8_proj_dir, 'config.xml');
+    this.config = new util.config_parser(this.config_path);
+};
+
+module.exports.check_requirements = function(project_root, callback) {
+    events.emit('log', 'Checking windows8 requirements...');
+    var lib_path = path.join(util.libDirectory, 'windows8', 'cordova', require('../../platforms').windows8.version, 'windows8');
+    var custom_path = config.has_custom_path(project_root, 'windows8');
+    if (custom_path) lib_path = custom_path;
+    var command = '"' + path.join(lib_path, 'bin', 'check_reqs') + '"';
+    events.emit('log', 'Running "' + command + '" (output to follow)');
+    shell.exec(command, {silent:true, async:true}, function(code, output) {
+        events.emit('log', 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');
+
+        //Get manifest file
+        var manifest = xml.parseElementtreeSync(this.manifest_path);
+
+        //Update app version
+        var version = config.version();
+        manifest.find('.//App').attrib.Version = version;
+
+        // Update app name by editing app title in Properties\WMAppManifest.xml
+        var name = config.name();
+        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('.//App').attrib.Publisher = name + " Publisher";
+            manifest.find('.//App').attrib.Author = name + " Author";
+            manifest.find('.//PrimaryToken').attrib.TokenID = name;
+            //update name of sln and jsproj.
+            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.windows8_proj_dir).filter(function(e) { return e.match(/\.sln$/i); })[0];
+            var sln_path = path.join(this.windows8_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.jsproj_path, path.join(this.windows8_proj_dir, name + '.jsproj'));
+            this.jsproj_path = path.join(this.windows8_proj_dir, name + '.jsproj');
+            shell.mv('-f', sln_path, path.join(this.windows8_proj_dir, name + '.sln'));
+            this.sln_path    = path.join(this.windows8_proj_dir, name + '.sln');
+        }
+
+        // Update package name by changing:
+        /*  - CordovaAppProj.jsproj
+         *  - MainPage.xaml
+         *  - MainPage.xaml.cs
+         *  - App.xaml
+         *  - App.xaml.cs
+         */
+         var pkg = config.packageName();
+         var jsproj = xml.parseElementtreeSync(this.jsproj_path);
+         prev_name = jsproj.find('.//RootNamespace').text;
+         if(prev_name != pkg) {
+            //console.log("Updating package name from " + prev_name + " to " + pkg);
+            //CordovaAppProj.jsproj
+            jsproj.find('.//RootNamespace').text = pkg;
+            jsproj.find('.//AssemblyName').text = pkg;
+            jsproj.find('.//XapFilename').text = pkg + '.xap';
+            jsproj.find('.//SilverlightAppEntry').text = pkg + '.App';
+            fs.writeFileSync(this.jsproj_path, jsproj.write({indent: 4}), 'utf-8');
+            //MainPage.xaml
+            var mainPageXAML = xml.parseElementtreeSync(path.join(this.windows8_proj_dir, 'MainPage.xaml'));
+            mainPageXAML.getroot().attrib['x:Class'] = pkg + '.MainPage';
+            fs.writeFileSync(path.join(this.windows8_proj_dir, 'MainPage.xaml'), mainPageXAML.write({indent: 4}), 'utf-8');
+            //MainPage.xaml.cs
+            var mainPageCS = fs.readFileSync(path.join(this.windows8_proj_dir, 'MainPage.xaml.cs'), 'utf-8');
+            var namespaceRegEx = new RegExp('namespace ' + prev_name);
+            fs.writeFileSync(path.join(this.windows8_proj_dir, 'MainPage.xaml.cs'), mainPageCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+            //App.xaml
+            var appXAML = xml.parseElementtreeSync(path.join(this.windows8_proj_dir, 'App.xaml'));
+            appXAML.getroot().attrib['x:Class'] = pkg + '.App';
+            fs.writeFileSync(path.join(this.windows8_proj_dir, 'App.xaml'), appXAML.write({indent: 4}), 'utf-8');
+            //App.xaml.cs
+            var appCS = fs.readFileSync(path.join(this.windows8_proj_dir, 'App.xaml.cs'), 'utf-8');
+            fs.writeFileSync(path.join(this.windows8_proj_dir, 'App.xaml.cs'), appCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+         }
+
+         // Update content (start page) element
+         this.config.content(config.content());
+
+         //Write out manifest
+         fs.writeFileSync(this.manifest_path, manifest.write({indent: 4}), 'utf-8');
+    },
+    // Returns the platform-specific www directory.
+    www_dir:function() {
+        return path.join(this.windows8_proj_dir, 'www');
+    },
+    config_xml:function() {
+    },
+    // copy files from merges directory to actual www dir
+    copy_merges:function(merges_sub_path) {
+        var merges_path = path.join(util.appDir(util.isCordova(this.windows8_proj_dir)), 'merges', merges_sub_path);
+        if (fs.existsSync(merges_path)) {
+            var overrides = path.join(merges_path, '*');
+            shell.cp('-rf', overrides, this.www_dir());
+        }
+    },
+    // copies the app www folder into the windows8 project's www folder and updates the jsproj file.
+    update_www:function() {
+        var project_root = util.isCordova(this.windows8_proj_dir);
+        var project_www = util.projectWww(project_root);
+        // remove stock platform assets
+        shell.rm('-rf', this.www_dir());
+        // copy over all app www assets
+        shell.cp('-rf', project_www, this.windows8_proj_dir);
+
+        // copy all files from merges directories (generic first, then specific)
+        this.copy_merges('wp');
+        this.copy_merges('windows8');
+
+        // copy over windows8 lib's cordova.js
+        var lib_path = path.join(util.libDirectory, 'wp', 'cordova', require('../../platforms').windows8.version);
+        var custom_path = config.has_custom_path(project_root, 'windows8');
+        if (custom_path) lib_path = custom_path;
+        var cordovajs_path = path.join(lib_path, 'common', 'www', 'cordova.js');
+        fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
+        this.update_jsproj();
+    },
+    // updates the jsproj file to explicitly list all www content.
+    update_jsproj:function() {
+        var jsproj_xml = xml.parseElementtreeSync(this.jsproj_path);
+        // remove any previous references to the www files
+        var item_groups = jsproj_xml.findall('ItemGroup');
+        for (var i = 0, l = item_groups.length; i < l; i++) {
+            var group = item_groups[i];
+            var files = group.findall('Content');
+            for (var j = 0, k = files.length; j < k; j++) {
+                var file = files[j];
+                if (file.attrib.Include.substr(0, 3) == 'www') {
+                    // remove file reference
+                    group.remove(0, file);
+                    // remove ItemGroup if empty
+                    var new_group = group.findall('Content');
+                    if(new_group.length < 1) {
+                        jsproj_xml.getroot().remove(0, group);
+                    }
+                }
+            }
+        }
+
+        // now add all www references back in from the root www folder
+        var project_root = util.isCordova(this.windows8_proj_dir);
+        var www_files = this.folder_contents('www', this.www_dir());
+        for(file in www_files) {
+            var item = new et.Element('ItemGroup');
+            var content = new et.Element('Content');
+            content.attrib.Include = www_files[file];
+            item.append(content);
+            jsproj_xml.getroot().append(item);
+        }
+        // save file
+        fs.writeFileSync(this.jsproj_path, jsproj_xml.write({indent:4}), 'utf-8');
+    },
+    // Returns an array of all the files in the given directory with reletive paths
+    // - name     : the name of the top level directory (i.e all files will start with this in their path)
+    // - path     : the directory whos contents will be listed under 'name' directory
+    folder_contents:function(name, dir) {
+        var results = [];
+        var folder_dir = fs.readdirSync(dir);
+        for(item in folder_dir) {
+            var stat = fs.statSync(path.join(dir, folder_dir[item]));
+            // means its a folder?
+            if(stat.size == 0) {
+                var sub_dir = this.folder_contents(path.join(name, folder_dir[item]), path.join(dir, folder_dir[item]));
+                //Add all subfolder item paths
+                for(sub_item in sub_dir) {
+                    results.push(sub_dir[sub_item]);
+                }
+            }
+            else {
+                results.push(path.join(name, folder_dir[item]));
+            }
+        }
+        return results;
+    },
+    staging_dir: function() {
+        return path.join(this.windows8_proj_dir, '.staging', 'www');
+    },
+
+    update_staging: function() {
+        var projectRoot = util.isCordova(this.windows8_proj_dir);
+        if (fs.existsSync(this.staging_dir())) {
+            var staging = path.join(this.staging_dir(), '*');
+            shell.cp('-rf', staging, this.www_dir());
+        }
+    },
+
+    // calls the nessesary functions to update the windows8 project
+    update_project:function(cfg, callback) {
+        //console.log("Updating windows8 project...");
+
+        try {
+            this.update_from_config(cfg);
+        } catch(e) {
+            if (callback) return callback(e);
+            else throw e;
+        }
+        // overrides (merges) are handled in update_www()
+        this.update_www();
+        this.update_staging();
+        util.deleteSvnFolders(this.www_dir());
+
+        if (callback) callback();
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/a6929d1c/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 3b4adac..74122aa 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -234,8 +234,15 @@ function call_into_create(target, projectRoot, cfg, id, version, template_dir) {
             // Create a platform app using the ./bin/create scripts that exist in each repo.
             // Run platform's create script
             var bin = path.join(cordova_util.libDirectory, target, id, version, 'bin', 'create');
-            if(target == 'wp7') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp7', 'bin', 'create');
-            if(target == 'wp8') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp8', 'bin', 'create');
+            if(target == 'wp7') {
+                bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp7', 'bin', 'create');
+            }
+            else if(target == 'wp8') {
+                bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp8', 'bin', 'create');
+            }
+            else if(target == 'windows8') {
+                bin = path.join(cordova_util.libDirectory, 'windows8', id, version, 'windows8', 'bin', 'create');
+            }
             var args = (target=='ios') ? '--arc' : '';
             var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
             var name = cfg.name();