You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by an...@apache.org on 2016/10/20 12:11:56 UTC
cordova-windows git commit: CB-11933: Add uap prefixes for
capabilities at plugin install
Repository: cordova-windows
Updated Branches:
refs/heads/master 610b0adeb -> b64ee1e5c
CB-11933: Add uap prefixes for capabilities at plugin install
This closes #203
Project: http://git-wip-us.apache.org/repos/asf/cordova-windows/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-windows/commit/b64ee1e5
Tree: http://git-wip-us.apache.org/repos/asf/cordova-windows/tree/b64ee1e5
Diff: http://git-wip-us.apache.org/repos/asf/cordova-windows/diff/b64ee1e5
Branch: refs/heads/master
Commit: b64ee1e5cb82a10e0762be51fc532ccf8da0e56a
Parents: 610b0ad
Author: Nikita Matrosov <ma...@gmail.com>
Authored: Wed Oct 19 14:23:52 2016 +0300
Committer: Vladimir Kotikov <v-...@microsoft.com>
Committed: Thu Oct 20 15:11:27 2016 +0300
----------------------------------------------------------------------
spec/unit/ConfigChanges.spec.js | 81 +++++++-----
.../windows/package.windows10.appxmanifest | 73 +++++++++++
template/cordova/Api.js | 5 +-
template/cordova/lib/AppxManifest.js | 7 ++
template/cordova/lib/ConfigChanges.js | 125 +++++++++++++++----
5 files changed, 237 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/b64ee1e5/spec/unit/ConfigChanges.spec.js
----------------------------------------------------------------------
diff --git a/spec/unit/ConfigChanges.spec.js b/spec/unit/ConfigChanges.spec.js
index 44ad4cd..df346dd 100644
--- a/spec/unit/ConfigChanges.spec.js
+++ b/spec/unit/ConfigChanges.spec.js
@@ -61,72 +61,97 @@ describe('PlatformMunger', function () {
});
it('should additionally call parent\'s method with another munge if removing changes from windows 10 appxmanifest', function () {
- munger.apply_file_munge('package.windows10.appxmanifest', munge, /*remove=*/true);
+ munger.apply_file_munge(WINDOWS10_MANIFEST, munge, /*remove=*/true);
expect(BaseMunger.prototype.apply_file_munge).toHaveBeenCalledWith(WINDOWS10_MANIFEST, munge, true);
- expect(BaseMunger.prototype.apply_file_munge).toHaveBeenCalledWith(WINDOWS10_MANIFEST, jasmine.any(Object), true);
});
it('should remove uap: capabilities added by windows prepare step', function () {
// Generate a munge that contain non-prefixed capabilities changes
- var baseMunge = { parents: { WINDOWS10_MANIFEST: [
+ var baseMunge = { parents: { '/Package/Capabilities': [
// Emulate capability that was initially added with uap prefix
{ before: undefined, count: 1, xml: '<uap:Capability Name=\"privateNetworkClientServer\">'},
{ before: undefined, count: 1, xml: '<Capability Name=\"enterpriseAuthentication\">'}
]}};
- var capabilitiesMunge = { parents: { WINDOWS10_MANIFEST: [
+ var capabilitiesMunge = { parents: { '/Package/Capabilities': [
{ before: undefined, count: 1, xml: '<uap:Capability Name=\"enterpriseAuthentication\">'}
]}};
-
- munger.apply_file_munge('package.windows10.appxmanifest', baseMunge, /*remove=*/true);
+ munger.apply_file_munge(WINDOWS10_MANIFEST, baseMunge, /*remove=*/true);
expect(BaseMunger.prototype.apply_file_munge).toHaveBeenCalledWith(WINDOWS10_MANIFEST, capabilitiesMunge, true);
});
});
});
describe('Capabilities within package.windows.appxmanifest', function() {
- var testDir;
+
+ var testDir, windowsPlatform, windowsManifest, windowsManifest10, dummyPluginInfo, api;
beforeEach(function() {
testDir = path.join(__dirname, 'testDir');
shell.mkdir('-p', testDir);
shell.cp('-rf', windowsProject + '/*', testDir);
+ windowsPlatform = path.join(testDir, 'platforms/windows');
+ windowsManifest = path.join(windowsPlatform, WINDOWS_MANIFEST);
+ windowsManifest10 = path.join(windowsPlatform, WINDOWS10_MANIFEST);
+ dummyPluginInfo = new PluginInfo(dummyPlugin);
+ api = new Api();
+ api.root = windowsPlatform;
+ api.locations.root = windowsPlatform;
+ api.locations.www = path.join(windowsPlatform, 'www');
});
afterEach(function() {
shell.rm('-rf', testDir);
});
- it('should be removed using overriden PlatformMunger', function(done) {
- var windowsPlatform = path.join(testDir, 'platforms/windows');
- var windowsManifest = path.join(windowsPlatform, WINDOWS_MANIFEST);
- var api = new Api();
- api.root = windowsPlatform;
- api.locations.root = windowsPlatform;
- api.locations.www = path.join(windowsPlatform, 'www');
- var dummyPluginInfo = new PluginInfo(dummyPlugin);
+ function getPluginCapabilities(pluginInfo) {
+ return pluginInfo.getConfigFiles()[0].xmls;
+ }
- var fail = jasmine.createSpy('fail')
- .andCallFake(function (err) {
- console.error(err);
- });
+ function getManifestCapabilities(manifest) {
+ var appxmanifest = AppxManifest.get(manifest, true);
+ return appxmanifest.getCapabilities();
+ }
- function getPluginCapabilities() {
- return dummyPluginInfo.getConfigFiles()[0].xmls;
- }
+ var fail = jasmine.createSpy('fail')
+ .andCallFake(function (err) {
+ console.error(err);
+ });
+
+ it('should be removed using overriden PlatformMunger', function(done) {
+ api.addPlugin(dummyPluginInfo)
+ .then(function() {
+ // There is the one default capability in manifest with 'internetClient' name
+ expect(getManifestCapabilities(windowsManifest).length).toBe(getPluginCapabilities(dummyPluginInfo).length + 1);
+ api.removePlugin(dummyPluginInfo);
+ })
+ .then(function() {
+ expect(getManifestCapabilities(windowsManifest).length).toBe(1);
+ })
+ .catch(fail)
+ .finally(function() {
+ expect(fail).not.toHaveBeenCalled();
+ done();
+ });
+ });
- function getManifestCapabilities() {
- var appxmanifest = AppxManifest.get(windowsManifest, true);
- return appxmanifest.getCapabilities();
- }
+ it('should be added with uap prefixes when install plugin', function(done) {
api.addPlugin(dummyPluginInfo)
.then(function() {
// There is the one default capability in manifest with 'internetClient' name
- expect(getManifestCapabilities().length).toBe(getPluginCapabilities().length + 1);
+ var manifestCapabilities = getManifestCapabilities(windowsManifest10);
+ expect(manifestCapabilities.length).toBe(getPluginCapabilities(dummyPluginInfo).length + 1);
+
+ // Count 'uap' prefixed capabilities
+ var uapPrefixedCapsCount = manifestCapabilities.filter(function(capability) {
+ return capability.type === 'uap:Capability';
+ }).length;
+
+ expect(uapPrefixedCapsCount).toBe(2);
api.removePlugin(dummyPluginInfo);
})
.then(function() {
- expect(getManifestCapabilities().length).toBe(1);
+ expect(getManifestCapabilities(windowsManifest10).length).toBe(1);
})
.catch(fail)
.finally(function() {
http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/b64ee1e5/spec/unit/fixtures/testProj/platforms/windows/package.windows10.appxmanifest
----------------------------------------------------------------------
diff --git a/spec/unit/fixtures/testProj/platforms/windows/package.windows10.appxmanifest b/spec/unit/fixtures/testProj/platforms/windows/package.windows10.appxmanifest
new file mode 100644
index 0000000..59e435a
--- /dev/null
+++ b/spec/unit/fixtures/testProj/platforms/windows/package.windows10.appxmanifest
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Package
+ xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
+ xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
+ xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
+ IgnorableNamespaces="uap mp">
+
+ <Identity
+ Name="$guid1$"
+ Version="1.0.0.0"
+ Publisher="CN=$username$" />
+
+ <mp:PhoneIdentity PhoneProductId="$guid1$" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
+
+ <Properties>
+ <DisplayName>$projectname$</DisplayName>
+ <PublisherDisplayName>$username$</PublisherDisplayName>
+ <Logo>images\StoreLogo.png</Logo>
+ </Properties>
+
+ <Dependencies>
+ <TargetDeviceFamily Name="Windows.Universal" MinVersion="0.0.0.0" MaxVersionTested="10.0.0.0" />
+ </Dependencies>
+
+ <Resources>
+ <Resource Language="x-generate" />
+ </Resources>
+
+ <Applications>
+ <Application
+ Id="App"
+ StartPage="www/index.html">
+
+ <uap:VisualElements
+ DisplayName="$projectname$"
+ Description="CordovaApp"
+ BackgroundColor="#464646"
+ Square150x150Logo="images\Square150x150Logo.png"
+ Square44x44Logo="images\Square44x44Logo.png">
+
+ <uap:SplashScreen Image="images\splashscreen.png" />
+ <uap:DefaultTile ShortName="$projectname$"
+ Square310x310Logo="images\Square310x310Logo.png"
+ Square71x71Logo="images\Square71x71Logo.png"
+ Wide310x150Logo="images\Wide310x150Logo.png" />
+
+ </uap:VisualElements>
+ </Application>
+ </Applications>
+
+ <Capabilities>
+ <Capability Name="internetClient" />
+ </Capabilities>
+
+</Package>
http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/b64ee1e5/template/cordova/Api.js
----------------------------------------------------------------------
diff --git a/template/cordova/Api.js b/template/cordova/Api.js
index 50a0778..7637582 100644
--- a/template/cordova/Api.js
+++ b/template/cordova/Api.js
@@ -208,7 +208,10 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
installOptions.variables.PACKAGE_NAME = jsProject.getPackageName();
}
- return PluginManager.get(this.platform, this.locations, jsProject)
+ var platformJson = PlatformJson.load(this.root, this.platform);
+ var pluginManager = PluginManager.get(this.platform, this.locations, jsProject);
+ pluginManager.munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
+ return pluginManager
.addPlugin(plugin, installOptions)
.then(function () {
// CB-11657 Add BOM to www files here because files added by plugin
http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/b64ee1e5/template/cordova/lib/AppxManifest.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/AppxManifest.js b/template/cordova/lib/AppxManifest.js
index 6973d13..75d4eee 100644
--- a/template/cordova/lib/AppxManifest.js
+++ b/template/cordova/lib/AppxManifest.js
@@ -72,6 +72,13 @@ function AppxManifest(path, prefix) {
this.hasPhoneIdentity = this.prefix === 'uap:' || this.prefix === 'm3:';
}
+// Static read-only property to get capabilities which need to be prefixed with uap
+Object.defineProperty(AppxManifest, 'CapsNeedUapPrefix', {
+ writable: false,
+ configurable: false,
+ value: CAPS_NEEDING_UAPNS
+});
+
/**
* @static
* @constructs AppxManifest|Win10AppxManifest
http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/b64ee1e5/template/cordova/lib/ConfigChanges.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/ConfigChanges.js b/template/cordova/lib/ConfigChanges.js
index 7e15606..64eba4d 100644
--- a/template/cordova/lib/ConfigChanges.js
+++ b/template/cordova/lib/ConfigChanges.js
@@ -15,7 +15,12 @@
*/
var util = require('util');
+var path = require('path');
var CommonMunger = require('cordova-common').ConfigChanges.PlatformMunger;
+var CapsNeedUapPrefix = require(path.join(__dirname, 'AppxManifest')).CapsNeedUapPrefix;
+
+var CAPS_SELECTOR = '/Package/Capabilities';
+var WINDOWS10_MANIFEST = 'package.windows10.appxmanifest';
function PlatformMunger(platform, project_dir, platformJson, pluginInfoProvider) {
CommonMunger.apply(this, arguments);
@@ -34,36 +39,111 @@ util.inherits(PlatformMunger, CommonMunger);
* need to be removed or added to the file
*/
PlatformMunger.prototype.apply_file_munge = function (file, munge, remove) {
- // Call parent class' method
- PlatformMunger.super_.prototype.apply_file_munge.call(this, file, munge, remove);
-
- // CB-11066 If this is a windows10 manifest and we're removing the changes
- // then we also need to check if there are <Capability> elements were previously
- // added and schedule removal of corresponding <uap:Capability> elements
- if (remove && file === 'package.windows10.appxmanifest') {
- var uapCapabilitiesMunge = generateUapCapabilities(munge);
- // We do not check whether generated munge is empty or not before calling
- // 'apply_file_munge' since applying empty one is just a no-op
- PlatformMunger.super_.prototype.apply_file_munge.call(this, file, uapCapabilitiesMunge, remove);
+
+ // Create a copy to avoid modification of original munge
+ var mungeCopy = cloneObject(munge);
+ var capabilities = mungeCopy.parents[CAPS_SELECTOR];
+
+ if (capabilities) {
+ // Add 'uap' prefixes for windows 10 manifest
+ if (file === WINDOWS10_MANIFEST) {
+ capabilities = generateUapCapabilities(capabilities);
+ }
+
+ // Remove duplicates and sort capabilities when installing plugin
+ if (!remove) {
+ capabilities = getUniqueCapabilities(capabilities).sort(compareCapabilities);
+ }
+
+ // Put back capabilities into munge's copy
+ mungeCopy.parents[CAPS_SELECTOR] = capabilities;
}
+
+ PlatformMunger.super_.prototype.apply_file_munge.call(this, file, mungeCopy, remove);
};
+// Recursive function to clone an object
+function cloneObject(obj) {
+ if (obj === null || typeof obj !== 'object') {
+ return obj;
+ }
+
+ var copy = obj.constructor();
+ Object.keys(obj).forEach(function(key) {
+ copy[key] = cloneObject(obj[key]);
+ });
+
+ return copy;
+}
+
+/**
+ * Retrieve capabality name from xml field
+ * @param {Object} capability with xml field like <Capability Name="CapabilityName">
+ * @return {String} name of capability
+ */
+function getCapabilityName(capability) {
+ var reg = /Name="(\w+)"/i;
+ return capability.xml.match(reg)[1];
+}
+
+/**
+ * Remove capabilities with same names
+ * @param {Object} an array of capabilities
+ * @return {Object} an unique array of capabilities
+ */
+function getUniqueCapabilities(capabilities) {
+ return capabilities.reduce(function(uniqueCaps, currCap) {
+
+ var isRepeated = uniqueCaps.some(function(cap) {
+ return getCapabilityName(cap) === getCapabilityName(currCap);
+ });
+
+ return isRepeated ? uniqueCaps : uniqueCaps.concat([currCap]);
+ }, []);
+}
+
+/**
+ * Comparator function to pass to Array.sort
+ * @param {Object} firstCap first capability
+ * @param {Object} secondCap second capability
+ * @return {Number} either -1, 0 or 1
+ */
+function compareCapabilities(firstCap, secondCap) {
+ var firstCapName = getCapabilityName(firstCap);
+ var secondCapName = getCapabilityName(secondCap);
+
+ if (firstCapName < secondCapName) {
+ return -1;
+ }
+
+ if (firstCapName > secondCapName) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
/**
* Generates a new munge that contains <uap:Capability> elements created based on
* corresponding <Capability> elements from base munge. If there are no such elements
* found in base munge, the empty munge is returned (selectors might be present under
* the 'parents' key, but they will contain no changes).
*
- * @param {Object} munge A munge that we need to check for <Capability> elements
- * @return {Object} A munge with 'uap'-prefixed capabilities or empty one
+ * @param {Object} capabilities A list of capabilities
+ * @return {Object} A list with 'uap'-prefixed capabilities
*/
-function generateUapCapabilities(munge) {
+function generateUapCapabilities(capabilities) {
function hasCapabilityChange(change) {
return /^\s*<Capability\s/.test(change.xml);
}
function createPrefixedCapabilityChange(change) {
+ if (CapsNeedUapPrefix.indexOf(getCapabilityName(change)) < 0) {
+ return change;
+ }
+
return {
xml: change.xml.replace(/Capability/, 'uap:Capability'),
count: change.count,
@@ -71,17 +151,12 @@ function generateUapCapabilities(munge) {
};
}
- // Iterate through all selectors in munge
- return Object.keys(munge.parents)
- .reduce(function (result, selector) {
- result.parents[selector] = munge.parents[selector]
- // For every xml change check if it adds a <Capability> element ...
- .filter(hasCapabilityChange)
- // ... and create a duplicate with 'uap:' prefix
- .map(createPrefixedCapabilityChange);
-
- return result;
- }, { parents: {} });
+ return capabilities
+ // For every xml change check if it adds a <Capability> element ...
+ .filter(hasCapabilityChange)
+ // ... and create a duplicate with 'uap:' prefix
+ .map(createPrefixedCapabilityChange);
+
}
exports.PlatformMunger = PlatformMunger;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org