summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/cordova/lib
diff options
context:
space:
mode:
authorJules Laplace <julescarbon@gmail.com>2020-08-31 23:07:20 +0200
committerJules Laplace <julescarbon@gmail.com>2020-08-31 23:07:20 +0200
commit22721a013bdd10d5eb395ba18453585f5f3f1f7f (patch)
tree5a920e31d6026ed5dc55265e5fd057febccc50e3 /StoneIsland/platforms/ios/cordova/lib
parentd22d51a1ae49680015326857360eb699f31efced (diff)
rebuild the ios platform and the plugins
Diffstat (limited to 'StoneIsland/platforms/ios/cordova/lib')
-rw-r--r--StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js123
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/Podfile.js289
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/PodsJson.js154
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/build.js276
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/check_reqs.js139
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/clean.js37
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js73
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/list-devices49
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets99
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/list-emulator-images29
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/list-started-emulators32
-rw-r--r--StoneIsland/platforms/ios/cordova/lib/listDevices.js42
-rw-r--r--StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js95
-rw-r--r--StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js30
-rw-r--r--StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js50
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js205
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/prepare.js863
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/projectFile.js69
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/run.js168
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/spawn.js47
-rw-r--r--[-rwxr-xr-x]StoneIsland/platforms/ios/cordova/lib/versions.js173
21 files changed, 1630 insertions, 1412 deletions
diff --git a/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js b/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js
new file mode 100644
index 00000000..9e200b50
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/BridgingHeader.js
@@ -0,0 +1,123 @@
+/*
+ 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.
+*/
+'use strict';
+
+const fs = require('fs-extra');
+const CordovaError = require('cordova-common').CordovaError;
+
+function BridgingHeader (bridgingHeaderPath) {
+ this.path = bridgingHeaderPath;
+ this.bridgingHeaders = null;
+ if (!fs.existsSync(this.path)) {
+ throw new CordovaError('BridgingHeader.h is not found.');
+ }
+ this.bridgingHeaders = this.__parseForBridgingHeader(fs.readFileSync(this.path, 'utf8'));
+}
+
+BridgingHeader.prototype.addHeader = function (plugin_id, header_path) {
+ this.bridgingHeaders.push({ type: 'code', code: `#import "${header_path}"\n` });
+};
+
+BridgingHeader.prototype.removeHeader = function (plugin_id, header_path) {
+ this.bridgingHeaders = this.bridgingHeaders.filter(function (line) {
+ if (this.found) {
+ return true;
+ }
+ if (line.type === 'code') {
+ const re = new RegExp(`#import\\s+"${preg_quote(header_path)}"(\\s*|\\s.+)(\\n|$)`);
+ if (re.test(line.code)) {
+ this.found = true;
+ return false;
+ }
+ }
+ return true;
+ }, { found: false });
+};
+
+BridgingHeader.prototype.write = function () {
+ const text = this.__stringifyForBridgingHeader(this.bridgingHeaders);
+ fs.writeFileSync(this.path, text, 'utf8');
+};
+
+BridgingHeader.prototype.__stringifyForBridgingHeader = function (bridgingHeaders) {
+ return bridgingHeaders.map(obj => obj.code).join('');
+};
+
+BridgingHeader.prototype.__parseForBridgingHeader = function (text) {
+ let i = 0;
+ const list = [];
+ let type = 'code';
+ let start = 0;
+ while (i < text.length) {
+ switch (type) {
+ case 'comment':
+ if (i + 1 < text.length && text[i] === '*' && text[i + 1] === '/') {
+ i += 2;
+ list.push({ type, code: text.slice(start, i) });
+ type = 'code';
+ start = i;
+ } else {
+ i += 1;
+ }
+ break;
+ case 'line-comment':
+ if (i < text.length && text[i] === '\n') {
+ i += 1;
+ list.push({ type, code: text.slice(start, i) });
+ type = 'code';
+ start = i;
+ } else {
+ i += 1;
+ }
+ break;
+ case 'code':
+ default:
+ if (i + 1 < text.length && text[i] === '/' && text[i + 1] === '*') { // comment
+ if (start < i) {
+ list.push({ type, code: text.slice(start, i) });
+ }
+ type = 'comment';
+ start = i;
+ } else if (i + 1 < text.length && text[i] === '/' && text[i + 1] === '/') { // line comment
+ if (start < i) {
+ list.push({ type, code: text.slice(start, i) });
+ }
+ type = 'line-comment';
+ start = i;
+ } else if (i < text.length && text[i] === '\n') {
+ i += 1;
+ list.push({ type, code: text.slice(start, i) });
+ start = i;
+ } else {
+ i += 1;
+ }
+ break;
+ }
+ }
+ if (start < i) {
+ list.push({ type, code: text.slice(start, i) });
+ }
+ return list;
+};
+
+function preg_quote (str, delimiter) {
+ return (`${str}`).replace(new RegExp(`[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\${delimiter || ''}-]`, 'g'), '\\$&');
+}
+
+module.exports.BridgingHeader = BridgingHeader;
diff --git a/StoneIsland/platforms/ios/cordova/lib/Podfile.js b/StoneIsland/platforms/ios/cordova/lib/Podfile.js
index 49173c4c..f1672974 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/Podfile.js
+++ b/StoneIsland/platforms/ios/cordova/lib/Podfile.js
@@ -18,27 +18,37 @@
*/
'use strict';
-var fs = require('fs');
-var path = require('path');
-var util = require('util');
-var events = require('cordova-common').events;
-var Q = require('q');
-var superspawn = require('cordova-common').superspawn;
-var CordovaError = require('cordova-common').CordovaError;
+const fs = require('fs-extra');
+const path = require('path');
+const util = require('util');
+const {
+ CordovaError,
+ events,
+ superspawn: { spawn }
+} = require('cordova-common');
Podfile.FILENAME = 'Podfile';
+Podfile.declarationRegexpMap = {
+ 'use_frameworks!': 'use[-_]frameworks!?',
+ 'inhibit_all_warnings!': 'inhibit[-_]all[-_]warnings!?'
+};
-function Podfile (podFilePath, projectName) {
+function Podfile (podFilePath, projectName, minDeploymentTarget) {
+ this.declarationToken = '##INSERT_DECLARATION##';
+ this.sourceToken = '##INSERT_SOURCE##';
this.podToken = '##INSERT_POD##';
this.path = podFilePath;
this.projectName = projectName;
+ this.minDeploymentTarget = minDeploymentTarget || '11.0';
this.contents = null;
+ this.sources = null;
+ this.declarations = null;
this.pods = null;
this.__dirty = false;
// check whether it is named Podfile
- var filename = this.path.split(path.sep).pop();
+ const filename = this.path.split(path.sep).pop();
if (filename !== Podfile.FILENAME) {
throw new CordovaError(util.format('Podfile: The file at %s is not `%s`.', this.path, Podfile.FILENAME));
}
@@ -55,33 +65,101 @@ function Podfile (podFilePath, projectName) {
} else {
events.emit('verbose', 'Podfile found in platforms/ios');
// parse for pods
- this.pods = this.__parseForPods(fs.readFileSync(this.path, 'utf8'));
+ const fileText = fs.readFileSync(this.path, 'utf8');
+ this.declarations = this.__parseForDeclarations(fileText);
+ this.sources = this.__parseForSources(fileText);
+ this.pods = this.__parseForPods(fileText);
}
}
+Podfile.prototype.__parseForDeclarations = function (text) {
+ // split by \n
+ const arr = text.split('\n');
+
+ // getting lines between "platform :ios, '11.0'"" and "target 'HelloCordova'" do
+ const declarationsPreRE = new RegExp('platform :ios,\\s+\'[^\']+\'');
+ const declarationsPostRE = new RegExp('target\\s+\'[^\']+\'\\s+do');
+ const declarationRE = new RegExp('^\\s*[^#]');
+
+ return arr.reduce((acc, line) => {
+ switch (acc.state) {
+ case 0:
+ if (declarationsPreRE.exec(line)) {
+ acc.state = 1; // Start to read
+ }
+ break;
+ case 1:
+ if (declarationsPostRE.exec(line)) {
+ acc.state = 2; // Finish to read
+ } else {
+ acc.lines.push(line);
+ }
+ break;
+ case 2:
+ default:
+ // do nothing;
+ }
+ return acc;
+ }, { state: 0, lines: [] })
+ .lines
+ .filter(line => declarationRE.exec(line))
+ .reduce((obj, line) => {
+ obj[line] = line;
+ return obj;
+ }, {});
+};
+
+Podfile.prototype.__parseForSources = function (text) {
+ // split by \n
+ const arr = text.split('\n');
+
+ const sourceRE = new RegExp('source \'(.*)\'');
+ return arr.filter(line => {
+ const m = sourceRE.exec(line);
+
+ return (m !== null);
+ })
+ .reduce((obj, line) => {
+ const m = sourceRE.exec(line);
+ if (m !== null) {
+ const source = m[1];
+ obj[source] = source;
+ }
+ return obj;
+ }, {});
+};
+
Podfile.prototype.__parseForPods = function (text) {
// split by \n
- var arr = text.split('\n');
+ const arr = text.split('\n');
// aim is to match (space insignificant around the comma, comma optional):
// pod 'Foobar', '1.2'
// pod 'Foobar', 'abc 123 1.2'
// pod 'PonyDebugger', :configurations => ['Debug', 'Beta']
- var podRE = new RegExp('pod \'([^\']*)\'\\s*,?\\s*(.*)');
+ // var podRE = new RegExp('pod \'([^\']*)\'\\s*,?\\s*(.*)');
+ const podRE = new RegExp('pod \'([^\']*)\'\\s*(?:,\\s*\'([^\']*)\'\\s*)?,?\\s*(.*)');
// only grab lines that don't have the pod spec'
- return arr.filter(function (line) {
- var m = podRE.exec(line);
+ return arr.filter(line => {
+ const m = podRE.exec(line);
return (m !== null);
})
- .reduce(function (obj, line) {
- var m = podRE.exec(line);
+ .reduce((obj, line) => {
+ const m = podRE.exec(line);
if (m !== null) {
- // strip out any single quotes around the value m[2]
- var podSpec = m[2].replace(/^\'|\'$/g, ''); /* eslint no-useless-escape : 0 */
- obj[m[1]] = podSpec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'}
+ const podspec = {
+ name: m[1]
+ };
+ if (m[2]) {
+ podspec.spec = m[2];
+ }
+ if (m[3]) {
+ podspec.options = m[3];
+ }
+ obj[m[1]] = podspec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'}
}
return obj;
@@ -89,20 +167,22 @@ Podfile.prototype.__parseForPods = function (text) {
};
Podfile.prototype.escapeSingleQuotes = function (string) {
- return string.replace('\'', '\\\'');
+ return string.replace(/'/g, '\\\'');
};
Podfile.prototype.getTemplate = function () {
// Escaping possible ' in the project name
- var projectName = this.escapeSingleQuotes(this.projectName);
+ const projectName = this.escapeSingleQuotes(this.projectName);
return util.format(
'# DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
- 'platform :ios, \'8.0\'\n' +
+ '%s\n' +
+ 'platform :ios, \'%s\'\n' +
+ '%s\n' +
'target \'%s\' do\n' +
'\tproject \'%s.xcodeproj\'\n' +
'%s\n' +
'end\n',
- projectName, projectName, this.podToken);
+ this.sourceToken, this.minDeploymentTarget, this.declarationToken, projectName, projectName, this.podToken);
};
Podfile.prototype.addSpec = function (name, spec) {
@@ -114,6 +194,14 @@ Podfile.prototype.addSpec = function (name, spec) {
throw new CordovaError('Podfile addSpec: name is not specified.');
}
+ if (typeof spec === 'string') {
+ if (spec.startsWith(':')) {
+ spec = { name, options: spec };
+ } else {
+ spec = { name, spec };
+ }
+ }
+
this.pods[name] = spec;
this.__dirty = true;
@@ -137,7 +225,60 @@ Podfile.prototype.existsSpec = function (name) {
return (name in this.pods);
};
+Podfile.prototype.addSource = function (src) {
+ this.sources[src] = src;
+ this.__dirty = true;
+
+ events.emit('verbose', util.format('Added source line for `%s`', src));
+};
+
+Podfile.prototype.removeSource = function (src) {
+ if (this.existsSource(src)) {
+ delete this.sources[src];
+ this.__dirty = true;
+ }
+
+ events.emit('verbose', util.format('Removed source line for `%s`', src));
+};
+
+Podfile.prototype.existsSource = function (src) {
+ return (src in this.sources);
+};
+
+Podfile.prototype.addDeclaration = function (declaration) {
+ this.declarations[declaration] = declaration;
+ this.__dirty = true;
+
+ events.emit('verbose', util.format('Added declaration line for `%s`', declaration));
+};
+
+Podfile.prototype.removeDeclaration = function (declaration) {
+ if (this.existsDeclaration(declaration)) {
+ delete this.declarations[declaration];
+ this.__dirty = true;
+ }
+
+ events.emit('verbose', util.format('Removed source line for `%s`', declaration));
+};
+
+Podfile.proofDeclaration = declaration => {
+ const list = Object.keys(Podfile.declarationRegexpMap).filter(key => {
+ const regexp = new RegExp(Podfile.declarationRegexpMap[key]);
+ return regexp.test(declaration);
+ });
+ if (list.length > 0) {
+ return list[0];
+ }
+ return declaration;
+};
+
+Podfile.prototype.existsDeclaration = function (declaration) {
+ return (declaration in this.declarations);
+};
+
Podfile.prototype.clear = function () {
+ this.sources = {};
+ this.declarations = {};
this.pods = {};
this.__dirty = true;
};
@@ -148,28 +289,65 @@ Podfile.prototype.destroy = function () {
};
Podfile.prototype.write = function () {
- var text = this.getTemplate();
- var self = this;
+ let text = this.getTemplate();
- var podsString =
- Object.keys(this.pods).map(function (key) {
- var name = key;
- var spec = self.pods[key];
+ const podsString =
+ Object.keys(this.pods).map(key => {
+ const name = key;
+ const json = this.pods[key];
- if (spec.length) {
- if (spec.indexOf(':') === 0) {
- // don't quote it, it's a specification (starts with ':')
- return util.format('\tpod \'%s\', %s', name, spec);
+ if (typeof json === 'string') { // compatibility for using framework tag.
+ const spec = json;
+ if (spec.length) {
+ if (spec.indexOf(':') === 0) {
+ // don't quote it, it's a specification (starts with ':')
+ return util.format('\tpod \'%s\', %s', name, spec);
+ } else {
+ // quote it, it's a version
+ return util.format('\tpod \'%s\', \'%s\'', name, spec);
+ }
} else {
- // quote it, it's a version
- return util.format('\tpod \'%s\', \'%s\'', name, spec);
+ return util.format('\tpod \'%s\'', name);
}
} else {
- return util.format('\tpod \'%s\'', name);
+ const list = [`'${name}'`];
+ if ('spec' in json && json.spec.length) {
+ list.push(`'${json.spec}'`);
+ }
+
+ let options = ['tag', 'branch', 'commit', 'git', 'podspec']
+ .filter(tag => tag in json)
+ .map(tag => `:${tag} => '${json[tag]}'`);
+
+ if ('configurations' in json) {
+ options.push(`:configurations => [${json.configurations.split(',').map(conf => `'${conf.trim()}'`).join(',')}]`);
+ }
+ if ('options' in json) {
+ options = [json.options];
+ }
+ if (options.length > 0) {
+ list.push(options.join(', '));
+ }
+ return util.format('\tpod %s', list.join(', '));
}
}).join('\n');
- text = text.replace(this.podToken, podsString);
+ const sourcesString =
+ Object.keys(this.sources).map(key => {
+ const source = this.sources[key];
+ return util.format('source \'%s\'', source);
+ }).join('\n');
+
+ const declarationString =
+ Object.keys(this.declarations).map(key => {
+ const declaration = this.declarations[key];
+ return declaration;
+ }).join('\n');
+
+ text = text.replace(this.podToken, podsString)
+ .replace(this.sourceToken, sourcesString)
+ .replace(this.declarationToken, declarationString);
+
fs.writeFileSync(this.path, text, 'utf8');
this.__dirty = false;
@@ -184,45 +362,43 @@ Podfile.prototype.before_install = function (toolOptions) {
toolOptions = toolOptions || {};
// Template tokens in order: project name, project name, debug | release
- var template =
+ const template =
'// DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
'#include "Pods/Target Support Files/Pods-%s/Pods-%s.%s.xcconfig"';
- var debugContents = util.format(template, this.projectName, this.projectName, 'debug');
- var releaseContents = util.format(template, this.projectName, this.projectName, 'release');
+ const debugContents = util.format(template, this.projectName, this.projectName, 'debug');
+ const releaseContents = util.format(template, this.projectName, this.projectName, 'release');
- var debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig');
- var releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig');
+ const debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig');
+ const releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig');
fs.writeFileSync(debugConfigPath, debugContents, 'utf8');
fs.writeFileSync(releaseConfigPath, releaseContents, 'utf8');
- return Q.resolve(toolOptions);
+ return Promise.resolve(toolOptions);
};
Podfile.prototype.install = function (requirementsCheckerFunction) {
- var opts = {};
+ const opts = {};
opts.cwd = path.join(this.path, '..'); // parent path of this Podfile
opts.stdio = 'pipe';
- var first = true;
- var self = this;
+ opts.printCommand = true;
+ let first = true;
if (!requirementsCheckerFunction) {
- requirementsCheckerFunction = Q();
+ requirementsCheckerFunction = Promise.resolve();
}
return requirementsCheckerFunction()
- .then(function (toolOptions) {
- return self.before_install(toolOptions);
- })
- .then(function (toolOptions) {
+ .then(toolOptions => this.before_install(toolOptions))
+ .then(toolOptions => {
if (toolOptions.ignore) {
events.emit('verbose', '==== pod install start ====\n');
events.emit('verbose', toolOptions.ignoreMessage);
- return Q.resolve();
+ return Promise.resolve();
} else {
- return superspawn.spawn('pod', ['install', '--verbose'], opts)
- .progress(function (stdio) {
+ return spawn('pod', ['install', '--verbose'], opts)
+ .progress(stdio => {
if (stdio.stderr) { console.error(stdio.stderr); }
if (stdio.stdout) {
if (first) {
@@ -234,11 +410,8 @@ Podfile.prototype.install = function (requirementsCheckerFunction) {
});
}
})
- .then(function () { // done
+ .then(() => { // done
events.emit('verbose', '==== pod install end ====\n');
- })
- .fail(function (error) {
- throw error;
});
};
diff --git a/StoneIsland/platforms/ios/cordova/lib/PodsJson.js b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js
index 04705273..598d9607 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/PodsJson.js
+++ b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js
@@ -17,20 +17,23 @@
under the License.
*/
-var fs = require('fs');
-var path = require('path');
-var util = require('util');
-var events = require('cordova-common').events;
-var CordovaError = require('cordova-common').CordovaError;
+const fs = require('fs-extra');
+const path = require('path');
+const util = require('util');
+const events = require('cordova-common').events;
+const CordovaError = require('cordova-common').CordovaError;
PodsJson.FILENAME = 'pods.json';
+PodsJson.LIBRARY = 'libraries';
+PodsJson.SOURCE = 'sources';
+PodsJson.DECLARATION = 'declarations';
function PodsJson (podsJsonPath) {
this.path = podsJsonPath;
this.contents = null;
this.__dirty = false;
- var filename = this.path.split(path.sep).pop();
+ const filename = this.path.split(path.sep).pop();
if (filename !== PodsJson.FILENAME) {
throw new CordovaError(util.format('PodsJson: The file at %s is not `%s`.', this.path, PodsJson.FILENAME));
}
@@ -43,25 +46,81 @@ function PodsJson (podsJsonPath) {
} else {
events.emit('verbose', 'pods.json found in platforms/ios');
// load contents
- this.contents = fs.readFileSync(this.path, 'utf8');
- this.contents = JSON.parse(this.contents);
+ const contents = fs.readFileSync(this.path, 'utf8');
+ this.contents = JSON.parse(contents);
}
+ this.__updateFormatIfNecessary();
}
-PodsJson.prototype.get = function (name) {
- return this.contents[name];
+PodsJson.prototype.__isOldFormat = function () {
+ if (this.contents !== null) {
+ if (this.contents.declarations === undefined ||
+ this.contents.sources === undefined ||
+ this.contents.libraries === undefined) {
+ return true;
+ }
+ }
+ return false;
};
-PodsJson.prototype.remove = function (name) {
- if (this.contents[name]) {
- delete this.contents[name];
+PodsJson.prototype.__updateFormatIfNecessary = function () {
+ if (this.__isOldFormat()) {
+ this.contents = {
+ declarations: {},
+ sources: {},
+ libraries: this.contents
+ };
this.__dirty = true;
- events.emit('verbose', util.format('Remove from pods.json for `%s`', name));
+ events.emit('verbose', 'Update format of pods.json');
}
};
+PodsJson.prototype.getLibraries = function () {
+ return this.contents[PodsJson.LIBRARY];
+};
+
+PodsJson.prototype.__get = function (kind, name) {
+ return this.contents[kind][name];
+};
+
+PodsJson.prototype.getLibrary = function (name) {
+ return this.__get(PodsJson.LIBRARY, name);
+};
+
+PodsJson.prototype.getSource = function (name) {
+ return this.__get(PodsJson.SOURCE, name);
+};
+
+PodsJson.prototype.getDeclaration = function (name) {
+ return this.__get(PodsJson.DECLARATION, name);
+};
+
+PodsJson.prototype.__remove = function (kind, name) {
+ if (this.contents[kind][name]) {
+ delete this.contents[kind][name];
+ this.__dirty = true;
+ events.emit('verbose', util.format('Remove from pods.json for `%s` - `%s`', name));
+ }
+};
+
+PodsJson.prototype.removeLibrary = function (name) {
+ this.__remove(PodsJson.LIBRARY, name);
+};
+
+PodsJson.prototype.removeSource = function (name) {
+ this.__remove(PodsJson.SOURCE, name);
+};
+
+PodsJson.prototype.removeDeclaration = function (name) {
+ this.__remove(PodsJson.DECLARATION, name);
+};
+
PodsJson.prototype.clear = function () {
- this.contents = {};
+ this.contents = {
+ declarations: {},
+ sources: {},
+ libraries: {}
+ };
this.__dirty = true;
};
@@ -78,34 +137,69 @@ PodsJson.prototype.write = function () {
}
};
-PodsJson.prototype.set = function (name, type, spec, count) {
- this.setJson(name, { name: name, type: type, spec: spec, count: count });
-};
-
-PodsJson.prototype.increment = function (name) {
- var val = this.get(name);
+PodsJson.prototype.__increment = function (kind, name) {
+ const val = this.__get(kind, name);
if (val) {
val.count++;
- this.setJson(val);
}
};
-PodsJson.prototype.decrement = function (name) {
- var val = this.get(name);
+PodsJson.prototype.incrementLibrary = function (name) {
+ this.__increment(PodsJson.LIBRARY, name);
+};
+
+PodsJson.prototype.incrementSource = function (name) {
+ this.__increment(PodsJson.SOURCE, name);
+};
+
+PodsJson.prototype.incrementDeclaration = function (name) {
+ this.__increment(PodsJson.DECLARATION, name);
+};
+
+PodsJson.prototype.__decrement = function (kind, name) {
+ const val = this.__get(kind, name);
if (val) {
val.count--;
if (val.count <= 0) {
- this.remove(name);
- } else {
- this.setJson(val);
+ this.__remove(kind, name);
}
}
};
-PodsJson.prototype.setJson = function (name, json) {
- this.contents[name] = json;
+PodsJson.prototype.decrementLibrary = function (name) {
+ this.__decrement(PodsJson.LIBRARY, name);
+};
+
+PodsJson.prototype.decrementSource = function (name) {
+ this.__decrement(PodsJson.SOURCE, name);
+};
+
+PodsJson.prototype.decrementDeclaration = function (name) {
+ this.__decrement(PodsJson.DECLARATION, name);
+};
+
+PodsJson.prototype.__setJson = function (kind, name, json) {
+ this.contents[kind][name] = Object.assign({}, json);
this.__dirty = true;
- events.emit('verbose', util.format('Set pods.json for `%s`', name));
+ events.emit('verbose', util.format('Set pods.json for `%s` - `%s`', kind, name));
+};
+
+// sample json for library
+// { name: "Eureka", spec: "4.2.0", "swift-version": "4.1", count: 1 }
+PodsJson.prototype.setJsonLibrary = function (name, json) {
+ this.__setJson(PodsJson.LIBRARY, name, json);
+};
+
+// sample json for source
+// { source: "https://github.com/brightcove/BrightcoveSpecs.git", count: 1 }
+PodsJson.prototype.setJsonSource = function (name, json) {
+ this.__setJson(PodsJson.SOURCE, name, json);
+};
+
+// sample json for declaration
+// { declaration: ""}
+PodsJson.prototype.setJsonDeclaration = function (name, json) {
+ this.__setJson(PodsJson.DECLARATION, name, json);
};
PodsJson.prototype.isDirty = function () {
diff --git a/StoneIsland/platforms/ios/cordova/lib/build.js b/StoneIsland/platforms/ios/cordova/lib/build.js
index f51b084c..a7203875 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/build.js
+++ b/StoneIsland/platforms/ios/cordova/lib/build.js
@@ -17,38 +17,51 @@
* under the License.
*/
-var Q = require('q');
-var path = require('path');
-var shell = require('shelljs');
-var spawn = require('./spawn');
-var fs = require('fs');
-var plist = require('plist');
-var util = require('util');
+const path = require('path');
+const which = require('which');
+const {
+ CordovaError,
+ events,
+ superspawn: { spawn }
+} = require('cordova-common');
+const fs = require('fs-extra');
+const plist = require('plist');
+const util = require('util');
-var check_reqs = require('./check_reqs');
-var projectFile = require('./projectFile');
-
-var events = require('cordova-common').events;
-
-var projectPath = path.join(__dirname, '..', '..');
-var projectName = null;
+const check_reqs = require('./check_reqs');
+const projectFile = require('./projectFile');
// These are regular expressions to detect if the user is changing any of the built-in xcodebuildArgs
/* eslint-disable no-useless-escape */
-var buildFlagMatchers = {
- 'xcconfig': /^\-xcconfig\s*(.*)$/,
- 'workspace': /^\-workspace\s*(.*)/,
- 'scheme': /^\-scheme\s*(.*)/,
- 'configuration': /^\-configuration\s*(.*)/,
- 'sdk': /^\-sdk\s*(.*)/,
- 'destination': /^\-destination\s*(.*)/,
- 'archivePath': /^\-archivePath\s*(.*)/,
- 'configuration_build_dir': /^(CONFIGURATION_BUILD_DIR=.*)/,
- 'shared_precomps_dir': /^(SHARED_PRECOMPS_DIR=.*)/
+const buildFlagMatchers = {
+ workspace: /^\-workspace\s*(.*)/,
+ scheme: /^\-scheme\s*(.*)/,
+ configuration: /^\-configuration\s*(.*)/,
+ sdk: /^\-sdk\s*(.*)/,
+ destination: /^\-destination\s*(.*)/,
+ archivePath: /^\-archivePath\s*(.*)/,
+ configuration_build_dir: /^(CONFIGURATION_BUILD_DIR=.*)/,
+ shared_precomps_dir: /^(SHARED_PRECOMPS_DIR=.*)/
};
/* eslint-enable no-useless-escape */
/**
+ * Creates a project object (see projectFile.js/parseProjectFile) from
+ * a project path and name
+ *
+ * @param {*} projectPath
+ * @param {*} projectName
+ */
+function createProjectObject (projectPath, projectName) {
+ const locations = {
+ root: projectPath,
+ pbxproj: path.join(projectPath, `${projectName}.xcodeproj`, 'project.pbxproj')
+ };
+
+ return projectFile.parse(locations);
+}
+
+/**
* Returns a promise that resolves to the default simulator target; the logic here
* matches what `cordova emulate ios` does.
*
@@ -58,13 +71,13 @@ var buildFlagMatchers = {
* @return {Promise}
*/
function getDefaultSimulatorTarget () {
- return require('./list-emulator-build-targets').run()
- .then(function (emulators) {
- var targetEmulator;
+ return require('./listEmulatorBuildTargets').run()
+ .then(emulators => {
+ let targetEmulator;
if (emulators.length > 0) {
targetEmulator = emulators[0];
}
- emulators.forEach(function (emulator) {
+ emulators.forEach(emulator => {
if (emulator.name.indexOf('iPhone') === 0) {
targetEmulator = emulator;
}
@@ -73,120 +86,137 @@ function getDefaultSimulatorTarget () {
});
}
-module.exports.run = function (buildOpts) {
- var emulatorTarget = '';
+module.exports.run = buildOpts => {
+ let emulatorTarget = '';
+ const projectPath = path.join(__dirname, '..', '..');
+ let projectName = '';
buildOpts = buildOpts || {};
if (buildOpts.debug && buildOpts.release) {
- return Q.reject('Cannot specify "debug" and "release" options together.');
+ return Promise.reject(new CordovaError('Cannot specify "debug" and "release" options together.'));
}
if (buildOpts.device && buildOpts.emulator) {
- return Q.reject('Cannot specify "device" and "emulator" options together.');
+ return Promise.reject(new CordovaError('Cannot specify "device" and "emulator" options together.'));
}
if (buildOpts.buildConfig) {
if (!fs.existsSync(buildOpts.buildConfig)) {
- return Q.reject('Build config file does not exist:' + buildOpts.buildConfig);
+ return Promise.reject(new CordovaError(`Build config file does not exist: ${buildOpts.buildConfig}`));
}
- events.emit('log', 'Reading build config file:', path.resolve(buildOpts.buildConfig));
- var contents = fs.readFileSync(buildOpts.buildConfig, 'utf-8');
- var buildConfig = JSON.parse(contents.replace(/^\ufeff/, '')); // Remove BOM
+ events.emit('log', `Reading build config file: ${path.resolve(buildOpts.buildConfig)}`);
+ const contents = fs.readFileSync(buildOpts.buildConfig, 'utf-8');
+ const buildConfig = JSON.parse(contents.replace(/^\ufeff/, '')); // Remove BOM
if (buildConfig.ios) {
- var buildType = buildOpts.release ? 'release' : 'debug';
- var config = buildConfig.ios[buildType];
+ const buildType = buildOpts.release ? 'release' : 'debug';
+ const config = buildConfig.ios[buildType];
if (config) {
- ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType', 'buildFlag', 'iCloudContainerEnvironment'].forEach(
- function (key) {
+ ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType', 'buildFlag', 'iCloudContainerEnvironment', 'automaticProvisioning'].forEach(
+ key => {
buildOpts[key] = buildOpts[key] || config[key];
});
}
}
}
- return require('./list-devices').run()
- .then(function (devices) {
+ return require('./listDevices').run()
+ .then(devices => {
if (devices.length > 0 && !(buildOpts.emulator)) {
// we also explicitly set device flag in options as we pass
// those parameters to other api (build as an example)
buildOpts.device = true;
return check_reqs.check_ios_deploy();
}
- }).then(function () {
+ }).then(() => {
// CB-12287: Determine the device we should target when building for a simulator
if (!buildOpts.device) {
- var newTarget = buildOpts.target || '';
+ let newTarget = buildOpts.target || '';
if (newTarget) {
// only grab the device name, not the runtime specifier
newTarget = newTarget.split(',')[0];
}
// a target was given to us, find the matching Xcode destination name
- var promise = require('./list-emulator-build-targets').targetForSimIdentifier(newTarget);
- return promise.then(function (theTarget) {
+ const promise = require('./listEmulatorBuildTargets').targetForSimIdentifier(newTarget);
+ return promise.then(theTarget => {
if (!theTarget) {
- return getDefaultSimulatorTarget().then(function (defaultTarget) {
+ return getDefaultSimulatorTarget().then(defaultTarget => {
emulatorTarget = defaultTarget.name;
- events.emit('log', 'Building for ' + emulatorTarget + ' Simulator');
+ events.emit('warn', `No simulator found for "${newTarget}. Falling back to the default target.`);
+ events.emit('log', `Building for "${emulatorTarget}" Simulator (${defaultTarget.identifier}, ${defaultTarget.simIdentifier}).`);
return emulatorTarget;
});
} else {
emulatorTarget = theTarget.name;
- events.emit('log', 'Building for ' + emulatorTarget + ' Simulator');
+ events.emit('log', `Building for "${emulatorTarget}" Simulator (${theTarget.identifier}, ${theTarget.simIdentifier}).`);
return emulatorTarget;
}
});
}
- }).then(function () {
- return check_reqs.run();
- }).then(function () {
- return findXCodeProjectIn(projectPath);
- }).then(function (name) {
+ })
+ .then(() => check_reqs.run())
+ .then(() => findXCodeProjectIn(projectPath))
+ .then(name => {
projectName = name;
- var extraConfig = '';
+ let extraConfig = '';
if (buildOpts.codeSignIdentity) {
- extraConfig += 'CODE_SIGN_IDENTITY = ' + buildOpts.codeSignIdentity + '\n';
- extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + buildOpts.codeSignIdentity + '\n';
+ extraConfig += `CODE_SIGN_IDENTITY = ${buildOpts.codeSignIdentity}\n`;
+ extraConfig += `CODE_SIGN_IDENTITY[sdk=iphoneos*] = ${buildOpts.codeSignIdentity}\n`;
}
if (buildOpts.codeSignResourceRules) {
- extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + buildOpts.codeSignResourceRules + '\n';
+ extraConfig += `CODE_SIGN_RESOURCE_RULES_PATH = ${buildOpts.codeSignResourceRules}\n`;
}
if (buildOpts.provisioningProfile) {
- extraConfig += 'PROVISIONING_PROFILE = ' + buildOpts.provisioningProfile + '\n';
+ extraConfig += `PROVISIONING_PROFILE = ${buildOpts.provisioningProfile}\n`;
}
if (buildOpts.developmentTeam) {
- extraConfig += 'DEVELOPMENT_TEAM = ' + buildOpts.developmentTeam + '\n';
+ extraConfig += `DEVELOPMENT_TEAM = ${buildOpts.developmentTeam}\n`;
}
- return Q.nfcall(fs.writeFile, path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8');
- }).then(function () {
- var configuration = buildOpts.release ? 'Release' : 'Debug';
- events.emit('log', 'Building project: ' + path.join(projectPath, projectName + '.xcworkspace'));
- events.emit('log', '\tConfiguration: ' + configuration);
- events.emit('log', '\tPlatform: ' + (buildOpts.device ? 'device' : 'emulator'));
+ function writeCodeSignStyle (value) {
+ const project = createProjectObject(projectPath, projectName);
- var buildOutputDir = path.join(projectPath, 'build', (buildOpts.device ? 'device' : 'emulator'));
+ events.emit('verbose', `Set CODE_SIGN_STYLE Build Property to ${value}.`);
+ project.xcode.updateBuildProperty('CODE_SIGN_STYLE', value);
+ events.emit('verbose', `Set ProvisioningStyle Target Attribute to ${value}.`);
+ project.xcode.addTargetAttribute('ProvisioningStyle', value);
+
+ project.write();
+ }
+
+ if (buildOpts.provisioningProfile) {
+ events.emit('verbose', 'ProvisioningProfile build option set, changing project settings to Manual.');
+ writeCodeSignStyle('Manual');
+ } else if (buildOpts.automaticProvisioning) {
+ events.emit('verbose', 'ProvisioningProfile build option NOT set, changing project settings to Automatic.');
+ writeCodeSignStyle('Automatic');
+ }
+
+ return fs.writeFile(path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8');
+ }).then(() => {
+ const configuration = buildOpts.release ? 'Release' : 'Debug';
+
+ events.emit('log', `Building project: ${path.join(projectPath, `${projectName}.xcworkspace`)}`);
+ events.emit('log', `\tConfiguration: ${configuration}`);
+ events.emit('log', `\tPlatform: ${buildOpts.device ? 'device' : 'emulator'}`);
+ events.emit('log', `\tTarget: ${emulatorTarget}`);
+
+ const buildOutputDir = path.join(projectPath, 'build', (buildOpts.device ? 'device' : 'emulator'));
// remove the build/device folder before building
- return spawn('rm', [ '-rf', buildOutputDir ], projectPath)
- .then(function () {
- var xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag, emulatorTarget);
- return spawn('xcodebuild', xcodebuildArgs, projectPath);
- });
+ fs.removeSync(buildOutputDir);
- }).then(function () {
+ const xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag, emulatorTarget, buildOpts.automaticProvisioning);
+ return spawn('xcodebuild', xcodebuildArgs, { cwd: projectPath, printCommand: true, stdio: 'inherit' });
+ }).then(() => {
if (!buildOpts.device || buildOpts.noSign) {
return;
}
- var locations = {
- root: projectPath,
- pbxproj: path.join(projectPath, projectName + '.xcodeproj', 'project.pbxproj')
- };
-
- var bundleIdentifier = projectFile.parse(locations).getPackageName();
- var exportOptions = {'compileBitcode': false, 'method': 'development'};
+ const project = createProjectObject(projectPath, projectName);
+ const bundleIdentifier = project.getPackageName();
+ const exportOptions = { compileBitcode: false, method: 'development' };
if (buildOpts.packageType) {
exportOptions.method = buildOpts.packageType;
@@ -201,7 +231,7 @@ module.exports.run = function (buildOpts) {
}
if (buildOpts.provisioningProfile && bundleIdentifier) {
- exportOptions.provisioningProfiles = { [ bundleIdentifier ]: String(buildOpts.provisioningProfile) };
+ exportOptions.provisioningProfiles = { [bundleIdentifier]: String(buildOpts.provisioningProfile) };
exportOptions.signingStyle = 'manual';
}
@@ -209,13 +239,13 @@ module.exports.run = function (buildOpts) {
exportOptions.signingCertificate = buildOpts.codeSignIdentity;
}
- var exportOptionsPlist = plist.build(exportOptions);
- var exportOptionsPath = path.join(projectPath, 'exportOptions.plist');
+ const exportOptionsPlist = plist.build(exportOptions);
+ const exportOptionsPath = path.join(projectPath, 'exportOptions.plist');
- var buildOutputDir = path.join(projectPath, 'build', 'device');
+ const buildOutputDir = path.join(projectPath, 'build', 'device');
function checkSystemRuby () {
- var ruby_cmd = shell.which('ruby');
+ const ruby_cmd = which.sync('ruby', { nothrow: true });
if (ruby_cmd !== '/usr/bin/ruby') {
events.emit('warn', 'Non-system Ruby in use. This may cause packaging to fail.\n' +
@@ -225,11 +255,11 @@ module.exports.run = function (buildOpts) {
}
function packageArchive () {
- var xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath);
- return spawn('xcodebuild', xcodearchiveArgs, projectPath);
+ const xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath, buildOpts.automaticProvisioning);
+ return spawn('xcodebuild', xcodearchiveArgs, { cwd: projectPath, printCommand: true, stdio: 'inherit' });
}
- return Q.nfcall(fs.writeFile, exportOptionsPath, exportOptionsPlist, 'utf-8')
+ return fs.writeFile(exportOptionsPath, exportOptionsPlist, 'utf-8')
.then(checkSystemRuby)
.then(packageArchive);
});
@@ -242,20 +272,17 @@ module.exports.run = function (buildOpts) {
*/
function findXCodeProjectIn (projectPath) {
// 'Searching for Xcode project in ' + projectPath);
- var xcodeProjFiles = shell.ls(projectPath).filter(function (name) {
- return path.extname(name) === '.xcodeproj';
- });
+ const xcodeProjFiles = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');
if (xcodeProjFiles.length === 0) {
- return Q.reject('No Xcode project found in ' + projectPath);
+ return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
}
if (xcodeProjFiles.length > 1) {
- events.emit('warn', 'Found multiple .xcodeproj directories in \n' +
- projectPath + '\nUsing first one');
+ events.emit('warn', `Found multiple .xcodeproj directories in \n${projectPath}\nUsing first one`);
}
- var projectName = path.basename(xcodeProjFiles[0], '.xcodeproj');
- return Q.resolve(projectName);
+ const projectName = path.basename(xcodeProjFiles[0], '.xcodeproj');
+ return Promise.resolve(projectName);
}
module.exports.findXCodeProjectIn = findXCodeProjectIn;
@@ -268,21 +295,21 @@ module.exports.findXCodeProjectIn = findXCodeProjectIn;
* @param {Boolean} isDevice Flag that specify target for package (device/emulator)
* @param {Array} buildFlags
* @param {String} emulatorTarget Target for emulator (rather than default)
+ * @param {Boolean} autoProvisioning Whether to allow Xcode to automatically update provisioning
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
-function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, buildFlags, emulatorTarget) {
- var xcodebuildArgs;
- var options;
- var buildActions;
- var settings;
- var customArgs = {};
+function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, buildFlags, emulatorTarget, autoProvisioning) {
+ let options;
+ let buildActions;
+ let settings;
+ const customArgs = {};
customArgs.otherFlags = [];
if (buildFlags) {
if (typeof buildFlags === 'string' || buildFlags instanceof String) {
parseBuildFlag(buildFlags, customArgs);
} else { // buildFlags is an Array of strings
- buildFlags.forEach(function (flag) {
+ buildFlags.forEach(flag => {
parseBuildFlag(flag, customArgs);
});
}
@@ -290,36 +317,38 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b
if (isDevice) {
options = [
- '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-workspace', customArgs.workspace || projectName + '.xcworkspace',
+ '-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
'-configuration', customArgs.configuration || configuration,
'-destination', customArgs.destination || 'generic/platform=iOS',
- '-archivePath', customArgs.archivePath || projectName + '.xcarchive'
+ '-archivePath', customArgs.archivePath || `${projectName}.xcarchive`
];
- buildActions = [ 'archive' ];
+ buildActions = ['archive'];
settings = [
- customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'device'),
- customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ customArgs.configuration_build_dir || `CONFIGURATION_BUILD_DIR=${path.join(projectPath, 'build', 'device')}`,
+ customArgs.shared_precomps_dir || `SHARED_PRECOMPS_DIR=${path.join(projectPath, 'build', 'sharedpch')}`
];
// Add other matched flags to otherFlags to let xcodebuild present an appropriate error.
// This is preferable to just ignoring the flags that the user has passed in.
if (customArgs.sdk) {
customArgs.otherFlags = customArgs.otherFlags.concat(['-sdk', customArgs.sdk]);
}
+
+ if (autoProvisioning) {
+ options = options.concat(['-allowProvisioningUpdates']);
+ }
} else { // emulator
options = [
- '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-workspace', customArgs.project || projectName + '.xcworkspace',
+ '-workspace', customArgs.project || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
'-configuration', customArgs.configuration || configuration,
'-sdk', customArgs.sdk || 'iphonesimulator',
- '-destination', customArgs.destination || 'platform=iOS Simulator,name=' + emulatorTarget
+ '-destination', customArgs.destination || `platform=iOS Simulator,name=${emulatorTarget}`
];
- buildActions = [ 'build' ];
+ buildActions = ['build'];
settings = [
- customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'emulator'),
- customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ customArgs.configuration_build_dir || `CONFIGURATION_BUILD_DIR=${path.join(projectPath, 'build', 'emulator')}`,
+ customArgs.shared_precomps_dir || `SHARED_PRECOMPS_DIR=${path.join(projectPath, 'build', 'sharedpch')}`
];
// Add other matched flags to otherFlags to let xcodebuild present an appropriate error.
// This is preferable to just ignoring the flags that the user has passed in.
@@ -327,8 +356,8 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b
customArgs.otherFlags = customArgs.otherFlags.concat(['-archivePath', customArgs.archivePath]);
}
}
- xcodebuildArgs = options.concat(buildActions).concat(settings).concat(customArgs.otherFlags);
- return xcodebuildArgs;
+
+ return options.concat(buildActions).concat(settings).concat(customArgs.otherFlags);
}
/**
@@ -337,21 +366,22 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, b
* @param {String} projectPath Path to project file. Will be used to set CWD for xcodebuild
* @param {String} outputPath Output directory to contain the IPA
* @param {String} exportOptionsPath Path to the exportOptions.plist file
+ * @param {Boolean} autoProvisioning Whether to allow Xcode to automatically update provisioning
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
-function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath) {
+function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath, autoProvisioning) {
return [
'-exportArchive',
- '-archivePath', projectName + '.xcarchive',
+ '-archivePath', `${projectName}.xcarchive`,
'-exportOptionsPlist', exportOptionsPath,
'-exportPath', outputPath
- ];
+ ].concat(autoProvisioning ? ['-allowProvisioningUpdates'] : []);
}
function parseBuildFlag (buildFlag, args) {
- var matched;
- for (var key in buildFlagMatchers) {
- var found = buildFlag.match(buildFlagMatchers[key]);
+ let matched;
+ for (const key in buildFlagMatchers) {
+ const found = buildFlag.match(buildFlagMatchers[key]);
if (found) {
matched = true;
// found[0] is the whole match, found[1] is the first match in parentheses.
diff --git a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
index 21a22081..33dc684f 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
+++ b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
@@ -19,37 +19,28 @@
'use strict';
-const Q = require('q');
-const shell = require('shelljs');
-const util = require('util');
+const which = require('which');
const versions = require('./versions');
+const { CordovaError } = require('cordova-common');
-const SUPPORTED_OS_PLATFORMS = [ 'darwin' ];
+const SUPPORTED_OS_PLATFORMS = ['darwin'];
-const XCODEBUILD_MIN_VERSION = '7.0.0';
+const XCODEBUILD_MIN_VERSION = '9.0.0';
const XCODEBUILD_NOT_FOUND_MESSAGE =
- 'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store';
+ `Please install version ${XCODEBUILD_MIN_VERSION} or greater from App Store`;
const IOS_DEPLOY_MIN_VERSION = '1.9.2';
const IOS_DEPLOY_NOT_FOUND_MESSAGE =
- 'Please download, build and install version ' + IOS_DEPLOY_MIN_VERSION + ' or greater' +
- ' from https://github.com/phonegap/ios-deploy into your path, or do \'npm install -g ios-deploy\'';
+ `Please download, build and install version ${IOS_DEPLOY_MIN_VERSION} or greater from https://github.com/ios-control/ios-deploy into your path, or do 'npm install -g ios-deploy'`;
-const COCOAPODS_MIN_VERSION = '1.0.1';
-const COCOAPODS_NOT_FOUND_MESSAGE =
- 'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/';
-const COCOAPODS_NOT_SYNCED_MESSAGE =
- 'The CocoaPods repo has not been synced yet, this will take a long time (approximately 500MB as of Sept 2016). Please run `pod setup` first to sync the repo.';
-const COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes
-const COCOAPODS_SYNC_ERROR_MESSAGE =
- 'The CocoaPods repo has been created, but there appears to be a sync error. The repo size should be at least ' + COCOAPODS_SYNCED_MIN_SIZE + '. Please run `pod setup --verbose` to sync the repo.';
-const COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.';
+const COCOAPODS_MIN_VERSION = '1.8.0';
+const COCOAPODS_NOT_FOUND_MESSAGE = `Please install version ${COCOAPODS_MIN_VERSION} or greater from https://cocoapods.org/`;
/**
* Checks if xcode util is available
* @return {Promise} Returns a promise either resolved with xcode version or rejected
*/
-module.exports.run = module.exports.check_xcodebuild = function () {
+module.exports.run = module.exports.check_xcodebuild = () => {
return checkTool('xcodebuild', XCODEBUILD_MIN_VERSION, XCODEBUILD_NOT_FOUND_MESSAGE);
};
@@ -57,81 +48,27 @@ module.exports.run = module.exports.check_xcodebuild = function () {
* Checks if ios-deploy util is available
* @return {Promise} Returns a promise either resolved with ios-deploy version or rejected
*/
-module.exports.check_ios_deploy = function () {
+module.exports.check_ios_deploy = () => {
return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE);
};
-module.exports.check_os = function () {
+module.exports.check_os = () => {
// Build iOS apps available for OSX platform only, so we reject on others platforms
- return os_platform_is_supported() ?
- Q.resolve(process.platform) :
- Q.reject('Cordova tooling for iOS requires Apple macOS');
+ return os_platform_is_supported()
+ ? Promise.resolve(process.platform)
+ : Promise.reject(new CordovaError('Cordova tooling for iOS requires Apple macOS'));
};
function os_platform_is_supported () {
return (SUPPORTED_OS_PLATFORMS.indexOf(process.platform) !== -1);
}
-function check_cocoapod_tool (toolChecker) {
- toolChecker = toolChecker || checkTool;
- if (os_platform_is_supported()) { // CB-12856
- return toolChecker('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods');
- } else {
- return Q.resolve({
- 'ignore': true,
- 'ignoreMessage': `CocoaPods check and installation ignored on ${process.platform}`
- });
- }
-}
-
/**
- * Checks if cocoapods repo size is what is expected
+ * Checks if cocoapods is available.
* @return {Promise} Returns a promise either resolved or rejected
*/
-module.exports.check_cocoapods_repo_size = function () {
- return check_cocoapod_tool()
- .then(function (toolOptions) {
- // check size of ~/.cocoapods repo
- let commandString = util.format('du -sh %s/.cocoapods', process.env.HOME);
- let command = shell.exec(commandString, { silent: true });
- // command.output is e.g "750M path/to/.cocoapods", we just scan the number
- let size = toolOptions.ignore ? 0 : parseFloat(command.output);
-
- if (toolOptions.ignore || command.code === 0) { // success, parse output
- return Q.resolve(size, toolOptions);
- } else { // error, perhaps not found
- return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output));
- }
- })
- .then(function (repoSize, toolOptions) {
- if (toolOptions.ignore || COCOAPODS_SYNCED_MIN_SIZE <= repoSize) { // success, expected size
- return Q.resolve(toolOptions);
- } else {
- return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE);
- }
- });
-};
-
-/**
- * Checks if cocoapods is available, and whether the repo is synced (because it takes a long time to download)
- * @return {Promise} Returns a promise either resolved or rejected
- */
-module.exports.check_cocoapods = function (toolChecker) {
- return check_cocoapod_tool(toolChecker)
- // check whether the cocoapods repo has been synced through `pod repo` command
- // a value of '0 repos' means it hasn't been synced
- .then(function (toolOptions) {
- let code = shell.exec('pod repo | grep -e "^0 repos"', { silent: true }).code;
- let repoIsSynced = (code !== 0);
-
- if (toolOptions.ignore || repoIsSynced) {
- // return check_cocoapods_repo_size();
- // we could check the repo size above, but it takes too long.
- return Q.resolve(toolOptions);
- } else {
- return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE);
- }
- });
+module.exports.check_cocoapods = toolChecker => {
+ return checkTool('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods');
};
/**
@@ -146,18 +83,17 @@ function checkTool (tool, minVersion, message, toolFriendlyName) {
toolFriendlyName = toolFriendlyName || tool;
// Check whether tool command is available at all
- let tool_command = shell.which(tool);
+ const tool_command = which.sync(tool, { nothrow: true });
if (!tool_command) {
- return Q.reject(toolFriendlyName + ' was not found. ' + (message || ''));
+ return Promise.reject(new CordovaError(`${toolFriendlyName} was not found. ${message || ''}`));
}
// check if tool version is greater than specified one
- return versions.get_tool_version(tool).then(function (version) {
+ return versions.get_tool_version(tool).then(version => {
version = version.trim();
- return versions.compareVersions(version, minVersion) >= 0 ?
- Q.resolve({ 'version': version }) :
- Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion +
- ' or greater, you have version ' + version + '. ' + (message || ''));
+ return versions.compareVersions(version, minVersion) >= 0
+ ? Promise.resolve({ version })
+ : Promise.reject(new CordovaError(`Cordova needs ${toolFriendlyName} version ${minVersion} or greater, you have version ${version}. ${message || ''}`));
});
}
@@ -168,7 +104,7 @@ function checkTool (tool, minVersion, message, toolFriendlyName) {
* @param {Boolean} isFatal Marks the requirement as fatal. If such requirement will fail
* next requirements' checks will be skipped.
*/
-let Requirement = function (id, name, isFatal) {
+const Requirement = function (id, name, isFatal) {
this.id = id;
this.name = name;
this.installed = false;
@@ -182,8 +118,7 @@ let Requirement = function (id, name, isFatal) {
*
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
*/
-module.exports.check_all = function () {
-
+module.exports.check_all = () => {
const requirements = [
new Requirement('os', 'Apple macOS', true),
new Requirement('xcode', 'Xcode'),
@@ -191,10 +126,10 @@ module.exports.check_all = function () {
new Requirement('CocoaPods', 'CocoaPods')
];
- let result = [];
+ const result = [];
let fatalIsHit = false;
- let checkFns = [
+ const checkFns = [
module.exports.check_os,
module.exports.check_xcodebuild,
module.exports.check_ios_deploy,
@@ -202,27 +137,25 @@ module.exports.check_all = function () {
];
// Then execute requirement checks one-by-one
- return checkFns.reduce(function (promise, checkFn, idx) {
- return promise.then(function () {
+ return checkFns.reduce((promise, checkFn, idx) => {
+ return promise.then(() => {
// If fatal requirement is failed,
// we don't need to check others
- if (fatalIsHit) return Q();
+ if (fatalIsHit) return Promise.resolve();
- let requirement = requirements[idx];
+ const requirement = requirements[idx];
return checkFn()
- .then(function (version) {
+ .then(version => {
requirement.installed = true;
requirement.metadata.version = version;
result.push(requirement);
- }, function (err) {
+ }, err => {
if (requirement.isFatal) fatalIsHit = true;
requirement.metadata.reason = err;
result.push(requirement);
});
});
- }, Q())
- .then(function () {
- // When chain is completed, return requirements array to upstream API
- return result;
- });
+ }, Promise.resolve())
+ // When chain is completed, return requirements array to upstream API
+ .then(() => result);
};
diff --git a/StoneIsland/platforms/ios/cordova/lib/clean.js b/StoneIsland/platforms/ios/cordova/lib/clean.js
index 20e8ac66..72aac0ba 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/clean.js
+++ b/StoneIsland/platforms/ios/cordova/lib/clean.js
@@ -17,26 +17,31 @@
* under the License.
*/
-var Q = require('q');
-var path = require('path');
-var shell = require('shelljs');
-var spawn = require('./spawn');
+const path = require('path');
+const fs = require('fs-extra');
+const {
+ CordovaError,
+ superspawn: { spawn }
+} = require('cordova-common');
-var projectPath = path.join(__dirname, '..', '..');
+const projectPath = path.join(__dirname, '..', '..');
-module.exports.run = function () {
- var projectName = shell.ls(projectPath).filter(function (name) {
- return path.extname(name) === '.xcodeproj';
- })[0];
+module.exports.run = () => {
+ const projectName = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');
if (!projectName) {
- return Q.reject('No Xcode project found in ' + projectPath);
+ return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
}
- return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Debug', '-alltargets', 'clean'], projectPath)
- .then(function () {
- return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Release', '-alltargets', 'clean'], projectPath);
- }).then(function () {
- return shell.rm('-rf', path.join(projectPath, 'build'));
- });
+ const xcodebuildClean = configName => {
+ return spawn(
+ 'xcodebuild',
+ ['-project', projectName, '-configuration', configName, '-alltargets', 'clean'],
+ { cwd: projectPath, printCommand: true, stdio: 'inherit' }
+ );
+ };
+
+ return xcodebuildClean('Debug')
+ .then(() => xcodebuildClean('Release'))
+ .then(() => fs.removeSync(path.join(projectPath, 'build')));
};
diff --git a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js b/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js
deleted file mode 100755
index e05aacf2..00000000
--- a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env node
-
-/*
- 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.
-*/
-
-// This script copies the www directory into the Xcode project.
-
-// This script should not be called directly.
-// It is called as a build step from Xcode.
-
-var BUILT_PRODUCTS_DIR = process.env.BUILT_PRODUCTS_DIR;
-var FULL_PRODUCT_NAME = process.env.FULL_PRODUCT_NAME;
-var COPY_HIDDEN = process.env.COPY_HIDDEN;
-var PROJECT_FILE_PATH = process.env.PROJECT_FILE_PATH;
-
-var path = require('path');
-var fs = require('fs');
-var shell = require('shelljs');
-var srcDir = 'www';
-var dstDir = path.join(BUILT_PRODUCTS_DIR, FULL_PRODUCT_NAME);
-var dstWwwDir = path.join(dstDir, 'www');
-
-if (!BUILT_PRODUCTS_DIR) {
- console.error('The script is meant to be run as an Xcode build step and relies on env variables set by Xcode.');
- process.exit(1);
-}
-
-try {
- fs.statSync(srcDir);
-} catch (e) {
- console.error('Path does not exist: ' + srcDir);
- process.exit(2);
-}
-
-// Code signing files must be removed or else there are
-// resource signing errors.
-shell.rm('-rf', dstWwwDir);
-shell.rm('-rf', path.join(dstDir, '_CodeSignature'));
-shell.rm('-rf', path.join(dstDir, 'PkgInfo'));
-shell.rm('-rf', path.join(dstDir, 'embedded.mobileprovision'));
-
-// Copy www dir recursively
-var code;
-if (COPY_HIDDEN) {
- code = shell.exec('rsync -Lra "' + srcDir + '" "' + dstDir + '"').code;
-} else {
- code = shell.exec('rsync -Lra --exclude="- .*" "' + srcDir + '" "' + dstDir + '"').code;
-}
-
-if (code !== 0) {
- console.error('Error occured on copying www. Code: ' + code);
- process.exit(3);
-}
-
-// Copy the config.xml file.
-shell.cp('-f', path.join(path.dirname(PROJECT_FILE_PATH), path.basename(PROJECT_FILE_PATH, '.xcodeproj'), 'config.xml'),
- dstDir);
diff --git a/StoneIsland/platforms/ios/cordova/lib/list-devices b/StoneIsland/platforms/ios/cordova/lib/list-devices
index 047d5950..5f89e21b 100755
--- a/StoneIsland/platforms/ios/cordova/lib/list-devices
+++ b/StoneIsland/platforms/ios/cordova/lib/list-devices
@@ -19,49 +19,10 @@
under the License.
*/
+const { run } = require('./listDevices');
-var Q = require('q'),
- exec = require('child_process').exec;
-
-/**
- * Gets list of connected iOS devices
- * @return {Promise} Promise fulfilled with list of available iOS devices
- */
-function listDevices() {
- var commands = [
- Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPad/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPad"}\''),
- Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPhone/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPhone"}\''),
- Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPod/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPod"}\'')
- ];
-
- // wrap al lexec calls into promises and wait until they're fullfilled
- return Q.all(commands).then(function (results) {
- var accumulator = [];
- results.forEach(function (result) {
- var devicefound;
- // Each command promise resolves with array [stout, stderr], and we need stdout only
- // Append stdout lines to accumulator
- devicefound = result[0].trim().split('\n');
- if(devicefound && devicefound.length) {
- devicefound.forEach(function(device) {
- if (device) {
- accumulator.push(device);
- }
- });
- }
- });
- return accumulator;
- });
-}
-
-exports.run = listDevices;
-
-// Check if module is started as separate script.
-// If so, then invoke main method and print out results.
-if (!module.parent) {
- listDevices().then(function (devices) {
- devices.forEach(function (device) {
- console.log(device);
- });
+run().then(devices => {
+ devices.forEach(device => {
+ console.log(device);
});
-} \ No newline at end of file
+});
diff --git a/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets b/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets
index ccf61f98..304c4c17 100755
--- a/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets
+++ b/StoneIsland/platforms/ios/cordova/lib/list-emulator-build-targets
@@ -19,99 +19,8 @@
under the License.
*/
+const { run } = require('./listEmulatorBuildTargets');
-var Q = require('q'),
- exec = require('child_process').exec;
-
-/**
- * Returns a list of available simulator build targets of the form
- *
- * [
- * { name: <xcode-destination-name>,
- * identifier: <simctl-identifier>,
- * simIdentifier: <cordova emulate target>
- * }
- * ]
- *
- */
-function listEmulatorBuildTargets () {
- return Q.nfcall(exec, 'xcrun simctl list --json')
- .then(function(stdio) {
- return JSON.parse(stdio[0]);
- })
- .then(function(simInfo) {
- var devices = simInfo.devices;
- var deviceTypes = simInfo.devicetypes;
- return deviceTypes.reduce(function (typeAcc, deviceType) {
- if (!deviceType.name.match(/^[iPad|iPhone]/)) {
- // ignore targets we don't support (like Apple Watch or Apple TV)
- return typeAcc;
- }
- var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) {
- var availableDevicesInCategory = devices[deviceCategory];
- availableDevicesInCategory.forEach(function (device) {
- if (device && device.name === deviceType.name.replace(/\-inch/g, ' inch') && device.isAvailable == true) {
- availAcc.push(device);
- }
- });
- return availAcc;
- }, []);
-
- // var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) {
- // var availableDevicesInCategory = devices[deviceCategory];
- // availableDevicesInCategory.forEach(function (device) {
- // if (device.name === deviceType.name.replace(/\-inch/g, ' inch') &&
- // device.availability.toLowerCase().indexOf('unavailable') < 0) {
- // availAcc.push(device);
- // }
- // });
- // return availAcc;
- //}, []);
- // we only want device types that have at least one available device
- // (regardless of OS); this filters things out like iPhone 4s, which
- // is present in deviceTypes, but probably not available on the user's
- // system.
- if (availableDevices.length > 0) {
- typeAcc.push(deviceType);
- }
- return typeAcc;
- }, []);
- })
- .then(function(filteredTargets) {
- // the simIdentifier, or cordova emulate target name, is the very last part
- // of identifier.
- return filteredTargets.map(function (target) {
- var identifierPieces = target.identifier.split(".");
- target.simIdentifier = identifierPieces[identifierPieces.length-1];
- return target;
- });
- });
-}
-
-exports.run = listEmulatorBuildTargets;
-
-/**
- * Given a simIdentifier, return the matching target.
- *
- * @param {string} simIdentifier a target, like "iPhone-SE"
- * @return {Object} the matching target, or undefined if no match
- */
-exports.targetForSimIdentifier = function(simIdentifier) {
- return listEmulatorBuildTargets()
- .then(function(targets) {
- return targets.reduce(function(acc, target) {
- if (!acc && target.simIdentifier.toLowerCase() === simIdentifier.toLowerCase()) {
- acc = target;
- }
- return acc;
- }, undefined);
- });
-}
-
-// Check if module is started as separate script.
-// If so, then invoke main method and print out results.
-if (!module.parent) {
- listEmulatorBuildTargets().then(function (targets) {
- console.log(JSON.stringify(targets, null, 2));
- });
-}
+run().then(targets => {
+ console.log(JSON.stringify(targets, null, 2));
+});
diff --git a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
index d8be5766..db9b72af 100755
--- a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
+++ b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
@@ -19,29 +19,10 @@
under the License.
*/
+const { run } = require('./listEmulatorImages');
-var Q = require('q'),
- iossim = require('ios-sim'),
- exec = require('child_process').exec,
- check_reqs = require('./check_reqs');
-
-/**
- * Gets list of iOS devices available for simulation
- * @return {Promise} Promise fulfilled with list of devices available for simulation
- */
-function listEmulatorImages () {
- return Q.resolve(iossim.getdevicetypes());
-}
-
-
-exports.run = listEmulatorImages;
-
-// Check if module is started as separate script.
-// If so, then invoke main method and print out results.
-if (!module.parent) {
- listEmulatorImages().then(function (names) {
- names.forEach(function (name) {
- console.log(name);
- });
+run().then(names => {
+ names.forEach(name => {
+ console.log(name);
});
-}
+});
diff --git a/StoneIsland/platforms/ios/cordova/lib/list-started-emulators b/StoneIsland/platforms/ios/cordova/lib/list-started-emulators
index 710fa2f7..7f06cf2e 100755
--- a/StoneIsland/platforms/ios/cordova/lib/list-started-emulators
+++ b/StoneIsland/platforms/ios/cordova/lib/list-started-emulators
@@ -19,32 +19,10 @@
under the License.
*/
+const { run } = require('./listStartedEmulators');
-var Q = require('q'),
- exec = require('child_process').exec;
-
-/**
- * Gets list of running iOS simulators
- * @return {Promise} Promise fulfilled with list of running iOS simulators
- */
-function listStartedEmulators () {
- // wrap exec call into promise
- return Q.nfcall(exec, 'ps aux | grep -i "[i]OS Simulator"')
- .then(function () {
- return Q.nfcall(exec, 'defaults read com.apple.iphonesimulator "SimulateDevice"');
- }).then(function (stdio) {
- return stdio[0].trim().split('\n');
- });
-}
-
-exports.run = listStartedEmulators;
-
-// Check if module is started as separate script.
-// If so, then invoke main method and print out results.
-if (!module.parent) {
- listStartedEmulators().then(function (emulators) {
- emulators.forEach(function (emulator) {
- console.log(emulator);
- });
+run().then(emulators => {
+ emulators.forEach(emulator => {
+ console.log(emulator);
});
-}
+});
diff --git a/StoneIsland/platforms/ios/cordova/lib/listDevices.js b/StoneIsland/platforms/ios/cordova/lib/listDevices.js
new file mode 100644
index 00000000..86a67ffb
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/listDevices.js
@@ -0,0 +1,42 @@
+/*
+ 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.
+*/
+
+const { superspawn: { spawn } } = require('cordova-common');
+
+const DEVICE_REGEX = /-o (iPhone|iPad|iPod)@.*?"USB Serial Number" = "([^"]*)"/gs;
+
+/**
+ * Gets list of connected iOS devices
+ * @return {Promise} Promise fulfilled with list of available iOS devices
+ */
+function listDevices () {
+ return spawn('ioreg', ['-p', 'IOUSB', '-l'])
+ .then(output => {
+ return [...matchAll(output, DEVICE_REGEX)]
+ .map(m => m.slice(1).reverse().join(' '));
+ });
+}
+
+// TODO: Should be replaced with String#matchAll once available
+function * matchAll (s, r) {
+ let match;
+ while ((match = r.exec(s))) yield match;
+}
+
+exports.run = listDevices;
diff --git a/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js b/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js
new file mode 100644
index 00000000..73e35c05
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/listEmulatorBuildTargets.js
@@ -0,0 +1,95 @@
+/*
+ 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.
+*/
+
+const { superspawn: { spawn } } = require('cordova-common');
+
+/**
+ * Returns a list of available simulator build targets of the form
+ *
+ * [
+ * { name: <xcode-destination-name>,
+ * identifier: <simctl-identifier>,
+ * simIdentifier: <cordova emulate target>
+ * }
+ * ]
+ *
+ */
+function listEmulatorBuildTargets () {
+ return spawn('xcrun', ['simctl', 'list', '--json'])
+ .then(output => JSON.parse(output))
+ .then(function (simInfo) {
+ var devices = simInfo.devices;
+ var deviceTypes = simInfo.devicetypes;
+ return deviceTypes.reduce(function (typeAcc, deviceType) {
+ if (!deviceType.name.match(/^[iPad|iPhone]/)) {
+ // ignore targets we don't support (like Apple Watch or Apple TV)
+ return typeAcc;
+ }
+ var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) {
+ var availableDevicesInCategory = devices[deviceCategory];
+ availableDevicesInCategory.forEach(function (device) {
+ if (device.name === deviceType.name || device.name === deviceType.name.replace(/-inch/g, ' inch')) {
+ // Check new flag isAvailable (XCode 10.1+) or legacy string availability (XCode 10 and lower)
+ if (device.isAvailable || (device.availability && device.availability.toLowerCase().indexOf('unavailable') < 0)) {
+ availAcc.push(device);
+ }
+ }
+ });
+ return availAcc;
+ }, []);
+ // we only want device types that have at least one available device
+ // (regardless of OS); this filters things out like iPhone 4s, which
+ // is present in deviceTypes, but probably not available on the user's
+ // system.
+ if (availableDevices.length > 0) {
+ typeAcc.push(deviceType);
+ }
+ return typeAcc;
+ }, []);
+ })
+ .then(function (filteredTargets) {
+ // the simIdentifier, or cordova emulate target name, is the very last part
+ // of identifier.
+ return filteredTargets.map(function (target) {
+ var identifierPieces = target.identifier.split('.');
+ target.simIdentifier = identifierPieces[identifierPieces.length - 1];
+ return target;
+ });
+ });
+}
+
+exports.run = listEmulatorBuildTargets;
+
+/**
+ * Given a simIdentifier, return the matching target.
+ *
+ * @param {string} simIdentifier a target, like "iPhone-SE"
+ * @return {Object} the matching target, or undefined if no match
+ */
+exports.targetForSimIdentifier = function (simIdentifier) {
+ return listEmulatorBuildTargets()
+ .then(function (targets) {
+ return targets.reduce(function (acc, target) {
+ if (!acc && target.simIdentifier.toLowerCase() === simIdentifier.toLowerCase()) {
+ acc = target;
+ }
+ return acc;
+ }, undefined);
+ });
+};
diff --git a/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js b/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js
new file mode 100644
index 00000000..09e14340
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/listEmulatorImages.js
@@ -0,0 +1,30 @@
+/*
+ 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 iossim = require('ios-sim');
+
+/**
+ * Gets list of iOS devices available for simulation
+ * @return {Promise} Promise fulfilled with list of devices available for simulation
+ */
+function listEmulatorImages () {
+ return Promise.resolve(iossim.getdevicetypes());
+}
+
+exports.run = listEmulatorImages;
diff --git a/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js b/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js
new file mode 100644
index 00000000..ec1cb7f2
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/listStartedEmulators.js
@@ -0,0 +1,50 @@
+/*
+ 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.
+*/
+
+const { superspawn: { spawn } } = require('cordova-common');
+
+/**
+ * Gets list of running iOS simulators
+ * @return {Promise} Promise fulfilled with list of running iOS simulators
+ *
+ * @todo In the next PR, I will refactor this entire method.
+ *
+ * The process no longer contains the pattern "[i]OS Simulator".
+ * The process is now called "Simulator.app"
+ *
+ * Additionaly, `defaults read com.apple.iphonesimulator "SimulateDevice"` is also not valid aymore.
+ *
+ * I will replace this entire method to locate the active simulators though `simctl`
+ *
+ * Alternativly, remove this file. It is not documented in Cordova and not used anywhere in our code base.
+ */
+function listStartedEmulators () {
+ // wrap exec call into promise
+ return spawn('ps', ['aux'])
+ .then(output => {
+ if (output.match(/[i]OS Simulator/)) {
+ return spawn('defaults', ['read', 'com.apple.iphonesimulator', '"SimulateDevice"']);
+ }
+
+ return '';
+ })
+ .then(output => output.split('\n'));
+}
+
+exports.run = listStartedEmulators;
diff --git a/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js
index 1f6920fa..09d5ae51 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js
+++ b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js
@@ -15,21 +15,20 @@
under the License.
*/
'use strict';
-var fs = require('fs');
-var path = require('path');
-var shell = require('shelljs');
-var util = require('util');
-var events = require('cordova-common').events;
-var CordovaError = require('cordova-common').CordovaError;
+const fs = require('fs-extra');
+const path = require('path');
+const util = require('util');
+const events = require('cordova-common').events;
+const CordovaError = require('cordova-common').CordovaError;
// These frameworks are required by cordova-ios by default. We should never add/remove them.
-var keep_these_frameworks = [
+const keep_these_frameworks = [
'MobileCoreServices.framework',
'CoreGraphics.framework',
'AssetsLibrary.framework'
];
-var handlers = {
+const handlers = {
'source-file': {
install: function (obj, plugin, project, options) {
installHelper('source-file', obj, plugin.dir, project.projectDir, plugin.id, options, project);
@@ -48,47 +47,47 @@ var handlers = {
},
'resource-file': {
install: function (obj, plugin, project, options) {
- var src = obj.src;
- var target = obj.target;
- var srcFile = path.resolve(plugin.dir, src);
+ const src = obj.src;
+ let target = obj.target;
+ const srcFile = path.resolve(plugin.dir, src);
if (!target) {
target = path.basename(src);
}
- var destFile = path.resolve(project.resources_dir, target);
+ const destFile = path.resolve(project.resources_dir, target);
if (!fs.existsSync(srcFile)) {
- throw new CordovaError('Cannot find resource file "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform');
+ throw new CordovaError(`Cannot find resource file "${srcFile}" for plugin ${plugin.id} in iOS platform`);
}
if (fs.existsSync(destFile)) {
- throw new CordovaError('File already exists at destination "' + destFile + '" for resource file specified by plugin ' + plugin.id + ' in iOS platform');
+ throw new CordovaError(`File already exists at destination "${destFile}" for resource file specified by plugin ${plugin.id} in iOS platform`);
}
project.xcode.addResourceFile(path.join('Resources', target));
- var link = !!(options && options.link);
+ const link = !!(options && options.link);
copyFile(plugin.dir, src, project.projectDir, destFile, link);
},
uninstall: function (obj, plugin, project, options) {
- var src = obj.src;
- var target = obj.target;
+ const src = obj.src;
+ let target = obj.target;
if (!target) {
target = path.basename(src);
}
- var destFile = path.resolve(project.resources_dir, target);
+ const destFile = path.resolve(project.resources_dir, target);
project.xcode.removeResourceFile(path.join('Resources', target));
- shell.rm('-rf', destFile);
+ fs.removeSync(destFile);
}
},
- 'framework': { // CB-5238 custom frameworks only
+ framework: { // CB-5238 custom frameworks only
install: function (obj, plugin, project, options) {
- var src = obj.src;
- var custom = !!(obj.custom); // convert to boolean (if truthy/falsy)
- var embed = !!(obj.embed); // convert to boolean (if truthy/falsy)
- var link = !embed; // either link or embed can be true, but not both. the other has to be false
+ const src = obj.src;
+ const custom = !!(obj.custom); // convert to boolean (if truthy/falsy)
+ const embed = !!(obj.embed); // convert to boolean (if truthy/falsy)
+ const link = !embed; // either link or embed can be true, but not both. the other has to be false
if (!custom) {
- var keepFrameworks = keep_these_frameworks;
+ const keepFrameworks = keep_these_frameworks;
if (keepFrameworks.indexOf(src) < 0) {
if (obj.type === 'podspec') {
@@ -96,7 +95,7 @@ var handlers = {
} else {
project.frameworks[src] = project.frameworks[src] || 0;
project.frameworks[src]++;
- let opt = { customFramework: false, embed: false, link: true, weak: obj.weak };
+ const opt = { customFramework: false, embed: false, link: true, weak: obj.weak };
events.emit('verbose', util.format('Adding non-custom framework to project... %s -> %s', src, JSON.stringify(opt)));
project.xcode.addFramework(src, opt);
events.emit('verbose', util.format('Non-custom framework added to project. %s -> %s', src, JSON.stringify(opt)));
@@ -104,41 +103,32 @@ var handlers = {
}
return;
}
- var srcFile = path.resolve(plugin.dir, src);
- var targetDir = path.resolve(project.plugins_dir, plugin.id, path.basename(src));
- if (!fs.existsSync(srcFile)) throw new CordovaError('Cannot find framework "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform');
- if (fs.existsSync(targetDir)) throw new CordovaError('Framework "' + targetDir + '" for plugin ' + plugin.id + ' already exists in iOS platform');
- var symlink = !!(options && options.link);
+ const srcFile = path.resolve(plugin.dir, src);
+ const targetDir = path.resolve(project.plugins_dir, plugin.id, path.basename(src));
+ if (!fs.existsSync(srcFile)) throw new CordovaError(`Cannot find framework "${srcFile}" for plugin ${plugin.id} in iOS platform`);
+ if (fs.existsSync(targetDir)) throw new CordovaError(`Framework "${targetDir}" for plugin ${plugin.id} already exists in iOS platform`);
+ const symlink = !!(options && options.link);
copyFile(plugin.dir, src, project.projectDir, targetDir, symlink); // frameworks are directories
// CB-10773 translate back slashes to forward on win32
- var project_relative = fixPathSep(path.relative(project.projectDir, targetDir));
+ const project_relative = fixPathSep(path.relative(project.projectDir, targetDir));
// CB-11233 create Embed Frameworks Build Phase if does not exist
- var existsEmbedFrameworks = project.xcode.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks');
+ const existsEmbedFrameworks = project.xcode.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks');
if (!existsEmbedFrameworks && embed) {
events.emit('verbose', '"Embed Frameworks" Build Phase (Embedded Binaries) does not exist, creating it.');
project.xcode.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', null, 'frameworks');
}
- let opt = { customFramework: true, embed: embed, link: link, sign: true };
+ const opt = { customFramework: true, embed, link, sign: true };
events.emit('verbose', util.format('Adding custom framework to project... %s -> %s', src, JSON.stringify(opt)));
project.xcode.addFramework(project_relative, opt);
events.emit('verbose', util.format('Custom framework added to project. %s -> %s', src, JSON.stringify(opt)));
},
uninstall: function (obj, plugin, project, options) {
- var src = obj.src;
+ const src = obj.src;
if (!obj.custom) { // CB-9825 cocoapod integration for plugins
- var keepFrameworks = keep_these_frameworks;
+ const keepFrameworks = keep_these_frameworks;
if (keepFrameworks.indexOf(src) < 0) {
- if (obj.type === 'podspec') {
- var podsJSON = require(path.join(project.projectDir, 'pods.json'));
- if (podsJSON[src]) {
- if (podsJSON[src].count > 1) {
- podsJSON[src].count = podsJSON[src].count - 1;
- } else {
- delete podsJSON[src];
- }
- }
- } else {
+ if (obj.type !== 'podspec') {
// this should be refactored
project.frameworks[src] = project.frameworks[src] || 1;
project.frameworks[src]--;
@@ -153,12 +143,12 @@ var handlers = {
return;
}
- var targetDir = fixPathSep(path.resolve(project.plugins_dir, plugin.id, path.basename(src)));
- var pbxFile = project.xcode.removeFramework(targetDir, {customFramework: true});
+ const targetDir = fixPathSep(path.resolve(project.plugins_dir, plugin.id, path.basename(src)));
+ const pbxFile = project.xcode.removeFramework(targetDir, { customFramework: true });
if (pbxFile) {
project.xcode.removeFromPbxEmbedFrameworksBuildPhase(pbxFile);
}
- shell.rm('-rf', targetDir);
+ fs.removeSync(targetDir);
}
},
'lib-file': {
@@ -169,7 +159,7 @@ var handlers = {
events.emit('verbose', '<lib-file> uninstall is not supported for iOS plugins');
}
},
- 'asset': {
+ asset: {
install: function (obj, plugin, project, options) {
if (!obj.src) {
throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
@@ -182,7 +172,7 @@ var handlers = {
if (options && options.usePlatformWww) copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
},
uninstall: function (obj, plugin, project, options) {
- var target = obj.target;
+ const target = obj.target;
if (!target) {
throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
@@ -199,58 +189,58 @@ var handlers = {
'js-module': {
install: function (obj, plugin, project, options) {
// Copy the plugin's files into the www directory.
- var moduleSource = path.resolve(plugin.dir, obj.src);
- var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src)));
+ const moduleSource = path.resolve(plugin.dir, obj.src);
+ const moduleName = `${plugin.id}.${obj.name || path.basename(obj.src, path.extname(obj.src))}`;
// Read in the file, prepend the cordova.define, and write it back out.
- var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+ let scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
if (moduleSource.match(/.*\.json$/)) {
- scriptContent = 'module.exports = ' + scriptContent;
+ scriptContent = `module.exports = ${scriptContent}`;
}
- scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
+ scriptContent = `cordova.define("${moduleName}", function(require, exports, module) {\n${scriptContent}\n});\n`;
- var moduleDestination = path.resolve(project.www, 'plugins', plugin.id, obj.src);
- shell.mkdir('-p', path.dirname(moduleDestination));
+ const moduleDestination = path.resolve(project.www, 'plugins', plugin.id, obj.src);
+ fs.ensureDirSync(path.dirname(moduleDestination));
fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
if (options && options.usePlatformWww) {
- var platformWwwDestination = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
- shell.mkdir('-p', path.dirname(platformWwwDestination));
+ const platformWwwDestination = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
+ fs.ensureDirSync(path.dirname(platformWwwDestination));
fs.writeFileSync(platformWwwDestination, scriptContent, 'utf-8');
}
},
uninstall: function (obj, plugin, project, options) {
- var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
+ const pluginRelativePath = path.join('plugins', plugin.id, obj.src);
removeFileAndParents(project.www, pluginRelativePath);
if (options && options.usePlatformWww) removeFileAndParents(project.platformWww, pluginRelativePath);
}
}
};
-module.exports.getInstaller = function (type) {
+module.exports.getInstaller = type => {
if (handlers[type] && handlers[type].install) {
return handlers[type].install;
}
- events.emit('warn', '<' + type + '> is not supported for iOS plugins');
+ events.emit('warn', `<${type}> is not supported for iOS plugins`);
};
-module.exports.getUninstaller = function (type) {
+module.exports.getUninstaller = type => {
if (handlers[type] && handlers[type].uninstall) {
return handlers[type].uninstall;
}
- events.emit('warn', '<' + type + '> is not supported for iOS plugins');
+ events.emit('warn', `<${type}> is not supported for iOS plugins`);
};
function installHelper (type, obj, plugin_dir, project_dir, plugin_id, options, project) {
- var srcFile = path.resolve(plugin_dir, obj.src);
- var targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || '');
- var destFile = path.join(targetDir, path.basename(obj.src));
+ const srcFile = path.resolve(plugin_dir, obj.src);
+ const targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || '');
+ const destFile = path.join(targetDir, path.basename(obj.src));
- var project_ref;
- var link = !!(options && options.link);
+ let project_ref;
+ const link = !!(options && options.link);
if (link) {
- var trueSrc = fs.realpathSync(srcFile);
+ const trueSrc = fs.realpathSync(srcFile);
// Create a symlink in the expected place, so that uninstall can use it.
if (options && options.force) {
copyFile(plugin_dir, trueSrc, project_dir, destFile, link);
@@ -261,101 +251,98 @@ function installHelper (type, obj, plugin_dir, project_dir, plugin_id, options,
// Make the Xcode reference the file directly.
// Note: Can't use path.join() here since it collapses 'Plugins/..', and xcode
// library special-cases Plugins/ prefix.
- project_ref = 'Plugins/' + fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc));
+ project_ref = `Plugins/${fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc))}`;
} else {
if (options && options.force) {
copyFile(plugin_dir, srcFile, project_dir, destFile, link);
} else {
copyNewFile(plugin_dir, srcFile, project_dir, destFile, link);
}
- project_ref = 'Plugins/' + fixPathSep(path.relative(project.plugins_dir, destFile));
+ project_ref = `Plugins/${fixPathSep(path.relative(project.plugins_dir, destFile))}`;
}
if (type === 'header-file') {
project.xcode.addHeaderFile(project_ref);
} else if (obj.framework) {
- var opt = { weak: obj.weak };
- var project_relative = path.join(path.basename(project.xcode_path), project_ref);
+ const opt = { weak: obj.weak };
+ const project_relative = path.join(path.basename(project.xcode_path), project_ref);
project.xcode.addFramework(project_relative, opt);
- project.xcode.addToLibrarySearchPaths({path: project_ref});
+ project.xcode.addToLibrarySearchPaths({ path: project_ref });
} else {
- project.xcode.addSourceFile(project_ref, obj.compilerFlags ? {compilerFlags: obj.compilerFlags} : {});
+ project.xcode.addSourceFile(project_ref, obj.compilerFlags ? { compilerFlags: obj.compilerFlags } : {});
}
}
function uninstallHelper (type, obj, project_dir, plugin_id, options, project) {
- var targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || '');
- var destFile = path.join(targetDir, path.basename(obj.src));
+ const targetDir = path.resolve(project.plugins_dir, plugin_id, obj.targetDir || '');
+ const destFile = path.join(targetDir, path.basename(obj.src));
- var project_ref;
- var link = !!(options && options.link);
+ let project_ref;
+ const link = !!(options && options.link);
if (link) {
- var trueSrc = fs.readlinkSync(destFile);
- project_ref = 'Plugins/' + fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc));
+ const trueSrc = fs.readlinkSync(destFile);
+ project_ref = `Plugins/${fixPathSep(path.relative(fs.realpathSync(project.plugins_dir), trueSrc))}`;
} else {
- project_ref = 'Plugins/' + fixPathSep(path.relative(project.plugins_dir, destFile));
+ project_ref = `Plugins/${fixPathSep(path.relative(project.plugins_dir, destFile))}`;
}
- shell.rm('-rf', targetDir);
+ fs.removeSync(targetDir);
if (type === 'header-file') {
project.xcode.removeHeaderFile(project_ref);
} else if (obj.framework) {
- var project_relative = path.join(path.basename(project.xcode_path), project_ref);
+ const project_relative = path.join(path.basename(project.xcode_path), project_ref);
project.xcode.removeFramework(project_relative);
- project.xcode.removeFromLibrarySearchPaths({path: project_ref});
+ project.xcode.removeFromLibrarySearchPaths({ path: project_ref });
} else {
project.xcode.removeSourceFile(project_ref);
}
}
-var pathSepFix = new RegExp(path.sep.replace(/\\/, '\\\\'), 'g');
+const pathSepFix = new RegExp(path.sep.replace(/\\/, '\\\\'), 'g');
function fixPathSep (file) {
return file.replace(pathSepFix, '/');
}
function copyFile (plugin_dir, src, project_dir, dest, link) {
src = path.resolve(plugin_dir, src);
- if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
+ if (!fs.existsSync(src)) throw new CordovaError(`"${src}" not found!`);
// check that src path is inside plugin directory
- var real_path = fs.realpathSync(src);
- var real_plugin_path = fs.realpathSync(plugin_dir);
- if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
+ const real_path = fs.realpathSync(src);
+ const real_plugin_path = fs.realpathSync(plugin_dir);
+ if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError(`File "${src}" is located outside the plugin directory "${plugin_dir}"`); }
dest = path.resolve(project_dir, dest);
// check that dest path is located in project directory
- if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
+ if (dest.indexOf(project_dir) !== 0) { throw new CordovaError(`Destination "${dest}" for source file "${src}" is located outside the project`); }
- shell.mkdir('-p', path.dirname(dest));
+ fs.ensureDirSync(path.dirname(dest));
if (link) {
linkFileOrDirTree(src, dest);
- } else if (fs.statSync(src).isDirectory()) {
- // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
- shell.cp('-Rf', path.join(src, '/*'), dest);
} else {
- shell.cp('-f', src, dest);
+ fs.copySync(src, dest);
}
}
// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
- var target_path = path.resolve(project_dir, dest);
- if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
+ const target_path = path.resolve(project_dir, dest);
+ if (fs.existsSync(target_path)) { throw new CordovaError(`"${target_path}" already exists!`); }
copyFile(plugin_dir, src, project_dir, dest, !!link);
}
function linkFileOrDirTree (src, dest) {
if (fs.existsSync(dest)) {
- shell.rm('-Rf', dest);
+ fs.removeSync(dest);
}
if (fs.statSync(src).isDirectory()) {
- shell.mkdir('-p', dest);
- fs.readdirSync(src).forEach(function (entry) {
+ fs.ensureDirSync(dest);
+ fs.readdirSync(src).forEach(entry => {
linkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
});
} else {
@@ -365,24 +352,24 @@ function linkFileOrDirTree (src, dest) {
// checks if file exists and then deletes. Error if doesn't exist
function removeFile (project_dir, src) {
- var file = path.resolve(project_dir, src);
- shell.rm('-Rf', file);
+ const file = path.resolve(project_dir, src);
+ fs.removeSync(file);
}
// deletes file/directory without checking
function removeFileF (file) {
- shell.rm('-Rf', file);
+ fs.removeSync(file);
}
function removeFileAndParents (baseDir, destFile, stopper) {
stopper = stopper || '.';
- var file = path.resolve(baseDir, destFile);
+ const file = path.resolve(baseDir, destFile);
if (!fs.existsSync(file)) return;
removeFileF(file);
// check if directory is empty
- var curDir = path.dirname(file);
+ let curDir = path.dirname(file);
while (curDir !== path.resolve(baseDir, stopper)) {
if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
@@ -396,5 +383,5 @@ function removeFileAndParents (baseDir, destFile, stopper) {
}
function generateAttributeError (attribute, element, id) {
- return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
+ return `Required attribute "${attribute}" not specified in <${element}> element from plugin: ${id}`;
}
diff --git a/StoneIsland/platforms/ios/cordova/lib/prepare.js b/StoneIsland/platforms/ios/cordova/lib/prepare.js
index 17bbfeb7..c98cb8f4 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/prepare.js
+++ b/StoneIsland/platforms/ios/cordova/lib/prepare.js
@@ -18,53 +18,46 @@
*/
'use strict';
-var Q = require('q');
-var fs = require('fs');
-var path = require('path');
-var shell = require('shelljs');
-var xcode = require('xcode');
-var unorm = require('unorm');
-var plist = require('plist');
-var URL = require('url');
-var events = require('cordova-common').events;
-var xmlHelpers = require('cordova-common').xmlHelpers;
-var ConfigParser = require('cordova-common').ConfigParser;
-var CordovaError = require('cordova-common').CordovaError;
-var PlatformJson = require('cordova-common').PlatformJson;
-var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
-var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
-var FileUpdater = require('cordova-common').FileUpdater;
-var projectFile = require('./projectFile');
+
+const fs = require('fs-extra');
+const path = require('path');
+const unorm = require('unorm');
+const plist = require('plist');
+const URL = require('url');
+const events = require('cordova-common').events;
+const xmlHelpers = require('cordova-common').xmlHelpers;
+const ConfigParser = require('cordova-common').ConfigParser;
+const CordovaError = require('cordova-common').CordovaError;
+const PlatformJson = require('cordova-common').PlatformJson;
+const PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
+const PluginInfoProvider = require('cordova-common').PluginInfoProvider;
+const FileUpdater = require('cordova-common').FileUpdater;
+const projectFile = require('./projectFile');
// launch storyboard and related constants
-var LAUNCHIMAGE_BUILD_SETTING = 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME';
-var LAUNCHIMAGE_BUILD_SETTING_VALUE = 'LaunchImage';
-var UI_LAUNCH_STORYBOARD_NAME = 'UILaunchStoryboardName';
-var CDV_LAUNCH_STORYBOARD_NAME = 'CDVLaunchScreen';
-var IMAGESET_COMPACT_SIZE_CLASS = 'compact';
-var CDV_ANY_SIZE_CLASS = 'any';
+const IMAGESET_COMPACT_SIZE_CLASS = 'compact';
+const CDV_ANY_SIZE_CLASS = 'any';
module.exports.prepare = function (cordovaProject, options) {
- var self = this;
-
- var platformJson = PlatformJson.load(this.locations.root, 'ios');
- var munger = new PlatformMunger('ios', this.locations.root, platformJson, new PluginInfoProvider());
+ const platformJson = PlatformJson.load(this.locations.root, 'ios');
+ const munger = new PlatformMunger('ios', this.locations.root, platformJson, new PluginInfoProvider());
this._config = updateConfigFile(cordovaProject.projectConfig, munger, this.locations);
// Update own www dir with project's www assets and plugins' assets and js-files
- return Q.when(updateWww(cordovaProject, this.locations))
- .then(function () {
- // update project according to config.xml changes.
- return updateProject(self._config, self.locations);
+ return updateWww(cordovaProject, this.locations)
+ // update project according to config.xml changes.
+ .then(() => updateProject(this._config, this.locations))
+ .then(() => {
+ updateIcons(cordovaProject, this.locations);
+ updateLaunchStoryboardImages(cordovaProject, this.locations);
+ updateBackgroundColor(cordovaProject, this.locations);
+ updateFileResources(cordovaProject, this.locations);
})
- .then(function () {
- updateIcons(cordovaProject, self.locations);
- updateSplashScreens(cordovaProject, self.locations);
- updateLaunchStoryboardImages(cordovaProject, self.locations);
- updateFileResources(cordovaProject, self.locations);
+ .then(() => {
+ alertDeprecatedPreference(this._config);
})
- .then(function () {
+ .then(() => {
events.emit('verbose', 'Prepared iOS project successfully');
});
};
@@ -74,22 +67,21 @@ module.exports.clean = function (options) {
// been called from the platform shell script rather than the CLI. Check for the
// noPrepare option passed in by the non-CLI clean script. If that's present, or if
// there's no config.xml found at the project root, then don't clean prepared files.
- var projectRoot = path.resolve(this.root, '../..');
- var projectConfigFile = path.join(projectRoot, 'config.xml');
+ const projectRoot = path.resolve(this.root, '../..');
+ const projectConfigFile = path.join(projectRoot, 'config.xml');
if ((options && options.noPrepare) || !fs.existsSync(projectConfigFile) ||
!fs.existsSync(this.locations.configXml)) {
- return Q();
+ return Promise.resolve();
}
- var projectConfig = new ConfigParser(this.locations.configXml);
+ const projectConfig = new ConfigParser(this.locations.configXml);
- var self = this;
- return Q().then(function () {
- cleanWww(projectRoot, self.locations);
- cleanIcons(projectRoot, projectConfig, self.locations);
- cleanSplashScreens(projectRoot, projectConfig, self.locations);
- cleanLaunchStoryboardImages(projectRoot, projectConfig, self.locations);
- cleanFileResources(projectRoot, projectConfig, self.locations);
+ return Promise.resolve().then(() => {
+ cleanWww(projectRoot, this.locations);
+ cleanIcons(projectRoot, projectConfig, this.locations);
+ cleanLaunchStoryboardImages(projectRoot, projectConfig, this.locations);
+ cleanBackgroundColor(projectRoot, projectConfig, this.locations);
+ cleanFileResources(projectRoot, projectConfig, this.locations);
});
};
@@ -108,11 +100,11 @@ module.exports.clean = function (options) {
* configuration is already dumped to appropriate config.xml file.
*/
function updateConfigFile (sourceConfig, configMunger, locations) {
- events.emit('verbose', 'Generating platform-specific config.xml from defaults for iOS at ' + locations.configXml);
+ events.emit('verbose', `Generating platform-specific config.xml from defaults for iOS at ${locations.configXml}`);
// First cleanup current config and merge project's one into own
// Overwrite platform config.xml with defaults.xml.
- shell.cp('-f', locations.defaultConfigXml, locations.configXml);
+ fs.copySync(locations.defaultConfigXml, locations.configXml);
// Then apply config changes from global munge to all config files
// in project (including project's config)
@@ -120,7 +112,7 @@ function updateConfigFile (sourceConfig, configMunger, locations) {
events.emit('verbose', 'Merging project\'s config.xml into platform-specific iOS config.xml');
// Merge changes from app's config.xml into platform's one
- var config = new ConfigParser(locations.configXml);
+ const config = new ConfigParser(locations.configXml);
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
config.doc.getroot(), 'ios', /* clobber= */true);
@@ -132,7 +124,7 @@ function updateConfigFile (sourceConfig, configMunger, locations) {
* Logs all file operations via the verbose event stream, indented.
*/
function logFileOp (message) {
- events.emit('verbose', ' ' + message);
+ events.emit('verbose', ` ${message}`);
}
/**
@@ -145,31 +137,33 @@ function logFileOp (message) {
* paths for www files.
*/
function updateWww (cordovaProject, destinations) {
- var sourceDirs = [
+ const sourceDirs = [
path.relative(cordovaProject.root, cordovaProject.locations.www),
path.relative(cordovaProject.root, destinations.platformWww)
];
// If project contains 'merges' for our platform, use them as another overrides
- var merges_path = path.join(cordovaProject.root, 'merges', 'ios');
+ const merges_path = path.join(cordovaProject.root, 'merges', 'ios');
if (fs.existsSync(merges_path)) {
events.emit('verbose', 'Found "merges/ios" folder. Copying its contents into the iOS project.');
sourceDirs.push(path.join('merges', 'ios'));
}
- var targetDir = path.relative(cordovaProject.root, destinations.www);
+ const targetDir = path.relative(cordovaProject.root, destinations.www);
events.emit(
- 'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+ 'verbose', `Merging and updating files from [${sourceDirs.join(', ')}] to ${targetDir}`);
FileUpdater.mergeAndUpdateDir(
sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
+
+ return Promise.resolve();
}
/**
* Cleans all files from the platform 'www' directory.
*/
function cleanWww (projectRoot, locations) {
- var targetDir = path.relative(projectRoot, locations.www);
- events.emit('verbose', 'Cleaning ' + targetDir);
+ const targetDir = path.relative(projectRoot, locations.www);
+ events.emit('verbose', `Cleaning ${targetDir}`);
// No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
FileUpdater.mergeAndUpdateDir(
@@ -184,169 +178,176 @@ function cleanWww (projectRoot, locations) {
* @param {Object} locations A map of locations for this platform (In/Out)
*/
function updateProject (platformConfig, locations) {
-
// CB-6992 it is necessary to normalize characters
// because node and shell scripts handles unicode symbols differently
// We need to normalize the name to NFD form since iOS uses NFD unicode form
- var name = unorm.nfd(platformConfig.name());
- var pkg = platformConfig.getAttribute('ios-CFBundleIdentifier') || platformConfig.packageName();
- var version = platformConfig.version();
- var displayName = platformConfig.shortName && platformConfig.shortName();
+ const name = unorm.nfd(platformConfig.name());
+ const version = platformConfig.version();
+ const displayName = platformConfig.shortName && platformConfig.shortName();
- var originalName = path.basename(locations.xcodeCordovaProj);
+ const originalName = path.basename(locations.xcodeCordovaProj);
// Update package id (bundle id)
- var plistFile = path.join(locations.xcodeCordovaProj, originalName + '-Info.plist');
- var infoPlist = plist.parse(fs.readFileSync(plistFile, 'utf8'));
- infoPlist['CFBundleIdentifier'] = pkg;
+ const plistFile = path.join(locations.xcodeCordovaProj, `${originalName}-Info.plist`);
+ const infoPlist = plist.parse(fs.readFileSync(plistFile, 'utf8'));
// Update version (bundle version)
- infoPlist['CFBundleShortVersionString'] = version;
- var CFBundleVersion = platformConfig.getAttribute('ios-CFBundleVersion') || default_CFBundleVersion(version);
- infoPlist['CFBundleVersion'] = CFBundleVersion;
+ infoPlist.CFBundleShortVersionString = version;
+ const CFBundleVersion = platformConfig.getAttribute('ios-CFBundleVersion') || default_CFBundleVersion(version);
+ infoPlist.CFBundleVersion = CFBundleVersion;
if (platformConfig.getAttribute('defaultlocale')) {
- infoPlist['CFBundleDevelopmentRegion'] = platformConfig.getAttribute('defaultlocale');
+ infoPlist.CFBundleDevelopmentRegion = platformConfig.getAttribute('defaultlocale');
}
if (displayName) {
- infoPlist['CFBundleDisplayName'] = displayName;
+ infoPlist.CFBundleDisplayName = displayName;
}
// replace Info.plist ATS entries according to <access> and <allow-navigation> config.xml entries
- var ats = writeATSEntries(platformConfig);
+ const ats = writeATSEntries(platformConfig);
if (Object.keys(ats).length > 0) {
- infoPlist['NSAppTransportSecurity'] = ats;
+ infoPlist.NSAppTransportSecurity = ats;
} else {
- delete infoPlist['NSAppTransportSecurity'];
+ delete infoPlist.NSAppTransportSecurity;
}
handleOrientationSettings(platformConfig, infoPlist);
- updateProjectPlistForLaunchStoryboard(platformConfig, infoPlist);
- var info_contents = plist.build(infoPlist);
+ /* eslint-disable no-tabs */
+ // Write out the plist file with the same formatting as Xcode does
+ let info_contents = plist.build(infoPlist, { indent: '\t', offset: -1 });
+ /* eslint-enable no-tabs */
+
info_contents = info_contents.replace(/<string>[\s\r\n]*<\/string>/g, '<string></string>');
fs.writeFileSync(plistFile, info_contents, 'utf-8');
- events.emit('verbose', 'Wrote out iOS Bundle Identifier "' + pkg + '" and iOS Bundle Version "' + version + '" to ' + plistFile);
+ events.emit('verbose', `Wrote out iOS Bundle Version "${version}" to ${plistFile}`);
- return handleBuildSettings(platformConfig, locations, infoPlist).then(function () {
+ return handleBuildSettings(platformConfig, locations, infoPlist).then(() => {
if (name === originalName) {
- events.emit('verbose', 'iOS Product Name has not changed (still "' + originalName + '")');
- return Q();
+ events.emit('verbose', `iOS Product Name has not changed (still "${originalName}")`);
+ return Promise.resolve();
} else { // CB-11712 <name> was changed, we don't support it'
- var errorString =
+ const errorString =
'The product name change (<name> tag) in config.xml is not supported dynamically.\n' +
'To change your product name, you have to remove, then add your ios platform again.\n' +
'Make sure you save your plugins beforehand using `cordova plugin save`.\n' +
'\tcordova plugin save\n' +
'\tcordova platform rm ios\n' +
- '\tcordova platform add ios\n'
- ;
+ '\tcordova platform add ios\n';
- return Q.reject(new CordovaError(errorString));
+ return Promise.reject(new CordovaError(errorString));
}
});
}
function handleOrientationSettings (platformConfig, infoPlist) {
-
switch (getOrientationValue(platformConfig)) {
case 'portrait':
- infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationPortrait' ];
- infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown' ];
- infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown' ];
+ infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationPortrait'];
+ infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown'];
+ infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown'];
break;
case 'landscape':
- infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationLandscapeLeft' ];
- infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
- infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
+ infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationLandscapeLeft'];
+ infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
+ infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
break;
case 'all':
- infoPlist['UIInterfaceOrientation'] = [ 'UIInterfaceOrientationPortrait' ];
- infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
- infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
+ infoPlist.UIInterfaceOrientation = ['UIInterfaceOrientationPortrait'];
+ infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
+ infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
break;
case 'default':
- infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
- infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
- delete infoPlist['UIInterfaceOrientation'];
+ infoPlist.UISupportedInterfaceOrientations = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
+ infoPlist['UISupportedInterfaceOrientations~ipad'] = ['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight'];
+ delete infoPlist.UIInterfaceOrientation;
}
}
function handleBuildSettings (platformConfig, locations, infoPlist) {
- var targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios'));
- var deploymentTarget = platformConfig.getPreference('deployment-target', 'ios');
- var needUpdatedBuildSettingsForLaunchStoryboard = checkIfBuildSettingsNeedUpdatedForLaunchStoryboard(platformConfig, infoPlist);
+ const pkg = platformConfig.getAttribute('ios-CFBundleIdentifier') || platformConfig.packageName();
+ const targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios'));
+ const deploymentTarget = platformConfig.getPreference('deployment-target', 'ios');
+ const swiftVersion = platformConfig.getPreference('SwiftVersion', 'ios');
+
+ let project;
+
+ try {
+ project = projectFile.parse(locations);
+ } catch (err) {
+ return Promise.reject(new CordovaError(`Could not parse ${locations.pbxproj}: ${err}`));
+ }
+
+ const origPkg = project.xcode.getBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', undefined, platformConfig.name());
// no build settings provided and we don't need to update build settings for launch storyboards,
// then we don't need to parse and update .pbxproj file
- if (!targetDevice && !deploymentTarget && !needUpdatedBuildSettingsForLaunchStoryboard) {
- return Q();
+ if (origPkg === pkg && !targetDevice && !deploymentTarget && !swiftVersion) {
+ return Promise.resolve();
}
- var proj = new xcode.project(locations.pbxproj); /* eslint new-cap : 0 */
-
- try {
- proj.parseSync();
- } catch (err) {
- return Q.reject(new CordovaError('Could not parse project.pbxproj: ' + err));
+ if (origPkg !== pkg) {
+ events.emit('verbose', `Set PRODUCT_BUNDLE_IDENTIFIER to ${pkg}.`);
+ project.xcode.updateBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', pkg, null, platformConfig.name());
}
if (targetDevice) {
- events.emit('verbose', 'Set TARGETED_DEVICE_FAMILY to ' + targetDevice + '.');
- proj.updateBuildProperty('TARGETED_DEVICE_FAMILY', targetDevice);
+ events.emit('verbose', `Set TARGETED_DEVICE_FAMILY to ${targetDevice}.`);
+ project.xcode.updateBuildProperty('TARGETED_DEVICE_FAMILY', targetDevice);
}
if (deploymentTarget) {
- events.emit('verbose', 'Set IPHONEOS_DEPLOYMENT_TARGET to "' + deploymentTarget + '".');
- proj.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget);
+ events.emit('verbose', `Set IPHONEOS_DEPLOYMENT_TARGET to "${deploymentTarget}".`);
+ project.xcode.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget);
}
- updateBuildSettingsForLaunchStoryboard(proj, platformConfig, infoPlist);
+ if (swiftVersion) {
+ events.emit('verbose', `Set SwiftVersion to "${swiftVersion}".`);
+ project.xcode.updateBuildProperty('SWIFT_VERSION', swiftVersion);
+ }
- fs.writeFileSync(locations.pbxproj, proj.writeSync(), 'utf-8');
+ project.write();
- return Q();
+ return Promise.resolve();
}
function mapIconResources (icons, iconsDir) {
// See https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html
// for launch images sizes reference.
- var platformIcons = [
- {dest: 'icon-20.png', width: 20, height: 20},
- {dest: 'icon-20@2x.png', width: 40, height: 40},
- {dest: 'icon-20@3x.png', width: 60, height: 60},
- {dest: 'icon-40.png', width: 40, height: 40},
- {dest: 'icon-50.png', width: 50, height: 50},
- {dest: 'icon-50@2x.png', width: 100, height: 100},
- {dest: 'icon-60@2x.png', width: 120, height: 120},
- {dest: 'icon-60@3x.png', width: 180, height: 180},
- {dest: 'icon-72.png', width: 72, height: 72},
- {dest: 'icon-72@2x.png', width: 144, height: 144},
- {dest: 'icon-76.png', width: 76, height: 76},
- {dest: 'icon-76@2x.png', width: 152, height: 152},
- {dest: 'icon-83.5@2x.png', width: 167, height: 167},
- {dest: 'icon-1024.png', width: 1024, height: 1024},
- {dest: 'icon-small.png', width: 29, height: 29},
- {dest: 'icon-small@2x.png', width: 58, height: 58},
- {dest: 'icon-small@3x.png', width: 87, height: 87},
- {dest: 'icon.png', width: 57, height: 57},
- {dest: 'icon@2x.png', width: 114, height: 114},
- {dest: 'AppIcon24x24@2x.png', width: 48, height: 48},
- {dest: 'AppIcon27.5x27.5@2x.png', width: 55, height: 55},
- {dest: 'AppIcon29x29@2x.png', width: 58, height: 58},
- {dest: 'AppIcon29x29@3x.png', width: 87, height: 87},
- {dest: 'AppIcon40x40@2x.png', width: 80, height: 80},
- {dest: 'AppIcon44x44@2x.png', width: 88, height: 88},
- {dest: 'AppIcon86x86@2x.png', width: 172, height: 172},
- {dest: 'AppIcon98x98@2x.png', width: 196, height: 196}
+ const platformIcons = [
+ { dest: 'icon-20.png', width: 20, height: 20 },
+ { dest: 'icon-20@2x.png', width: 40, height: 40 },
+ { dest: 'icon-20@3x.png', width: 60, height: 60 },
+ { dest: 'icon-40.png', width: 40, height: 40 },
+ { dest: 'icon-40@2x.png', width: 80, height: 80 },
+ { dest: 'icon-50.png', width: 50, height: 50 },
+ { dest: 'icon-50@2x.png', width: 100, height: 100 },
+ { dest: 'icon-60@2x.png', width: 120, height: 120 },
+ { dest: 'icon-60@3x.png', width: 180, height: 180 },
+ { dest: 'icon-72.png', width: 72, height: 72 },
+ { dest: 'icon-72@2x.png', width: 144, height: 144 },
+ { dest: 'icon-76.png', width: 76, height: 76 },
+ { dest: 'icon-76@2x.png', width: 152, height: 152 },
+ { dest: 'icon-83.5@2x.png', width: 167, height: 167 },
+ { dest: 'icon-1024.png', width: 1024, height: 1024 },
+ { dest: 'icon-29.png', width: 29, height: 29 },
+ { dest: 'icon-29@2x.png', width: 58, height: 58 },
+ { dest: 'icon-29@3x.png', width: 87, height: 87 },
+ { dest: 'icon.png', width: 57, height: 57 },
+ { dest: 'icon@2x.png', width: 114, height: 114 },
+ { dest: 'icon-24@2x.png', width: 48, height: 48 },
+ { dest: 'icon-27.5@2x.png', width: 55, height: 55 },
+ { dest: 'icon-44@2x.png', width: 88, height: 88 },
+ { dest: 'icon-86@2x.png', width: 172, height: 172 },
+ { dest: 'icon-98@2x.png', width: 196, height: 196 }
];
- var pathMap = {};
- platformIcons.forEach(function (item) {
- var icon = icons.getBySize(item.width, item.height) || icons.getDefault();
+ const pathMap = {};
+ platformIcons.forEach(item => {
+ const icon = icons.getBySize(item.width, item.height) || icons.getDefault();
if (icon) {
- var target = path.join(iconsDir, item.dest);
+ const target = path.join(iconsDir, item.dest);
pathMap[target] = icon.src;
}
});
@@ -354,8 +355,8 @@ function mapIconResources (icons, iconsDir) {
}
function getIconsDir (projectRoot, platformProjDir) {
- var iconsDir;
- var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+ let iconsDir;
+ const xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
if (xcassetsExists) {
iconsDir = path.join(platformProjDir, 'Images.xcassets/AppIcon.appiconset/');
@@ -367,31 +368,31 @@ function getIconsDir (projectRoot, platformProjDir) {
}
function updateIcons (cordovaProject, locations) {
- var icons = cordovaProject.projectConfig.getIcons('ios');
+ const icons = cordovaProject.projectConfig.getIcons('ios');
if (icons.length === 0) {
events.emit('verbose', 'This app does not have icons defined');
return;
}
- var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
- var iconsDir = getIconsDir(cordovaProject.root, platformProjDir);
- var resourceMap = mapIconResources(icons, iconsDir);
- events.emit('verbose', 'Updating icons at ' + iconsDir);
+ const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
+ const iconsDir = getIconsDir(cordovaProject.root, platformProjDir);
+ const resourceMap = mapIconResources(icons, iconsDir);
+ events.emit('verbose', `Updating icons at ${iconsDir}`);
FileUpdater.updatePaths(
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
}
function cleanIcons (projectRoot, projectConfig, locations) {
- var icons = projectConfig.getIcons('ios');
+ const icons = projectConfig.getIcons('ios');
if (icons.length > 0) {
- var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
- var iconsDir = getIconsDir(projectRoot, platformProjDir);
- var resourceMap = mapIconResources(icons, iconsDir);
- Object.keys(resourceMap).forEach(function (targetIconPath) {
+ const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
+ const iconsDir = getIconsDir(projectRoot, platformProjDir);
+ const resourceMap = mapIconResources(icons, iconsDir);
+ Object.keys(resourceMap).forEach(targetIconPath => {
resourceMap[targetIconPath] = null;
});
- events.emit('verbose', 'Cleaning icons at ' + iconsDir);
+ events.emit('verbose', `Cleaning icons at ${iconsDir}`);
// Source paths are removed from the map, so updatePaths() will delete the target files.
FileUpdater.updatePaths(
@@ -399,74 +400,120 @@ function cleanIcons (projectRoot, projectConfig, locations) {
}
}
-function mapSplashScreenResources (splashScreens, splashScreensDir) {
- var platformSplashScreens = [
- {dest: 'Default~iphone.png', width: 320, height: 480},
- {dest: 'Default@2x~iphone.png', width: 640, height: 960},
- {dest: 'Default-Portrait~ipad.png', width: 768, height: 1024},
- {dest: 'Default-Portrait@2x~ipad.png', width: 1536, height: 2048},
- {dest: 'Default-Landscape~ipad.png', width: 1024, height: 768},
- {dest: 'Default-Landscape@2x~ipad.png', width: 2048, height: 1536},
- {dest: 'Default-568h@2x~iphone.png', width: 640, height: 1136},
- {dest: 'Default-667h.png', width: 750, height: 1334},
- {dest: 'Default-736h.png', width: 1242, height: 2208},
- {dest: 'Default-Landscape-736h.png', width: 2208, height: 1242}
- ];
-
- var pathMap = {};
- platformSplashScreens.forEach(function (item) {
- var splash = splashScreens.getBySize(item.width, item.height);
- if (splash) {
- var target = path.join(splashScreensDir, item.dest);
- pathMap[target] = splash.src;
- }
- });
- return pathMap;
+/**
+ * Returns the directory for the BackgroundColor.colorset asset, or null if no
+ * xcassets exist.
+ *
+ * @param {string} projectRoot The project's root directory
+ * @param {string} platformProjDir The platform's project directory
+ */
+function getBackgroundColorDir (projectRoot, platformProjDir) {
+ if (folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'))) {
+ return path.join(platformProjDir, 'Images.xcassets', 'BackgroundColor.colorset');
+ } else {
+ return null;
+ }
}
-function getSplashScreensDir (projectRoot, platformProjDir) {
- var splashScreensDir;
- var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+function colorPreferenceToComponents (pref) {
+ if (!pref || !pref.match(/^(#[0-9A-F]{3}|(0x|#)([0-9A-F]{2})?[0-9A-F]{6})$/)) {
+ return {
+ platform: 'ios',
+ reference: 'systemBackgroundColor'
+ };
+ }
- if (xcassetsExists) {
- splashScreensDir = path.join(platformProjDir, 'Images.xcassets/LaunchImage.launchimage/');
- } else {
- splashScreensDir = path.join(platformProjDir, 'Resources/splash/');
+ let red = 'FF';
+ let green = 'FF';
+ let blue = 'FF';
+ let alpha = 1.0;
+
+ if (pref[0] === '#' && pref.length === 4) {
+ red = pref[1] + pref[1];
+ green = pref[2] + pref[2];
+ blue = pref[3] + pref[3];
}
- return splashScreensDir;
-}
+ if (pref.length >= 7 && (pref[0] === '#' || pref.substring(0, 2) === '0x')) {
+ let offset = pref[0] === '#' ? 1 : 2;
-function updateSplashScreens (cordovaProject, locations) {
- var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios');
+ if (pref.substring(offset).length === 8) {
+ alpha = parseInt(pref.substring(offset, offset + 2), 16) / 255.0;
+ offset += 2;
+ }
- if (splashScreens.length === 0) {
- events.emit('verbose', 'This app does not have splash screens defined');
- return;
+ red = pref.substring(offset, offset + 2);
+ green = pref.substring(offset + 2, offset + 4);
+ blue = pref.substring(offset + 4, offset + 6);
}
- var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
- var splashScreensDir = getSplashScreensDir(cordovaProject.root, platformProjDir);
- var resourceMap = mapSplashScreenResources(splashScreens, splashScreensDir);
- events.emit('verbose', 'Updating splash screens at ' + splashScreensDir);
- FileUpdater.updatePaths(
- resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+ return {
+ 'color-space': 'srgb',
+ components: {
+ red: '0x' + red,
+ green: '0x' + green,
+ blue: '0x' + blue,
+ alpha: alpha.toFixed(3)
+ }
+ };
}
-function cleanSplashScreens (projectRoot, projectConfig, locations) {
- var splashScreens = projectConfig.getSplashScreens('ios');
- if (splashScreens.length > 0) {
- var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
- var splashScreensDir = getSplashScreensDir(projectRoot, platformProjDir);
- var resourceMap = mapIconResources(splashScreens, splashScreensDir);
- Object.keys(resourceMap).forEach(function (targetSplashPath) {
- resourceMap[targetSplashPath] = null;
- });
- events.emit('verbose', 'Cleaning splash screens at ' + splashScreensDir);
+/**
+ * Update the background color Contents.json in xcassets.
+ *
+ * @param {Object} cordovaProject The cordova project
+ * @param {Object} locations A dictionary containing useful location paths
+ */
+function updateBackgroundColor (cordovaProject, locations) {
+ const pref = cordovaProject.projectConfig.getPreference('BackgroundColor', 'ios') || '';
- // Source paths are removed from the map, so updatePaths() will delete the target files.
- FileUpdater.updatePaths(
- resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+ const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
+ const backgroundColorDir = getBackgroundColorDir(cordovaProject.root, platformProjDir);
+
+ if (backgroundColorDir) {
+ const contentsJSON = {
+ colors: [{
+ idiom: 'universal',
+ color: colorPreferenceToComponents(pref)
+ }],
+ info: {
+ author: 'Xcode',
+ version: 1
+ }
+ };
+
+ events.emit('verbose', 'Updating Background Color color set Contents.json');
+ fs.writeFileSync(path.join(cordovaProject.root, backgroundColorDir, 'Contents.json'),
+ JSON.stringify(contentsJSON, null, 2));
+ }
+}
+
+/**
+ * Resets the background color Contents.json in xcassets to default.
+ *
+ * @param {string} projectRoot Path to the project root
+ * @param {Object} projectConfig The project's config.xml
+ * @param {Object} locations A dictionary containing useful location paths
+ */
+function cleanBackgroundColor (projectRoot, projectConfig, locations) {
+ const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
+ const backgroundColorDir = getBackgroundColorDir(projectRoot, platformProjDir);
+
+ if (backgroundColorDir) {
+ const contentsJSON = {
+ colors: [{
+ idiom: 'universal',
+ color: colorPreferenceToComponents(null)
+ }],
+ info: {
+ author: 'Xcode',
+ version: 1
+ }
+ };
+
+ events.emit('verbose', 'Cleaning Background Color color set Contents.json');
+ fs.writeFileSync(path.join(projectRoot, backgroundColorDir, 'Contents.json'),
+ JSON.stringify(contentsJSON, null, 2));
}
}
@@ -482,9 +529,9 @@ function updateFileResources (cordovaProject, locations) {
return;
}
- let resourceMap = {};
- files.forEach(function (res) {
- let src = res.src;
+ const resourceMap = {};
+ files.forEach(res => {
+ const src = res.src;
let target = res.target;
if (!target) {
@@ -494,29 +541,75 @@ function updateFileResources (cordovaProject, locations) {
let targetPath = path.join(project.resources_dir, target);
targetPath = path.relative(cordovaProject.root, targetPath);
- project.xcode.addResourceFile(target);
+ if (!fs.existsSync(targetPath)) {
+ project.xcode.addResourceFile(target);
+ } else {
+ events.emit('warn', `Overwriting existing resource file at ${targetPath}`);
+ }
resourceMap[targetPath] = src;
});
- events.emit('verbose', 'Updating resource files at ' + platformDir);
+ events.emit('verbose', `Updating resource files at ${platformDir}`);
FileUpdater.updatePaths(
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
project.write();
}
+function alertDeprecatedPreference (configParser) {
+ const deprecatedToNewPreferences = {
+ MediaPlaybackRequiresUserAction: {
+ newPreference: 'MediaTypesRequiringUserActionForPlayback',
+ isDeprecated: true
+ },
+ MediaPlaybackAllowsAirPlay: {
+ newPreference: 'AllowsAirPlayForMediaPlayback',
+ isDeprecated: false
+ }
+ };
+
+ Object.keys(deprecatedToNewPreferences).forEach(oldKey => {
+ if (configParser.getPreference(oldKey)) {
+ const isDeprecated = deprecatedToNewPreferences[oldKey].isDeprecated;
+ const verb = isDeprecated ? 'has been' : 'is being';
+ const newPreferenceKey = deprecatedToNewPreferences[oldKey].newPreference;
+
+ // Create the Log Message
+ const log = [`The preference name "${oldKey}" ${verb} deprecated.`];
+ if (newPreferenceKey) {
+ log.push(`It is recommended to replace this preference with "${newPreferenceKey}."`);
+ } else {
+ log.push('There is no replacement for this preference.');
+ }
+
+ /**
+ * If the preference has been deprecated, the usage of the old preference is no longer used.
+ * Therefore, the following line is not appended. It is added only if the old preference is still used.
+ * We are only keeping the top lines for deprecated items only for an additional major release when
+ * the pre-warning was not provided in a past major release due to a necessary quick deprecation.
+ * Typically caused by implementation nature or third-party requirement changes.
+ */
+ if (!isDeprecated) {
+ log.push('Please note that this preference will be removed in the near future.');
+ }
+
+ events.emit('warn', log.join(' '));
+ }
+ });
+}
+
function cleanFileResources (projectRoot, projectConfig, locations) {
const platformDir = path.relative(projectRoot, locations.root);
const files = projectConfig.getFileResources('ios', true);
if (files.length > 0) {
- events.emit('verbose', 'Cleaning resource files at ' + platformDir);
+ events.emit('verbose', `Cleaning resource files at ${platformDir}`);
const project = projectFile.parse(locations);
- var resourceMap = {};
- files.forEach(function (res) {
- let src = res.src;
+ const resourceMap = {};
+ files.forEach(res => {
+ const src = res.src;
let target = res.target;
if (!target) {
@@ -532,7 +625,7 @@ function cleanFileResources (projectRoot, projectConfig, locations) {
});
FileUpdater.updatePaths(
- resourceMap, {rootDir: projectRoot, all: true}, logFileOp);
+ resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
project.write();
}
@@ -555,7 +648,8 @@ function cleanFileResources (projectRoot, projectConfig, locations) {
* height: 'any|com',
* filename: undefined|'Default@scale~idiom~widthheight.png',
* src: undefined|'path/to/original/matched/image/from/splash/screens.png',
- * target: undefined|'path/to/asset/library/Default@scale~idiom~widthheight.png'
+ * target: undefined|'path/to/asset/library/Default@scale~idiom~widthheight.png',
+ * appearence: undefined|'dark'|'light'
* }, ...
* ]
*
@@ -564,51 +658,54 @@ function cleanFileResources (projectRoot, projectConfig, locations) {
* @return {Array<Object>}
*/
function mapLaunchStoryboardContents (splashScreens, launchStoryboardImagesDir) {
- var platformLaunchStoryboardImages = [];
- var idioms = ['universal', 'ipad', 'iphone'];
- var scalesForIdiom = {
+ const platformLaunchStoryboardImages = [];
+ const idioms = ['universal', 'ipad', 'iphone'];
+ const scalesForIdiom = {
universal: ['1x', '2x', '3x'],
ipad: ['1x', '2x'],
iphone: ['1x', '2x', '3x']
};
- var sizes = ['com', 'any'];
+ const sizes = ['com', 'any'];
+ const appearences = ['', 'dark', 'light'];
- idioms.forEach(function (idiom) {
- scalesForIdiom[idiom].forEach(function (scale) {
- sizes.forEach(function (width) {
- sizes.forEach(function (height) {
- var item = {
- idiom: idiom,
- scale: scale,
- width: width,
- height: height
- };
+ idioms.forEach(idiom => {
+ scalesForIdiom[idiom].forEach(scale => {
+ sizes.forEach(width => {
+ sizes.forEach(height => {
+ appearences.forEach(appearence => {
+ const item = { idiom, scale, width, height };
- /* examples of the search pattern:
- * scale ~ idiom ~ width height
- * @2x ~ universal ~ any any
- * @3x ~ iphone ~ com any
- * @2x ~ ipad ~ com any
- */
- var searchPattern = '@' + scale + '~' + idiom + '~' + width + height;
+ if (appearence !== '') {
+ item.appearence = appearence;
+ }
- /* because old node versions don't have Array.find, the below is
- * functionally equivalent to this:
- * var launchStoryboardImage = splashScreens.find(function(item) {
- * return item.src.indexOf(searchPattern) >= 0;
- * });
- */
- var launchStoryboardImage = splashScreens.reduce(function (p, c) {
- return (c.src.indexOf(searchPattern) >= 0) ? c : p;
- }, undefined);
+ /* examples of the search pattern:
+ * scale ~ idiom ~ width height ~ appearence
+ * @2x ~ universal ~ any any
+ * @3x ~ iphone ~ com any ~ dark
+ * @2x ~ ipad ~ com any ~ light
+ */
+ const searchPattern = '@' + scale + '~' + idiom + '~' + width + height + (appearence ? '~' + appearence : '');
- if (launchStoryboardImage) {
- item.filename = 'Default' + searchPattern + '.png';
- item.src = launchStoryboardImage.src;
- item.target = path.join(launchStoryboardImagesDir, item.filename);
- }
+ /* because old node versions don't have Array.find, the below is
+ * functionally equivalent to this:
+ * var launchStoryboardImage = splashScreens.find(function(item) {
+ * return (item.src.indexOf(searchPattern) >= 0) ? (appearence !== '' ? true : ((item.src.indexOf(searchPattern + '~light') >= 0 || (item.src.indexOf(searchPattern + '~dark') >= 0)) ? false : true)) : false;
+ * });
+ */
+ const launchStoryboardImage = splashScreens.reduce(
+ (p, c) => (c.src.indexOf(searchPattern) >= 0) ? (appearence !== '' ? c : ((c.src.indexOf(searchPattern + '~light') >= 0 || (c.src.indexOf(searchPattern + '~dark') >= 0)) ? p : c)) : p,
+ undefined
+ );
- platformLaunchStoryboardImages.push(item);
+ if (launchStoryboardImage) {
+ item.filename = `Default${searchPattern}.png`;
+ item.src = launchStoryboardImage.src;
+ item.target = path.join(launchStoryboardImagesDir, item.filename);
+ }
+
+ platformLaunchStoryboardImages.push(item);
+ });
});
});
});
@@ -632,9 +729,9 @@ function mapLaunchStoryboardContents (splashScreens, launchStoryboardImagesDir)
* @return {Object}
*/
function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir) {
- var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
- var pathMap = {};
- platformLaunchStoryboardImages.forEach(function (item) {
+ const platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
+ const pathMap = {};
+ platformLaunchStoryboardImages.forEach(item => {
if (item.target) {
pathMap[item.target] = item.src;
}
@@ -654,6 +751,7 @@ function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir)
* scale: '1x|2x|3x',
* width-class: undefined|'compact',
* height-class: undefined|'compact'
+ * ...
* }, ...
* ],
* info: {
@@ -670,17 +768,16 @@ function mapLaunchStoryboardResources (splashScreens, launchStoryboardImagesDir)
* @return {Object}
*/
function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesDir) {
-
- var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
- var contentsJSON = {
+ const platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
+ const contentsJSON = {
images: [],
info: {
author: 'Xcode',
version: 1
}
};
- contentsJSON.images = platformLaunchStoryboardImages.map(function (item) {
- var newItem = {
+ contentsJSON.images = platformLaunchStoryboardImages.map(item => {
+ const newItem = {
idiom: item.idiom,
scale: item.scale
};
@@ -694,6 +791,10 @@ function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesD
newItem['height-class'] = IMAGESET_COMPACT_SIZE_CLASS;
}
+ if (item.appearence) {
+ newItem.appearances = [{ appearance: 'luminosity', value: item.appearence }];
+ }
+
// Xcode doesn't want a filename property if there's no image for these traits
if (item.filename) {
newItem.filename = item.filename;
@@ -704,107 +805,6 @@ function getLaunchStoryboardContentsJSON (splashScreens, launchStoryboardImagesD
}
/**
- * Determines if the project's build settings may need to be updated for launch storyboard support
- *
- */
-function checkIfBuildSettingsNeedUpdatedForLaunchStoryboard (platformConfig, infoPlist) {
- var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig);
- var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig);
- var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME];
-
- if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) {
- // don't need legacy launch images if we are using our launch storyboard
- // so we do need to update the project file
- events.emit('verbose', 'Need to update build settings because project is using our launch storyboard.');
- return true;
- } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) {
- // we do need to ensure legacy launch images are used if there's no launch storyboard present
- // so we do need to update the project file
- events.emit('verbose', 'Need to update build settings because project is using legacy launch images and no storyboard.');
- return true;
- }
- events.emit('verbose', 'No need to update build settings for launch storyboard support.');
- return false;
-}
-
-function updateBuildSettingsForLaunchStoryboard (proj, platformConfig, infoPlist) {
- var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig);
- var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig);
- var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME];
-
- if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) {
- // don't need legacy launch images if we are using our launch storyboard
- events.emit('verbose', 'Removed ' + LAUNCHIMAGE_BUILD_SETTING + ' because project is using our launch storyboard.');
- proj.removeBuildProperty(LAUNCHIMAGE_BUILD_SETTING);
- } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) {
- // we do need to ensure legacy launch images are used if there's no launch storyboard present
- events.emit('verbose', 'Set ' + LAUNCHIMAGE_BUILD_SETTING + ' to ' + LAUNCHIMAGE_BUILD_SETTING_VALUE + ' because project is using legacy launch images and no storyboard.');
- proj.updateBuildProperty(LAUNCHIMAGE_BUILD_SETTING, LAUNCHIMAGE_BUILD_SETTING_VALUE);
- } else {
- events.emit('verbose', 'Did not update build settings for launch storyboard support.');
- }
-}
-
-function splashScreensHaveLaunchStoryboardImages (contentsJSON) {
- /* do we have any launch images do we have for our launch storyboard?
- * Again, for old Node versions, the below code is equivalent to this:
- * return !!contentsJSON.images.find(function (item) {
- * return item.filename !== undefined;
- * });
- */
- return !!contentsJSON.images.reduce(function (p, c) {
- return (c.filename !== undefined) ? c : p;
- }, undefined);
-}
-
-function platformHasLaunchStoryboardImages (platformConfig) {
- var splashScreens = platformConfig.getSplashScreens('ios');
- var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, ''); // note: we don't need a file path here; we're just counting
- return splashScreensHaveLaunchStoryboardImages(contentsJSON);
-}
-
-function platformHasLegacyLaunchImages (platformConfig) {
- var splashScreens = platformConfig.getSplashScreens('ios');
- return !!splashScreens.reduce(function (p, c) {
- return (c.width !== undefined || c.height !== undefined) ? c : p;
- }, undefined);
-}
-
-/**
- * Updates the project's plist based upon our launch storyboard images. If there are no images, then we should
- * fall back to the regular launch images that might be supplied (that is, our app will be scaled on an iPad Pro),
- * and if there are some images, we need to alter the UILaunchStoryboardName property to point to
- * CDVLaunchScreen.
- *
- * There's some logic here to avoid overwriting changes the user might have made to their plist if they are using
- * their own launch storyboard.
- */
-function updateProjectPlistForLaunchStoryboard (platformConfig, infoPlist) {
- var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME];
- events.emit('verbose', 'Current launch storyboard ' + currentLaunchStoryboard);
-
- var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig);
-
- if (hasLaunchStoryboardImages && !currentLaunchStoryboard) {
- // only change the launch storyboard if we have images to use AND the current value is blank
- // if it's not blank, we've either done this before, or the user has their own launch storyboard
- events.emit('verbose', 'Changing info plist to use our launch storyboard');
- infoPlist[UI_LAUNCH_STORYBOARD_NAME] = CDV_LAUNCH_STORYBOARD_NAME;
- return;
- }
-
- if (!hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME) {
- // only revert to using the launch images if we have don't have any images for the launch storyboard
- // but only clear it if current launch storyboard is our storyboard; the user might be using their
- // own storyboard instead.
- events.emit('verbose', 'Changing info plist to use legacy launch images');
- delete infoPlist[UI_LAUNCH_STORYBOARD_NAME];
- return;
- }
- events.emit('verbose', 'Not changing launch storyboard setting in info plist.');
-}
-
-/**
* Returns the directory for the Launch Storyboard image set, if image sets are being used. If they aren't
* being used, returns null.
*
@@ -812,8 +812,8 @@ function updateProjectPlistForLaunchStoryboard (platformConfig, infoPlist) {
* @param {string} platformProjDir The platform's project directory
*/
function getLaunchStoryboardImagesDir (projectRoot, platformProjDir) {
- var launchStoryboardImagesDir;
- var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+ let launchStoryboardImagesDir;
+ const xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
if (xcassetsExists) {
launchStoryboardImagesDir = path.join(platformProjDir, 'Images.xcassets/LaunchStoryboard.imageset/');
@@ -832,15 +832,15 @@ function getLaunchStoryboardImagesDir (projectRoot, platformProjDir) {
* @param {Object} locations A dictionary containing useful location paths
*/
function updateLaunchStoryboardImages (cordovaProject, locations) {
- var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios');
- var platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
- var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(cordovaProject.root, platformProjDir);
+ const splashScreens = cordovaProject.projectConfig.getSplashScreens('ios');
+ const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
+ const launchStoryboardImagesDir = getLaunchStoryboardImagesDir(cordovaProject.root, platformProjDir);
if (launchStoryboardImagesDir) {
- var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
- var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
+ const resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
+ const contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
- events.emit('verbose', 'Updating launch storyboard images at ' + launchStoryboardImagesDir);
+ events.emit('verbose', `Updating launch storyboard images at ${launchStoryboardImagesDir}`);
FileUpdater.updatePaths(
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
@@ -859,24 +859,24 @@ function updateLaunchStoryboardImages (cordovaProject, locations) {
* @param {Object} locations A dictionary containing useful location paths
*/
function cleanLaunchStoryboardImages (projectRoot, projectConfig, locations) {
- var splashScreens = projectConfig.getSplashScreens('ios');
- var platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
- var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(projectRoot, platformProjDir);
+ const splashScreens = projectConfig.getSplashScreens('ios');
+ const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
+ const launchStoryboardImagesDir = getLaunchStoryboardImagesDir(projectRoot, platformProjDir);
if (launchStoryboardImagesDir) {
- var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
- var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
+ const resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
+ const contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
- Object.keys(resourceMap).forEach(function (targetPath) {
+ Object.keys(resourceMap).forEach(targetPath => {
resourceMap[targetPath] = null;
});
- events.emit('verbose', 'Cleaning storyboard image set at ' + launchStoryboardImagesDir);
+ events.emit('verbose', `Cleaning storyboard image set at ${launchStoryboardImagesDir}`);
// Source paths are removed from the map, so updatePaths() will delete the target files.
FileUpdater.updatePaths(
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
// delete filename from contents.json
- contentsJSON.images.forEach(function (image) {
+ contentsJSON.images.forEach(image => {
image.filename = undefined;
});
@@ -896,10 +896,9 @@ function cleanLaunchStoryboardImages (projectRoot, projectConfig, locations) {
* (or empty string if both are undefined).
*/
function getOrientationValue (platformConfig) {
+ const ORIENTATION_DEFAULT = 'default';
- var ORIENTATION_DEFAULT = 'default';
-
- var orientation = platformConfig.getPreference('orientation');
+ let orientation = platformConfig.getPreference('orientation');
if (!orientation) {
return '';
}
@@ -911,8 +910,7 @@ function getOrientationValue (platformConfig) {
return orientation;
}
- events.emit('warn', 'Unrecognized value for Orientation preference: ' + orientation +
- '. Defaulting to value: ' + ORIENTATION_DEFAULT + '.');
+ events.emit('warn', `Unrecognized value for Orientation preference: ${orientation}. Defaulting to value: ${ORIENTATION_DEFAULT}.`);
return ORIENTATION_DEFAULT;
}
@@ -938,20 +936,20 @@ function getOrientationValue (platformConfig) {
}
*/
function processAccessAndAllowNavigationEntries (config) {
- var accesses = config.getAccesses();
- var allow_navigations = config.getAllowNavigations();
+ const accesses = config.getAccesses();
+ const allow_navigations = config.getAllowNavigations();
return allow_navigations
- // we concat allow_navigations and accesses, after processing accesses
- .concat(accesses.map(function (obj) {
+ // we concat allow_navigations and accesses, after processing accesses
+ .concat(accesses.map(obj => {
// map accesses to a common key interface using 'href', not origin
obj.href = obj.origin;
delete obj.origin;
return obj;
}))
// we reduce the array to an object with all the entries processed (key is Hostname)
- .reduce(function (previousReturn, currentElement) {
- var options = {
+ .reduce((previousReturn, currentElement) => {
+ const options = {
minimum_tls_version: currentElement.minimum_tls_version,
requires_forward_secrecy: currentElement.requires_forward_secrecy,
requires_certificate_transparency: currentElement.requires_certificate_transparency,
@@ -959,16 +957,16 @@ function processAccessAndAllowNavigationEntries (config) {
allows_arbitrary_loads_in_web_content: currentElement.allows_arbitrary_loads_in_web_content,
allows_local_networking: currentElement.allows_local_networking
};
- var obj = parseWhitelistUrlForATS(currentElement.href, options);
+ const obj = parseWhitelistUrlForATS(currentElement.href, options);
if (obj) {
// we 'union' duplicate entries
- var item = previousReturn[obj.Hostname];
+ let item = previousReturn[obj.Hostname];
if (!item) {
item = {};
}
- for (var o in obj) {
- if (obj.hasOwnProperty(o)) {
+ for (const o in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, o)) {
item[o] = obj[o];
}
}
@@ -999,15 +997,16 @@ function processAccessAndAllowNavigationEntries (config) {
null is returned if the URL cannot be parsed, or is to be skipped for ATS.
*/
function parseWhitelistUrlForATS (url, options) {
- var href = URL.parse(url);
- var retObj = {};
+ // @todo 'url.parse' was deprecated since v11.0.0. Use 'url.URL' constructor instead.
+ const href = URL.parse(url); // eslint-disable-line
+ const retObj = {};
retObj.Hostname = href.hostname;
// Guiding principle: we only set values in retObj if they are NOT the default
if (url === '*') {
retObj.Hostname = '*';
- var val;
+ let val;
val = (options.allows_arbitrary_loads_in_web_content === 'true');
if (options.allows_arbitrary_loads_in_web_content && val) { // default is false
@@ -1029,10 +1028,12 @@ function parseWhitelistUrlForATS (url, options) {
if (!retObj.Hostname) {
// check origin, if it allows subdomains (wildcard in hostname), we set NSIncludesSubdomains to YES. Default is NO
- var subdomain1 = '/*.'; // wildcard in hostname
- var subdomain2 = '*://*.'; // wildcard in hostname and protocol
- var subdomain3 = '*://'; // wildcard in protocol only
- if (href.pathname.indexOf(subdomain1) === 0) {
+ const subdomain1 = '/*.'; // wildcard in hostname
+ const subdomain2 = '*://*.'; // wildcard in hostname and protocol
+ const subdomain3 = '*://'; // wildcard in protocol only
+ if (!href.pathname) {
+ return null;
+ } else if (href.pathname.indexOf(subdomain1) === 0) {
retObj.NSIncludesSubdomains = true;
retObj.Hostname = href.pathname.substring(subdomain1.length);
} else if (href.pathname.indexOf(subdomain2) === 0) {
@@ -1050,12 +1051,12 @@ function parseWhitelistUrlForATS (url, options) {
retObj.NSExceptionMinimumTLSVersion = options.minimum_tls_version;
}
- var rfs = (options.requires_forward_secrecy === 'true');
+ const rfs = (options.requires_forward_secrecy === 'true');
if (options.requires_forward_secrecy && !rfs) { // default is true
retObj.NSExceptionRequiresForwardSecrecy = false;
}
- var rct = (options.requires_certificate_transparency === 'true');
+ const rct = (options.requires_certificate_transparency === 'true');
if (options.requires_certificate_transparency && rct) { // default is false
retObj.NSRequiresCertificateTransparency = true;
}
@@ -1075,48 +1076,48 @@ function parseWhitelistUrlForATS (url, options) {
in config.xml
*/
function writeATSEntries (config) {
- var pObj = processAccessAndAllowNavigationEntries(config);
+ const pObj = processAccessAndAllowNavigationEntries(config);
- var ats = {};
+ const ats = {};
- for (var hostname in pObj) {
- if (pObj.hasOwnProperty(hostname)) {
- var entry = pObj[hostname];
+ for (const hostname in pObj) {
+ if (Object.prototype.hasOwnProperty.call(pObj, hostname)) {
+ const entry = pObj[hostname];
// Guiding principle: we only set values if they are available
if (hostname === '*') {
// always write this, for iOS 9, since in iOS 10 it will be overriden if
// any of the other three keys are written
- ats['NSAllowsArbitraryLoads'] = true;
+ ats.NSAllowsArbitraryLoads = true;
// at least one of the overriding keys is present
if (entry.NSAllowsArbitraryLoadsInWebContent) {
- ats['NSAllowsArbitraryLoadsInWebContent'] = true;
+ ats.NSAllowsArbitraryLoadsInWebContent = true;
}
if (entry.NSAllowsArbitraryLoadsForMedia) {
- ats['NSAllowsArbitraryLoadsForMedia'] = true;
+ ats.NSAllowsArbitraryLoadsForMedia = true;
}
if (entry.NSAllowsLocalNetworking) {
- ats['NSAllowsLocalNetworking'] = true;
+ ats.NSAllowsLocalNetworking = true;
}
continue;
}
- var exceptionDomain = {};
+ const exceptionDomain = {};
- for (var key in entry) {
- if (entry.hasOwnProperty(key) && key !== 'Hostname') {
+ for (const key in entry) {
+ if (Object.prototype.hasOwnProperty.call(entry, key) && key !== 'Hostname') {
exceptionDomain[key] = entry[key];
}
}
- if (!ats['NSExceptionDomains']) {
- ats['NSExceptionDomains'] = {};
+ if (!ats.NSExceptionDomains) {
+ ats.NSExceptionDomains = {};
}
- ats['NSExceptionDomains'][hostname] = exceptionDomain;
+ ats.NSExceptionDomains[hostname] = exceptionDomain;
}
}
@@ -1125,7 +1126,7 @@ function writeATSEntries (config) {
function folderExists (folderPath) {
try {
- var stat = fs.statSync(folderPath);
+ const stat = fs.statSync(folderPath);
return stat && stat.isDirectory();
} catch (e) {
return false;
@@ -1141,10 +1142,10 @@ function default_CFBundleVersion (version) {
// Converts cordova specific representation of target device to XCode value
function parseTargetDevicePreference (value) {
if (!value) return null;
- var map = {'universal': '"1,2"', 'handset': '"1"', 'tablet': '"2"'};
+ const map = { universal: '"1,2"', handset: '"1"', tablet: '"2"' };
if (map[value.toLowerCase()]) {
return map[value.toLowerCase()];
}
- events.emit('warn', 'Unrecognized value for target-device preference: ' + value + '.');
+ events.emit('warn', `Unrecognized value for target-device preference: ${value}.`);
return null;
}
diff --git a/StoneIsland/platforms/ios/cordova/lib/projectFile.js b/StoneIsland/platforms/ios/cordova/lib/projectFile.js
index 8a3f7e51..3e1e8304 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/projectFile.js
+++ b/StoneIsland/platforms/ios/cordova/lib/projectFile.js
@@ -17,47 +17,46 @@
under the License.
*/
-var xcode = require('xcode');
-var plist = require('plist');
-var _ = require('underscore');
-var path = require('path');
-var fs = require('fs');
-var shell = require('shelljs');
+const xcode = require('xcode');
+const plist = require('plist');
+const _ = require('underscore');
+const path = require('path');
+const fs = require('fs-extra');
-var pluginHandlers = require('./plugman/pluginHandlers');
-var CordovaError = require('cordova-common').CordovaError;
+const pluginHandlers = require('./plugman/pluginHandlers');
+const CordovaError = require('cordova-common').CordovaError;
-var cachedProjectFiles = {};
+const cachedProjectFiles = {};
function parseProjectFile (locations) {
- var project_dir = locations.root;
- var pbxPath = locations.pbxproj;
+ const project_dir = locations.root;
+ const pbxPath = locations.pbxproj;
if (cachedProjectFiles[project_dir]) {
return cachedProjectFiles[project_dir];
}
- var xcodeproj = xcode.project(pbxPath);
+ const xcodeproj = xcode.project(pbxPath);
xcodeproj.parseSync();
- var xcBuildConfiguration = xcodeproj.pbxXCBuildConfigurationSection();
- var plist_file_entry = _.find(xcBuildConfiguration, function (entry) { return entry.buildSettings && entry.buildSettings.INFOPLIST_FILE; });
- var plist_file = path.join(project_dir, plist_file_entry.buildSettings.INFOPLIST_FILE.replace(/^"(.*)"$/g, '$1').replace(/\\&/g, '&'));
- var config_file = path.join(path.dirname(plist_file), 'config.xml');
+ const xcBuildConfiguration = xcodeproj.pbxXCBuildConfigurationSection();
+ const plist_file_entry = _.find(xcBuildConfiguration, entry => entry.buildSettings && entry.buildSettings.INFOPLIST_FILE);
+ const plist_file = path.join(project_dir, plist_file_entry.buildSettings.INFOPLIST_FILE.replace(/^"(.*)"$/g, '$1').replace(/\\&/g, '&'));
+ const config_file = path.join(path.dirname(plist_file), 'config.xml');
if (!fs.existsSync(plist_file) || !fs.existsSync(config_file)) {
throw new CordovaError('Could not find *-Info.plist file, or config.xml file.');
}
- var frameworks_file = path.join(project_dir, 'frameworks.json');
- var frameworks = {};
+ const frameworks_file = path.join(project_dir, 'frameworks.json');
+ let frameworks = {};
try {
frameworks = require(frameworks_file);
} catch (e) { }
- var xcode_dir = path.dirname(plist_file);
- var pluginsDir = path.resolve(xcode_dir, 'Plugins');
- var resourcesDir = path.resolve(xcode_dir, 'Resources');
+ const xcode_dir = path.dirname(plist_file);
+ const pluginsDir = path.resolve(xcode_dir, 'Plugins');
+ const resourcesDir = path.resolve(xcode_dir, 'Resources');
cachedProjectFiles[project_dir] = {
plugins_dir: pluginsDir,
@@ -72,13 +71,21 @@ function parseProjectFile (locations) {
fs.writeFileSync(pbxPath, xcodeproj.writeSync());
if (Object.keys(this.frameworks).length === 0) {
// If there is no framework references remain in the project, just remove this file
- shell.rm('-rf', frameworks_file);
+ fs.removeSync(frameworks_file);
return;
}
fs.writeFileSync(frameworks_file, JSON.stringify(this.frameworks, null, 4));
},
getPackageName: function () {
- return plist.parse(fs.readFileSync(plist_file, 'utf8')).CFBundleIdentifier;
+ const packageName = plist.parse(fs.readFileSync(plist_file, 'utf8')).CFBundleIdentifier;
+ let bundleIdentifier = packageName;
+
+ const variables = packageName.match(/\$\((\w+)\)/); // match $(VARIABLE), if any
+ if (variables && variables.length >= 2) {
+ bundleIdentifier = xcodeproj.getBuildProperty(variables[1]);
+ }
+
+ return bundleIdentifier.replace(/^"/, '').replace(/"$/, '');
},
getInstaller: function (name) {
return pluginHandlers.getInstaller(name);
@@ -86,7 +93,7 @@ function parseProjectFile (locations) {
getUninstaller: function (name) {
return pluginHandlers.getUninstaller(name);
},
- frameworks: frameworks
+ frameworks
};
return cachedProjectFiles[project_dir];
}
@@ -97,7 +104,7 @@ function purgeProjectFileCache (project_dir) {
module.exports = {
parse: parseProjectFile,
- purgeProjectFileCache: purgeProjectFileCache
+ purgeProjectFileCache
};
xcode.project.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) {
@@ -105,25 +112,23 @@ xcode.project.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) {
};
xcode.project.prototype.addToPbxEmbedFrameworksBuildPhase = function (file) {
- var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
+ const sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
if (sources) {
sources.files.push(pbxBuildPhaseObj(file));
}
};
xcode.project.prototype.removeFromPbxEmbedFrameworksBuildPhase = function (file) {
- var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
+ const sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
if (sources) {
- sources.files = _.reject(sources.files, function (file) {
- return file.comment === longComment(file);
- });
+ sources.files = _.reject(sources.files, file => file.comment === longComment(file));
}
};
// special handlers to add frameworks to the 'Embed Frameworks' build phase, needed for custom frameworks
// see CB-9517. should probably be moved to node-xcode.
-var util = require('util');
+const util = require('util');
function pbxBuildPhaseObj (file) {
- var obj = Object.create(null);
+ const obj = Object.create(null);
obj.value = file.uuid;
obj.comment = longComment(file);
return obj;
diff --git a/StoneIsland/platforms/ios/cordova/lib/run.js b/StoneIsland/platforms/ios/cordova/lib/run.js
index 3a6246e1..f7fd8c13 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/run.js
+++ b/StoneIsland/platforms/ios/cordova/lib/run.js
@@ -17,23 +17,23 @@
under the License.
*/
-var Q = require('q');
-var path = require('path');
-var iossim = require('ios-sim');
-var build = require('./build');
-var spawn = require('./spawn');
-var check_reqs = require('./check_reqs');
+const path = require('path');
+const build = require('./build');
+const {
+ CordovaError,
+ events,
+ superspawn: { spawn }
+} = require('cordova-common');
+const check_reqs = require('./check_reqs');
+const fs = require('fs-extra');
-var events = require('cordova-common').events;
-
-var cordovaPath = path.join(__dirname, '..');
-var projectPath = path.join(__dirname, '..', '..');
-
-module.exports.run = function (runOptions) {
+const cordovaPath = path.join(__dirname, '..');
+const projectPath = path.join(__dirname, '..', '..');
+module.exports.run = runOptions => {
// Validate args
if (runOptions.device && runOptions.emulator) {
- return Q.reject('Only one of "device"/"emulator" options should be specified');
+ return Promise.reject(new CordovaError('Only one of "device"/"emulator" options should be specified'));
}
// support for CB-8168 `cordova/run --list`
@@ -41,15 +41,13 @@ module.exports.run = function (runOptions) {
if (runOptions.device) return module.exports.listDevices();
if (runOptions.emulator) return module.exports.listEmulators();
// if no --device or --emulator flag is specified, list both devices and emulators
- return module.exports.listDevices().then(function () {
- return module.exports.listEmulators();
- });
+ return module.exports.listDevices().then(() => module.exports.listEmulators());
}
- var useDevice = !!runOptions.device;
+ let useDevice = !!runOptions.device;
- return require('./list-devices').run()
- .then(function (devices) {
+ return require('./listDevices').run()
+ .then(devices => {
if (devices.length > 0 && !(runOptions.emulator)) {
useDevice = true;
// we also explicitly set device flag in options as we pass
@@ -57,58 +55,56 @@ module.exports.run = function (runOptions) {
runOptions.device = true;
return check_reqs.check_ios_deploy();
}
- }).then(function () {
+ }).then(() => {
if (!runOptions.nobuild) {
return build.run(runOptions);
} else {
- return Q.resolve();
+ return Promise.resolve();
}
- }).then(function () {
- return build.findXCodeProjectIn(projectPath);
- }).then(function (projectName) {
- var appPath = path.join(projectPath, 'build', 'emulator', projectName + '.app');
- var buildOutputDir = path.join(projectPath, 'build', 'device');
+ }).then(() => build.findXCodeProjectIn(projectPath))
+ .then(projectName => {
+ let appPath = path.join(projectPath, 'build', 'emulator', `${projectName}.app`);
+ const buildOutputDir = path.join(projectPath, 'build', 'device');
// select command to run and arguments depending whether
// we're running on device/emulator
if (useDevice) {
return module.exports.checkDeviceConnected()
- .then(function () {
+ .then(() => {
// Unpack IPA
- var ipafile = path.join(buildOutputDir, projectName + '.ipa');
+ const ipafile = path.join(buildOutputDir, `${projectName}.ipa`);
// unpack the existing platform/ios/build/device/appname.ipa (zipfile), will create a Payload folder
- return spawn('unzip', [ '-o', '-qq', ipafile ], buildOutputDir);
+ return spawn('unzip', ['-o', '-qq', ipafile], { cwd: buildOutputDir, printCommand: true, stdio: 'inherit' });
})
- .then(function () {
+ .then(() => {
// Uncompress IPA (zip file)
- var appFileInflated = path.join(buildOutputDir, 'Payload', projectName + '.app');
- var appFile = path.join(buildOutputDir, projectName + '.app');
- var payloadFolder = path.join(buildOutputDir, 'Payload');
+ const appFileInflated = path.join(buildOutputDir, 'Payload', `${projectName}.app`);
+ const appFile = path.join(buildOutputDir, `${projectName}.app`);
+ const payloadFolder = path.join(buildOutputDir, 'Payload');
// delete the existing platform/ios/build/device/appname.app
- return spawn('rm', [ '-rf', appFile ], buildOutputDir)
- .then(function () {
- // move the platform/ios/build/device/Payload/appname.app to parent
- return spawn('mv', [ '-f', appFileInflated, buildOutputDir ], buildOutputDir);
- })
- .then(function () {
- // delete the platform/ios/build/device/Payload folder
- return spawn('rm', [ '-rf', payloadFolder ], buildOutputDir);
- });
+ fs.removeSync(appFile);
+ // move the platform/ios/build/device/Payload/appname.app to parent
+ fs.moveSync(appFileInflated, appFile);
+ // delete the platform/ios/build/device/Payload folder
+ fs.removeSync(payloadFolder);
+
+ return null;
})
- .then(function () {
- appPath = path.join(projectPath, 'build', 'device', projectName + '.app');
- var extraArgs = [];
- if (runOptions.argv) {
- // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args
- extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2));
- }
- return module.exports.deployToDevice(appPath, runOptions.target, extraArgs);
- }, function () {
+ .then(
+ () => {
+ appPath = path.join(projectPath, 'build', 'device', `${projectName}.app`);
+ let extraArgs = [];
+ if (runOptions.argv) {
+ // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args
+ extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2));
+ }
+ return module.exports.deployToDevice(appPath, runOptions.target, extraArgs);
+ },
// if device connection check failed use emulator then
- return module.exports.deployToSim(appPath, runOptions.target);
- });
+ () => module.exports.deployToSim(appPath, runOptions.target)
+ );
} else {
return module.exports.deployToSim(appPath, runOptions.target);
}
@@ -129,11 +125,11 @@ module.exports.listEmulators = listEmulators;
* @return {Array} array with unsupported args for the 'run' command
*/
function filterSupportedArgs (args) {
- var filtered = [];
- var sargs = ['--device', '--emulator', '--nobuild', '--list', '--target', '--debug', '--release'];
- var re = new RegExp(sargs.join('|'));
+ const filtered = [];
+ const sargs = ['--device', '--emulator', '--nobuild', '--list', '--target', '--debug', '--release'];
+ const re = new RegExp(sargs.join('|'));
- args.forEach(function (element) {
+ args.forEach(element => {
// supported args not found, we add
// we do a regex search because --target can be "--target=XXX"
if (element.search(re) === -1) {
@@ -149,7 +145,7 @@ function filterSupportedArgs (args) {
* @return {Promise} Fullfilled when any device is connected, rejected otherwise
*/
function checkDeviceConnected () {
- return spawn('ios-deploy', ['-c', '-t', '1']);
+ return spawn('ios-deploy', ['-c', '-t', '1'], { printCommand: true, stdio: 'inherit' });
}
/**
@@ -159,11 +155,12 @@ function checkDeviceConnected () {
* @return {Promise} Resolves when deploy succeeds otherwise rejects
*/
function deployToDevice (appPath, target, extraArgs) {
+ events.emit('log', 'Deploying to device');
// Deploying to device...
if (target) {
- return spawn('ios-deploy', ['--justlaunch', '-d', '-b', appPath, '-i', target].concat(extraArgs));
+ return spawn('ios-deploy', ['--justlaunch', '-d', '-b', appPath, '-i', target].concat(extraArgs), { printCommand: true, stdio: 'inherit' });
} else {
- return spawn('ios-deploy', ['--justlaunch', '--no-wifi', '-d', '-b', appPath].concat(extraArgs));
+ return spawn('ios-deploy', ['--justlaunch', '--no-wifi', '-d', '-b', appPath].concat(extraArgs), { printCommand: true, stdio: 'inherit' });
}
}
@@ -174,19 +171,20 @@ function deployToDevice (appPath, target, extraArgs) {
* @return {Promise} Resolves when deploy succeeds otherwise rejects
*/
function deployToSim (appPath, target) {
- // Select target device for emulator. Default is 'iPhone-6'
+ events.emit('log', 'Deploying to simulator');
if (!target) {
- return require('./list-emulator-images').run()
- .then(function (emulators) {
+ // Select target device for emulator
+ return require('./listEmulatorImages').run()
+ .then(emulators => {
if (emulators.length > 0) {
target = emulators[0];
}
- emulators.forEach(function (emulator) {
+ emulators.forEach(emulator => {
if (emulator.indexOf('iPhone') === 0) {
target = emulator;
}
});
- events.emit('log', 'No target specified for emulator. Deploying to ' + target + ' simulator');
+ events.emit('log', `No target specified for emulator. Deploying to "${target}" simulator.`);
return startSim(appPath, target);
});
} else {
@@ -195,32 +193,50 @@ function deployToSim (appPath, target) {
}
function startSim (appPath, target) {
- var logPath = path.join(cordovaPath, 'console.log');
+ const logPath = path.join(cordovaPath, 'console.log');
- return iossim.launch(appPath, 'com.apple.CoreSimulator.SimDeviceType.' + target, logPath, '--exit');
+ return iossimLaunch(appPath, `com.apple.CoreSimulator.SimDeviceType.${target}`, logPath, '--exit');
+}
+
+function iossimLaunch (appPath, devicetypeid, log, exit) {
+ return spawn(
+ require.resolve('ios-sim/bin/ios-sim'),
+ ['launch', appPath, '--devicetypeid', devicetypeid, '--log', log, exit],
+ { cwd: projectPath, printCommand: true }
+ ).progress(stdio => {
+ if (stdio.stderr) {
+ events.emit('error', `[ios-sim] ${stdio.stderr}`);
+ }
+ if (stdio.stdout) {
+ events.emit('log', `[ios-sim] ${stdio.stdout.trim()}`);
+ }
+ })
+ .then(result => {
+ events.emit('log', 'Simulator successfully started via `ios-sim`.');
+ });
}
function listDevices () {
- return require('./list-devices').run()
- .then(function (devices) {
+ return require('./listDevices').run()
+ .then(devices => {
events.emit('log', 'Available iOS Devices:');
- devices.forEach(function (device) {
- events.emit('log', '\t' + device);
+ devices.forEach(device => {
+ events.emit('log', `\t${device}`);
});
});
}
function listEmulators () {
- return require('./list-emulator-images').run()
- .then(function (emulators) {
+ return require('./listEmulatorImages').run()
+ .then(emulators => {
events.emit('log', 'Available iOS Simulators:');
- emulators.forEach(function (emulator) {
- events.emit('log', '\t' + emulator);
+ emulators.forEach(emulator => {
+ events.emit('log', `\t${emulator}`);
});
});
}
-module.exports.help = function () {
+module.exports.help = () => {
console.log('\nUsage: run [ --device | [ --emulator [ --target=<id> ] ] ] [ --debug | --release | --nobuild ]');
// TODO: add support for building different archs
// console.log(" [ --archs=\"<list of target architectures>\" ] ");
diff --git a/StoneIsland/platforms/ios/cordova/lib/spawn.js b/StoneIsland/platforms/ios/cordova/lib/spawn.js
deleted file mode 100755
index b5a56852..00000000
--- a/StoneIsland/platforms/ios/cordova/lib/spawn.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- 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 Q = require('q');
-var proc = require('child_process');
-
-/**
- * Run specified command with arguments
- * @param {String} cmd Command
- * @param {Array} args Array of arguments that should be passed to command
- * @param {String} opt_cwd Working directory for command
- * @param {String} opt_verbosity Verbosity level for command stdout output, "verbose" by default
- * @return {Promise} Promise either fullfilled or rejected with error code
- */
-module.exports = function (cmd, args, opt_cwd) {
- var d = Q.defer();
- try {
- var child = proc.spawn(cmd, args, {cwd: opt_cwd, stdio: 'inherit'});
-
- child.on('exit', function (code) {
- if (code) {
- d.reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args);
- } else {
- d.resolve();
- }
- });
- } catch (e) {
- d.reject(e);
- }
- return d.promise;
-};
diff --git a/StoneIsland/platforms/ios/cordova/lib/versions.js b/StoneIsland/platforms/ios/cordova/lib/versions.js
index c6a41b83..f8914785 100755..100644
--- a/StoneIsland/platforms/ios/cordova/lib/versions.js
+++ b/StoneIsland/platforms/ios/cordova/lib/versions.js
@@ -1,5 +1,3 @@
-#!/usr/bin/env node
-
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -19,76 +17,43 @@
under the License.
*/
-var child_process = require('child_process');
-var Q = require('q');
+const {
+ CordovaError,
+ superspawn: { spawn }
+} = require('cordova-common');
+const semver = require('semver');
-exports.get_apple_ios_version = function () {
- var d = Q.defer();
- child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) {
- if (error) {
- d.reject(stderr);
- } else {
- d.resolve(stdout);
- }
- });
+function fetchSdkVersionByType (sdkType) {
+ return spawn('xcodebuild', ['-showsdks'])
+ .then(output => {
+ const regexSdk = new RegExp(`^${sdkType} \\d`);
- return d.promise.then(function (output) {
- var regex = /[0-9]*\.[0-9]*/;
- var versions = [];
- var regexIOS = /^iOS \d+/;
- output = output.split('\n');
- for (var i = 0; i < output.length; i++) {
- if (output[i].trim().match(regexIOS)) {
- versions[versions.length] = parseFloat(output[i].match(regex)[0]);
- }
- }
- versions.sort();
- console.log(versions[0]);
- return Q();
- }, function (stderr) {
- return Q.reject(stderr);
- });
-};
+ const versions = output.split('\n')
+ .filter(line => line.trim().match(regexSdk))
+ .map(line => line.match(/\d+\.\d+/)[0])
+ .sort(exports.compareVersions);
-exports.get_apple_osx_version = function () {
- var d = Q.defer();
- child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) {
- if (error) {
- d.reject(stderr);
- } else {
- d.resolve(stdout);
- }
- });
+ console.log(versions[0]);
+ });
+}
- return d.promise.then(function (output) {
- var regex = /[0-9]*\.[0-9]*/;
- var versions = [];
- var regexOSX = /^OS X \d+/;
- output = output.split('\n');
- for (var i = 0; i < output.length; i++) {
- if (output[i].trim().match(regexOSX)) {
- versions[versions.length] = parseFloat(output[i].match(regex)[0]);
- }
- }
- versions.sort();
- console.log(versions[0]);
- return Q();
- }, function (stderr) {
- return Q.reject(stderr);
- });
+exports.get_apple_ios_version = () => {
+ return fetchSdkVersionByType('iOS');
};
-exports.get_apple_xcode_version = function () {
- var d = Q.defer();
- child_process.exec('xcodebuild -version', function (error, stdout, stderr) {
- var versionMatch = /Xcode (.*)/.exec(stdout);
- if (error || !versionMatch) {
- d.reject(stderr);
- } else {
- d.resolve(versionMatch[1]);
- }
- });
- return d.promise;
+exports.get_apple_osx_version = () => {
+ return fetchSdkVersionByType('macOS');
+};
+
+exports.get_apple_xcode_version = () => {
+ return spawn('xcodebuild', ['-version'])
+ .then(output => {
+ const versionMatch = /Xcode (.*)/.exec(output);
+
+ if (!versionMatch) return Promise.reject(output);
+
+ return versionMatch[1];
+ });
};
/**
@@ -96,16 +61,8 @@ exports.get_apple_xcode_version = function () {
* @return {Promise} Promise that either resolved with ios-deploy version
* or rejected in case of error
*/
-exports.get_ios_deploy_version = function () {
- var d = Q.defer();
- child_process.exec('ios-deploy --version', function (error, stdout, stderr) {
- if (error) {
- d.reject(stderr);
- } else {
- d.resolve(stdout);
- }
- });
- return d.promise;
+exports.get_ios_deploy_version = () => {
+ return spawn('ios-deploy', ['--version']);
};
/**
@@ -113,16 +70,8 @@ exports.get_ios_deploy_version = function () {
* @return {Promise} Promise that either resolved with pod version
* or rejected in case of error
*/
-exports.get_cocoapods_version = function () {
- var d = Q.defer();
- child_process.exec('pod --version', function (error, stdout, stderr) {
- if (error) {
- d.reject(stderr);
- } else {
- d.resolve(stdout);
- }
- });
- return d.promise;
+exports.get_cocoapods_version = () => {
+ return spawn('pod', ['--version']);
};
/**
@@ -130,16 +79,8 @@ exports.get_cocoapods_version = function () {
* @return {Promise} Promise that either resolved with ios-sim version
* or rejected in case of error
*/
-exports.get_ios_sim_version = function () {
- var d = Q.defer();
- child_process.exec('ios-sim --version', function (error, stdout, stderr) {
- if (error) {
- d.reject(stderr);
- } else {
- d.resolve(stdout);
- }
- });
- return d.promise;
+exports.get_ios_sim_version = () => {
+ return spawn('ios-sim', ['--version']);
};
/**
@@ -148,47 +89,31 @@ exports.get_ios_sim_version = function () {
* @return {Promise} Promise that either resolved with tool version
* or rejected in case of error
*/
-exports.get_tool_version = function (toolName) {
+exports.get_tool_version = toolName => {
switch (toolName) {
case 'xcodebuild': return exports.get_apple_xcode_version();
case 'ios-sim': return exports.get_ios_sim_version();
case 'ios-deploy': return exports.get_ios_deploy_version();
case 'pod': return exports.get_cocoapods_version();
- default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\', \'ios-deploy\', and \'pod\'');
+ default: return Promise.reject(new CordovaError(`${toolName} is not valid tool name. Valid names are: 'xcodebuild', 'ios-sim', 'ios-deploy', and 'pod'`));
}
};
/**
- * Compares two semver-notated version strings. Returns number
- * that indicates equality of provided version strings.
+ * Compares two version strings that can be coerced to semver.
+ *
* @param {String} version1 Version to compare
* @param {String} version2 Another version to compare
* @return {Number} Negative number if first version is lower than the second,
* positive otherwise and 0 if versions are equal.
*/
-exports.compareVersions = function (version1, version2) {
- function parseVer (version) {
- return version.split('.').map(function (value) {
- // try to convert version segment to Number
- var parsed = Number(value);
- // Number constructor is strict enough and will return NaN
- // if conversion fails. In this case we won't be able to compare versions properly
- if (isNaN(parsed)) {
- throw 'Version should contain only numbers and dots';
- }
- return parsed;
- });
- }
- var parsedVer1 = parseVer(version1);
- var parsedVer2 = parseVer(version2);
+exports.compareVersions = (...args) => {
+ const coerceToSemverIfInvalid = v => {
+ const semverVersion = semver.parse(v) || semver.coerce(v);
+ if (!semverVersion) throw new TypeError(`Invalid Version: ${v}`);
+ return semverVersion;
+ };
- // Compare corresponding segments of each version
- for (var i = 0; i < Math.max(parsedVer1.length, parsedVer2.length); i++) {
- // if segment is not specified, assume that it is 0
- // E.g. 3.1 is equal to 3.1.0
- var ret = (parsedVer1[i] || 0) - (parsedVer2[i] || 0);
- // if segments are not equal, we're finished
- if (ret !== 0) return ret;
- }
- return 0;
+ const semverVersions = args.map(coerceToSemverIfInvalid);
+ return semver.compare(...semverVersions);
};