summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/cordova
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/ios/cordova')
-rwxr-xr-xStoneIsland/platforms/ios/cordova/Api.js470
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build43
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build-debug.xcconfig7
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build-extras.xcconfig22
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build-release.xcconfig4
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build.bat19
-rwxr-xr-xStoneIsland/platforms/ios/cordova/build.xcconfig13
-rwxr-xr-xStoneIsland/platforms/ios/cordova/check_reqs4
-rwxr-xr-xStoneIsland/platforms/ios/cordova/clean27
-rwxr-xr-xStoneIsland/platforms/ios/cordova/clean.bat10
-rwxr-xr-xStoneIsland/platforms/ios/cordova/defaults.xml15
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/Podfile.js230
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/PodsJson.js115
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/build.js304
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/check_reqs.js96
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/clean.js8
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js14
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/list-emulator-images10
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js375
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/prepare.js1003
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/projectFile.js136
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/run.js146
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/spawn.js1
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/versions.js20
-rwxr-xr-xStoneIsland/platforms/ios/cordova/log.bat19
-rwxr-xr-xStoneIsland/platforms/ios/cordova/loggingHelper.js30
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE32
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js3
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/LICENSE23
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/abbrev.js62
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/package.json31
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/nopt/package.json63
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/q/package.json133
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/q/q.js278
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json62
-rwxr-xr-xStoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js1898
-rwxr-xr-xStoneIsland/platforms/ios/cordova/run41
-rwxr-xr-xStoneIsland/platforms/ios/cordova/run.bat10
-rwxr-xr-xStoneIsland/platforms/ios/cordova/version9
39 files changed, 3427 insertions, 2359 deletions
diff --git a/StoneIsland/platforms/ios/cordova/Api.js b/StoneIsland/platforms/ios/cordova/Api.js
new file mode 100755
index 00000000..b95f8e8c
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/Api.js
@@ -0,0 +1,470 @@
+/**
+ 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.
+*/
+
+/*jslint node: true */
+
+var fs = require('fs');
+var path = require('path');
+var unorm = require('unorm');
+var projectFile = require('./lib/projectFile');
+var CordovaError = require('cordova-common').CordovaError;
+var CordovaLogger = require('cordova-common').CordovaLogger;
+var events = require('cordova-common').events;
+var PluginManager = require('cordova-common').PluginManager;
+var Q = require('q');
+var util = require('util');
+
+function setupEvents(externalEventEmitter) {
+ if (externalEventEmitter) {
+ // This will make the platform internal events visible outside
+ events.forwardEventsTo(externalEventEmitter);
+ } else {
+ // There is no logger if external emitter is not present,
+ // so attach a console logger
+ CordovaLogger.get().subscribe(events);
+ }
+}
+
+/**
+ * Creates a new PlatformApi instance.
+ *
+ * @param {String} [platform] Platform name, used for backward compatibility
+ * w/ PlatformPoly (CordovaLib).
+ * @param {String} [platformRootDir] Platform root location, used for backward
+ * compatibility w/ PlatformPoly (CordovaLib).
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ * logging purposes. If no EventEmitter provided, all events will be logged to
+ * console
+ */
+function Api(platform, platformRootDir, events) {
+ // 'platform' property is required as per PlatformApi spec
+ this.platform = platform || 'ios';
+ this.root = platformRootDir || path.resolve(__dirname, '..');
+
+ setupEvents(events);
+
+ var xcodeProjDir;
+ var xcodeCordovaProj;
+
+ try {
+ xcodeProjDir = fs.readdirSync(this.root).filter( function(e) { return e.match(/\.xcodeproj$/i); })[0];
+ if (!xcodeProjDir) {
+ throw new CordovaError('The provided path "' + this.root + '" is not a Cordova iOS project.');
+ }
+
+ var cordovaProjName = xcodeProjDir.substring(xcodeProjDir.lastIndexOf(path.sep)+1, xcodeProjDir.indexOf('.xcodeproj'));
+ xcodeCordovaProj = path.join(this.root, cordovaProjName);
+ } catch(e) {
+ throw new CordovaError('The provided path "'+this.root+'" is not a Cordova iOS project.');
+ }
+
+ this.locations = {
+ root: this.root,
+ www: path.join(this.root, 'www'),
+ platformWww: path.join(this.root, 'platform_www'),
+ configXml: path.join(xcodeCordovaProj, 'config.xml'),
+ defaultConfigXml: path.join(this.root, 'cordova/defaults.xml'),
+ pbxproj: path.join(this.root, xcodeProjDir, 'project.pbxproj'),
+ xcodeProjDir: path.join(this.root, xcodeProjDir),
+ xcodeCordovaProj: xcodeCordovaProj,
+ // NOTE: this is required by browserify logic.
+ // As per platformApi spec we return relative to template root paths here
+ cordovaJs: 'bin/CordovaLib/cordova.js',
+ cordovaJsSrc: 'bin/cordova-js-src'
+ };
+}
+
+/**
+ * Creates platform in a specified directory.
+ *
+ * @param {String} destination Destination directory, where install platform to
+ * @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
+ * project creation options, such as package id and project name.
+ * @param {Object} [options] An options object. The most common options are:
+ * @param {String} [options.customTemplate] A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} [options.link] Flag that indicates that platform's
+ * sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ * logging purposes. If no EventEmitter provided, all events will be logged to
+ * console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+Api.createPlatform = function (destination, config, options, events) {
+ setupEvents(events);
+
+ // 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(config.name());
+ var result;
+ try {
+ result = require('../../../lib/create')
+ .createProject(destination, config.packageName(), name, options)
+ .then(function () {
+ // after platform is created we return Api instance based on new Api.js location
+ // This is required to correctly resolve paths in the future api calls
+ var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+ return new PlatformApi('ios', destination, events);
+ });
+ }
+ catch(e) {
+ events.emit('error','createPlatform is not callable from the iOS project API.');
+ throw(e);
+ }
+ return result;
+};
+
+/**
+ * Updates already installed platform.
+ *
+ * @param {String} destination Destination directory, where platform installed
+ * @param {Object} [options] An options object. The most common options are:
+ * @param {String} [options.customTemplate] A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} [options.link] Flag that indicates that platform's
+ * sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ * logging purposes. If no EventEmitter provided, all events will be logged to
+ * console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+Api.updatePlatform = function (destination, options, events) {
+ setupEvents(events);
+
+ var result;
+ try {
+ result = require('../../../lib/create')
+ .updateProject(destination, options)
+ .then(function () {
+ var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+ return new PlatformApi('ios', destination, events);
+ });
+ }
+ catch (e) {
+ events.emit('error','updatePlatform is not callable from the iOS project API, you will need to do this manually.');
+ throw(e);
+ }
+ return result;
+};
+
+/**
+ * Gets a CordovaPlatform object, that represents the platform structure.
+ *
+ * @return {CordovaPlatform} A structure that contains the description of
+ * platform's file structure and other properties of platform.
+ */
+Api.prototype.getPlatformInfo = function () {
+ var result = {};
+ result.locations = this.locations;
+ result.root = this.root;
+ result.name = this.platform;
+ result.version = require('./version');
+ result.projectConfig = this._config;
+
+ return result;
+};
+
+/**
+ * Updates installed platform with provided www assets and new app
+ * configuration. This method is required for CLI workflow and will be called
+ * each time before build, so the changes, made to app configuration and www
+ * code, will be applied to platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ * project structure and configuration, that should be applied to platform
+ * (contains project's www location and ConfigParser instance for project's
+ * config).
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.prepare = function (cordovaProject) {
+ return require('./lib/prepare').prepare.call(this, cordovaProject);
+};
+
+/**
+ * Installs a new plugin into platform. It doesn't resolves plugin dependencies.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ * @param {Object} installOptions An options object. Possible options below:
+ * @param {Boolean} installOptions.link: Flag that specifies that plugin
+ * sources will be symlinked to app's directory instead of copying (if
+ * possible).
+ * @param {Object} installOptions.variables An object that represents
+ * variables that will be used to install plugin. See more details on plugin
+ * variables in documentation:
+ * https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.addPlugin = function (plugin, installOptions) {
+ var xcodeproj = projectFile.parse(this.locations);
+ var self = this;
+
+ installOptions = installOptions || {};
+ installOptions.variables = installOptions.variables || {};
+ // Add PACKAGE_NAME variable into vars
+ if (!installOptions.variables.PACKAGE_NAME) {
+ installOptions.variables.PACKAGE_NAME = xcodeproj.getPackageName();
+ }
+
+ return PluginManager.get(self.platform, self.locations, xcodeproj)
+ .addPlugin(plugin, installOptions)
+ .then(function(){
+ var frameworkTags = plugin.getFrameworks(self.platform);
+ var frameworkPods = frameworkTags.filter(function(obj){
+ return (obj.type == 'podspec');
+ });
+
+ return Q.resolve(frameworkPods);
+ })
+ .then(function(frameworkPods) {
+ if (!(frameworkPods.length)) {
+ return Q.resolve();
+ }
+
+ var project_dir = self.locations.root;
+ var project_name = self.locations.xcodeCordovaProj.split('/').pop();
+
+ var Podfile = require('./lib/Podfile').Podfile;
+ var PodsJson = require('./lib/PodsJson').PodsJson;
+
+ events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type="podspec"');
+
+ var podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME));
+ var podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name);
+
+ frameworkPods.forEach(function(obj) {
+ var podJson = {
+ name: obj.src,
+ type: obj.type,
+ spec: obj.spec
+ };
+
+ var val = podsjsonFile.get(podJson.name);
+ if (val) { // found
+ if (podJson.spec !== val.spec) { // exists, different spec, print warning
+ events.emit('warn', plugin.id + ' depends on ' + podJson.name + '@' + podJson.spec + ', which conflicts with another plugin. ' + podJson.name + '@' + val.spec + ' is already installed and was not overwritten.');
+ }
+ // increment count, but don't add in Podfile because it already exists
+ podsjsonFile.increment(podJson.name);
+ } else { // not found, write new
+ podJson.count = 1;
+ podsjsonFile.setJson(podJson.name, podJson);
+ // add to Podfile
+ podfileFile.addSpec(podJson.name, podJson.spec);
+ }
+ });
+
+ // now that all the pods have been processed, write to pods.json
+ podsjsonFile.write();
+
+ // only write and pod install if the Podfile changed
+ if (podfileFile.isDirty()) {
+ podfileFile.write();
+ events.emit('verbose', 'Running `pod install` (to install plugins)');
+
+ var check_reqs = require('./lib/check_reqs');
+ return podfileFile.install(check_reqs.check_cocoapods);
+ } else {
+ events.emit('verbose', 'Podfile unchanged, skipping `pod install`');
+ }
+ })
+ // CB-11022 return non-falsy value to indicate
+ // that there is no need to run prepare after
+ .thenResolve(true);
+};
+
+/**
+ * Removes an installed plugin from platform.
+ *
+ * Since method accepts PluginInfo instance as input parameter instead of plugin
+ * id, caller shoud take care of managing/storing PluginInfo instances for
+ * future uninstalls.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.removePlugin = function (plugin, uninstallOptions) {
+ var xcodeproj = projectFile.parse(this.locations);
+ var self = this;
+
+ return PluginManager.get(self.platform, self.locations, xcodeproj)
+ .removePlugin(plugin, uninstallOptions)
+ .then(function(){
+ var frameworkTags = plugin.getFrameworks(self.platform);
+ var frameworkPods = frameworkTags.filter(function(obj){
+ return (obj.type == 'podspec');
+ });
+
+ return Q.resolve(frameworkPods);
+ })
+ .then(function(frameworkPods) {
+ if (!(frameworkPods.length)) {
+ return Q.resolve();
+ }
+
+ var project_dir = self.locations.root;
+ var project_name = self.locations.xcodeCordovaProj.split('/').pop();
+
+ var Podfile = require('./lib/Podfile').Podfile;
+ var PodsJson = require('./lib/PodsJson').PodsJson;
+
+ events.emit('verbose', 'Adding pods since the plugin contained <framework>(s) with type=\"podspec\"');
+
+ var podsjsonFile = new PodsJson(path.join(project_dir, PodsJson.FILENAME));
+ var podfileFile = new Podfile(path.join(project_dir, Podfile.FILENAME), project_name);
+
+ frameworkPods.forEach(function(obj) {
+ var podJson = {
+ name: obj.src,
+ type: obj.type,
+ spec: obj.spec
+ };
+
+ var val = podsjsonFile.get(podJson.name);
+ if (val) { // found, decrement count
+ podsjsonFile.decrement(podJson.name);
+ } else { // not found (perhaps a sync error)
+ var message = util.format('plugin \"%s\" podspec \"%s\" does not seem to be in pods.json, nothing to remove. Will attempt to remove from Podfile.', plugin.id, podJson.name);
+ events.emit('verbose', message);
+ }
+
+ // always remove from the Podfile
+ podfileFile.removeSpec(podJson.name);
+ });
+
+ // now that all the pods have been processed, write to pods.json
+ podsjsonFile.write();
+
+ if (podfileFile.isDirty()) {
+ podfileFile.write();
+ events.emit('verbose', 'Running `pod install` (to uninstall pods)');
+
+ var check_reqs = require('./lib/check_reqs');
+ return podfileFile.install(check_reqs.check_cocoapods);
+ } else {
+ events.emit('verbose', 'Podfile unchanged, skipping `pod install`');
+ }
+ })
+ // CB-11022 return non-falsy value to indicate
+ // that there is no need to run prepare after
+ .thenResolve(true);
+};
+
+/**
+ * Builds an application package for current platform.
+ *
+ * @param {Object} buildOptions A build options. This object's structure is
+ * highly depends on platform's specific. The most common options are:
+ * @param {Boolean} buildOptions.debug Indicates that packages should be
+ * built with debug configuration. This is set to true by default unless the
+ * 'release' option is not specified.
+ * @param {Boolean} buildOptions.release Indicates that packages should be
+ * built with release configuration. If not set to true, debug configuration
+ * will be used.
+ * @param {Boolean} buildOptions.device Specifies that built app is intended
+ * to run on device
+ * @param {Boolean} buildOptions.emulator: Specifies that built app is
+ * intended to run on emulator
+ * @param {String} buildOptions.target Specifies the device id that will be
+ * used to run built application.
+ * @param {Boolean} buildOptions.nobuild Indicates that this should be a
+ * dry-run call, so no build artifacts will be produced.
+ * @param {String[]} buildOptions.archs Specifies chip architectures which
+ * app packages should be built for. List of valid architectures is depends on
+ * platform.
+ * @param {String} buildOptions.buildConfig The path to build configuration
+ * file. The format of this file is depends on platform.
+ * @param {String[]} buildOptions.argv Raw array of command-line arguments,
+ * passed to `build` command. The purpose of this property is to pass a
+ * platform-specific arguments, and eventually let platform define own
+ * arguments processing logic.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.build = function (buildOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/build').run.call(self, buildOptions);
+ });
+};
+
+/**
+ * Builds an application package for current platform and runs it on
+ * specified/default device. If no 'device'/'emulator'/'target' options are
+ * specified, then tries to run app on default device if connected, otherwise
+ * runs the app on emulator.
+ *
+ * @param {Object} runOptions An options object. The structure is the same
+ * as for build options.
+ *
+ * @return {Promise} A promise either fulfilled if package was built and ran
+ * successfully, or rejected with CordovaError.
+ */
+Api.prototype.run = function(runOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/run').run.call(self, runOptions);
+ });
+};
+
+/**
+ * Cleans out the build artifacts from platform's directory.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError.
+ */
+Api.prototype.clean = function(cleanOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/clean').run.call(self, cleanOptions);
+ })
+ .then(function () {
+ return require('./lib/prepare').clean.call(self, cleanOptions);
+ });
+};
+
+/**
+ * Performs a requirements check for current platform. Each platform defines its
+ * own set of requirements, which should be resolved before platform can be
+ * built successfully.
+ *
+ * @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
+ * objects for current platform.
+ */
+Api.prototype.requirements = function() {
+ return require('./lib/check_reqs').check_all();
+};
+
+module.exports = Api;
diff --git a/StoneIsland/platforms/ios/cordova/build b/StoneIsland/platforms/ios/cordova/build
index 5007627f..61d26cca 100755
--- a/StoneIsland/platforms/ios/cordova/build
+++ b/StoneIsland/platforms/ios/cordova/build
@@ -19,18 +19,45 @@
under the License.
*/
-var build = require('./lib/build'),
- args = process.argv;
+var args = process.argv;
+var Api = require('./Api');
+var nopt = require('nopt');
+var path = require('path');
-// Handle help flag
-if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(args[2]) > -1) {
- build.help();
-} else {
- build.run(args).done(function() {
+// Support basic help commands
+if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+ require('./lib/build').help();
+ process.exit(0);
+}
+
+// Parse arguments
+var buildOpts = nopt({
+ 'verbose' : Boolean,
+ 'silent' : Boolean,
+ 'archs': String,
+ 'debug': Boolean,
+ 'release': Boolean,
+ 'device': Boolean,
+ 'emulator': Boolean,
+ 'codeSignIdentity': String,
+ 'codeSignResourceRules': String,
+ 'provisioningProfile': String,
+ 'developmentTeam': String,
+ 'packageType': String,
+ 'buildConfig' : String,
+ 'buildFlag' : [String, Array],
+ 'noSign' : Boolean
+}, { '-r': '--release', 'd' : '--verbose' }, args);
+
+// Make buildOptions compatible with PlatformApi build method spec
+buildOpts.argv = buildOpts.argv.remain;
+
+require('./loggingHelper').adjustLoggerLevel(buildOpts);
+
+new Api().build(buildOpts).done(function() {
console.log('** BUILD SUCCEEDED **');
}, function(err) {
var errorMessage = (err && err.stack) ? err.stack : err;
console.error(errorMessage);
process.exit(2);
});
-} \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/build-debug.xcconfig b/StoneIsland/platforms/ios/cordova/build-debug.xcconfig
index 124d020b..3f4767d2 100755
--- a/StoneIsland/platforms/ios/cordova/build-debug.xcconfig
+++ b/StoneIsland/platforms/ios/cordova/build-debug.xcconfig
@@ -22,4 +22,11 @@
//
#include "build.xcconfig"
+
+GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1
+
#include "build-extras.xcconfig"
+
+// (CB-11792)
+// @COCOAPODS_SILENCE_WARNINGS@ //
+#include "../pods-debug.xcconfig"
diff --git a/StoneIsland/platforms/ios/cordova/build-extras.xcconfig b/StoneIsland/platforms/ios/cordova/build-extras.xcconfig
index e69de29b..7e631112 100755
--- a/StoneIsland/platforms/ios/cordova/build-extras.xcconfig
+++ b/StoneIsland/platforms/ios/cordova/build-extras.xcconfig
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+
+//
+// Auto-generated config file to override configuration files (build-release/build-debug).
+//
diff --git a/StoneIsland/platforms/ios/cordova/build-release.xcconfig b/StoneIsland/platforms/ios/cordova/build-release.xcconfig
index 674aa796..70b0f073 100755
--- a/StoneIsland/platforms/ios/cordova/build-release.xcconfig
+++ b/StoneIsland/platforms/ios/cordova/build-release.xcconfig
@@ -27,3 +27,7 @@ CODE_SIGN_IDENTITY = iPhone Distribution
CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Distribution
#include "build-extras.xcconfig"
+
+// (CB-11792)
+// @COCOAPODS_SILENCE_WARNINGS@ //
+#include "../pods-release.xcconfig"
diff --git a/StoneIsland/platforms/ios/cordova/build.bat b/StoneIsland/platforms/ios/cordova/build.bat
new file mode 100755
index 00000000..2f97fcb4
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/build.bat
@@ -0,0 +1,19 @@
+:: 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
+
+@ECHO OFF
+ECHO WARN: The 'build' command is not available for cordova-ios on windows machines.>&2
diff --git a/StoneIsland/platforms/ios/cordova/build.xcconfig b/StoneIsland/platforms/ios/cordova/build.xcconfig
index 54a5abd4..bc9e0e3f 100755
--- a/StoneIsland/platforms/ios/cordova/build.xcconfig
+++ b/StoneIsland/platforms/ios/cordova/build.xcconfig
@@ -22,6 +22,10 @@
// Settings are overridden by configuration-level .xcconfig file (build-release/build-debug).
//
+HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/lib/include" "$(OBJROOT)/UninstalledProducts/include" "$(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include" "$(BUILT_PRODUCTS_DIR)"
+IPHONEOS_DEPLOYMENT_TARGET = 8.0
+OTHER_LDFLAGS = -ObjC
+TARGETED_DEVICE_FAMILY = 1,2
// Type of signing identity used for codesigning, resolves to first match of given type.
// "iPhone Developer": Development builds (default, local only; iOS Development certificate) or "iPhone Distribution": Distribution builds (Adhoc/In-House/AppStore; iOS Distribution certificate)
@@ -30,3 +34,12 @@ CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer
// (CB-9721) Set ENABLE_BITCODE to NO in build.xcconfig
ENABLE_BITCODE = NO
+
+// (CB-9719) Set CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES to YES in build.xcconfig
+CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES
+
+// (CB-10072)
+SWIFT_OBJC_BRIDGING_HEADER = $(PROJECT_DIR)/$(PROJECT_NAME)/Bridging-Header.h
+
+// (CB-11854)
+CODE_SIGN_ENTITLEMENTS = $(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-$(CONFIGURATION).plist
diff --git a/StoneIsland/platforms/ios/cordova/check_reqs b/StoneIsland/platforms/ios/cordova/check_reqs
index ba68ceb4..d101ccd1 100755
--- a/StoneIsland/platforms/ios/cordova/check_reqs
+++ b/StoneIsland/platforms/ios/cordova/check_reqs
@@ -23,10 +23,10 @@ var check_reqs = require('./lib/check_reqs');
// check for help flag
if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) > -1) {
- check_reqs.help();
+ console.log('Usage: check_reqs or node check_reqs');
} else {
check_reqs.run().done(null, function (err) {
console.error('Failed to check requirements due to ' + err);
process.exit(2);
});
-} \ No newline at end of file
+}
diff --git a/StoneIsland/platforms/ios/cordova/clean b/StoneIsland/platforms/ios/cordova/clean
index ae61078d..56665c48 100755
--- a/StoneIsland/platforms/ios/cordova/clean
+++ b/StoneIsland/platforms/ios/cordova/clean
@@ -19,11 +19,32 @@
under the License.
*/
-var clean = require('./lib/clean');
+var Api = require('./Api');
+var path = require('path');
+var nopt = require('nopt');
-clean.run(process.argv).done(function () {
+if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+ console.log('Cleans the project directory.');
+ process.exit(0);
+}
+
+// Do some basic argument parsing
+var opts = nopt({
+ 'verbose' : Boolean,
+ 'silent' : Boolean
+}, { 'd' : '--verbose' });
+
+// Make buildOptions compatible with PlatformApi clean method spec
+opts.argv = opts.argv.original;
+
+// Skip cleaning prepared files when not invoking via cordova CLI.
+opts.noPrepare = true;
+
+require('./loggingHelper').adjustLoggerLevel(opts);
+
+new Api().clean(opts).done(function() {
console.log('** CLEAN SUCCEEDED **');
}, function(err) {
console.error(err);
process.exit(2);
-}); \ No newline at end of file
+});
diff --git a/StoneIsland/platforms/ios/cordova/clean.bat b/StoneIsland/platforms/ios/cordova/clean.bat
index 25f17901..58307287 100755
--- a/StoneIsland/platforms/ios/cordova/clean.bat
+++ b/StoneIsland/platforms/ios/cordova/clean.bat
@@ -14,12 +14,6 @@
:: KIND, either express or implied. See the License for the
:: specific language governing permissions and limitations
:: under the License
+
@ECHO OFF
-SET script_path="%~dp0clean"
-IF EXIST %script_path% (
- node %script_path% %*
-) ELSE (
- ECHO.
- ECHO ERROR: Could not find 'clean' script in 'cordova' folder, aborting...>&2
- EXIT /B 1
-) \ No newline at end of file
+ECHO WARN: The 'clean' command is not available for cordova-ios on windows machines.>&2
diff --git a/StoneIsland/platforms/ios/cordova/defaults.xml b/StoneIsland/platforms/ios/cordova/defaults.xml
index c98d846b..f3ae2075 100755
--- a/StoneIsland/platforms/ios/cordova/defaults.xml
+++ b/StoneIsland/platforms/ios/cordova/defaults.xml
@@ -29,6 +29,8 @@
<preference name="KeyboardDisplayRequiresUserAction" value="true" />
<preference name="MediaPlaybackRequiresUserAction" value="false" />
<preference name="SuppressesIncrementalRendering" value="false" />
+ <preference name="SuppressesLongPressGesture" value="false" />
+ <preference name="Suppresses3DTouchGesture" value="false" />
<preference name="GapBetweenPages" value="0" />
<preference name="PageLength" value="0" />
<preference name="PaginationBreakingMode" value="page" /> <!-- page, column -->
@@ -37,4 +39,17 @@
<feature name="LocalStorage">
<param name="ios-package" value="CDVLocalStorage"/>
</feature>
+ <feature name="HandleOpenUrl">
+ <param name="ios-package" value="CDVHandleOpenURL"/>
+ <param name="onload" value="true"/>
+ </feature>
+ <feature name="IntentAndNavigationFilter">
+ <param name="ios-package" value="CDVIntentAndNavigationFilter"/>
+ <param name="onload" value="true"/>
+ </feature>
+ <feature name="GestureHandler">
+ <param name="ios-package" value="CDVGestureHandler"/>
+ <param name="onload" value="true"/>
+ </feature>
+
</widget>
diff --git a/StoneIsland/platforms/ios/cordova/lib/Podfile.js b/StoneIsland/platforms/ios/cordova/lib/Podfile.js
new file mode 100755
index 00000000..2cf254cc
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/Podfile.js
@@ -0,0 +1,230 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var fs = require('fs'),
+ path = require('path'),
+ util = require('util'),
+ events = require('cordova-common').events,
+ Q = require('q'),
+ superspawn = require('cordova-common').superspawn,
+ CordovaError = require('cordova-common').CordovaError;
+
+Podfile.FILENAME = 'Podfile';
+
+function Podfile(podFilePath, projectName) {
+ this.podToken = '##INSERT_POD##';
+
+ this.path = podFilePath;
+ this.projectName = projectName;
+ this.contents = null;
+ this.pods = null;
+ this.__dirty = false;
+
+ // check whether it is named Podfile
+ var 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));
+ }
+
+ if (!projectName) {
+ throw new CordovaError('Podfile: The projectName was not specified in the constructor.');
+ }
+
+ if (!fs.existsSync(this.path)) {
+ events.emit('verbose', util.format('Podfile: The file at %s does not exist.', this.path));
+ events.emit('verbose', 'Creating new Podfile in platforms/ios');
+ this.clear();
+ this.write();
+ } else {
+ events.emit('verbose', 'Podfile found in platforms/ios');
+ // parse for pods
+ this.pods = this.__parseForPods(fs.readFileSync(this.path, 'utf8'));
+ }
+}
+
+Podfile.prototype.__parseForPods = function(text) {
+ // split by \n
+ var 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 \'(\\w+)\'\\s*,?\\s*(.*)');
+
+ // only grab lines that don't have the pod spec'
+ return arr.filter(function(line) {
+ var m = podRE.exec(line);
+
+ return (m !== null);
+ })
+ .reduce(function(obj, line){
+ var m = podRE.exec(line);
+
+ if (m !== null) {
+ // strip out any single quotes around the value m[2]
+ var podSpec = m[2].replace(/^\'|\'$/g, '');
+ obj[m[1]] = podSpec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'}
+ }
+
+ return obj;
+ }, {});
+};
+
+Podfile.prototype.getTemplate = function() {
+ return util.format(
+ '# DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
+ 'platform :ios, \'8.0\'\n' +
+ 'target \'%s\' do\n' +
+ '\tproject \'%s.xcodeproj\'\n' +
+ '%s\n' +
+ 'end\n',
+ this.projectName, this.projectName, this.podToken);
+};
+
+Podfile.prototype.addSpec = function(name, spec) {
+ name = name || '';
+ spec = spec; // optional
+
+ if (!name.length) { // blank names are not allowed
+ throw new CordovaError('Podfile addSpec: name is not specified.');
+ }
+
+ this.pods[name] = spec;
+ this.__dirty = true;
+
+ events.emit('verbose', util.format('Added pod line for `%s`', name));
+};
+
+Podfile.prototype.removeSpec = function(name) {
+ if (this.existsSpec(name)) {
+ delete this.pods[name];
+ this.__dirty = true;
+ }
+
+ events.emit('verbose', util.format('Removed pod line for `%s`', name));
+};
+
+Podfile.prototype.getSpec = function(name) {
+ return this.pods[name];
+};
+
+Podfile.prototype.existsSpec = function(name) {
+ return (name in this.pods);
+};
+
+Podfile.prototype.clear = function() {
+ this.pods = {};
+ this.__dirty = true;
+};
+
+Podfile.prototype.destroy = function() {
+ fs.unlinkSync(this.path);
+ events.emit('verbose', util.format('Deleted `%s`', this.path));
+};
+
+Podfile.prototype.write = function() {
+ var text = this.getTemplate();
+ var self = this;
+
+ var podsString =
+ Object.keys(this.pods).map(function(key) {
+ var name = key;
+ var spec = self.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);
+ } else {
+ // quote it, it's a version
+ return util.format('\tpod \'%s\', \'%s\'', name, spec);
+ }
+ } else {
+ return util.format('\tpod \'%s\'', name);
+ }
+ })
+ .join('\n');
+
+ text = text.replace(this.podToken, podsString);
+ fs.writeFileSync(this.path, text, 'utf8');
+ this.__dirty = false;
+
+ events.emit('verbose', 'Wrote to Podfile.');
+};
+
+Podfile.prototype.isDirty = function() {
+ return this.__dirty;
+};
+
+Podfile.prototype.before_install = function() {
+ // Template tokens in order: project name, project name, debug | release
+ var 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');
+
+ var debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig');
+ var releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig');
+
+ fs.writeFileSync(debugConfigPath, debugContents, 'utf8');
+ fs.writeFileSync(releaseConfigPath, releaseContents, 'utf8');
+
+ return Q.resolve();
+};
+
+Podfile.prototype.install = function(requirementsCheckerFunction) {
+ var opts = {};
+ opts.cwd = path.join(this.path, '..'); // parent path of this Podfile
+ opts.stdio = 'pipe';
+ var first = true;
+ var self = this;
+
+ if (!requirementsCheckerFunction) {
+ requirementsCheckerFunction = Q();
+ }
+
+ return requirementsCheckerFunction()
+ .then(function() {
+ return self.before_install();
+ })
+ .then(function() {
+ return superspawn.spawn('pod', ['install', '--verbose'], opts)
+ .progress(function (stdio){
+ if (stdio.stderr) { console.error(stdio.stderr); }
+ if (stdio.stdout) {
+ if (first) {
+ events.emit('verbose', '==== pod install start ====\n');
+ first = false;
+ }
+ events.emit('verbose', stdio.stdout);
+ }
+ });
+ })
+ .then(function() { // done
+ events.emit('verbose', '==== pod install end ====\n');
+ })
+ .fail(function(error){
+ throw error;
+ });
+};
+
+module.exports.Podfile = Podfile; \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/lib/PodsJson.js b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js
new file mode 100755
index 00000000..b13a1afe
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/PodsJson.js
@@ -0,0 +1,115 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var fs = require('fs'),
+ path = require('path'),
+ util = require('util'),
+ events = require('cordova-common').events,
+ CordovaError = require('cordova-common').CordovaError;
+
+PodsJson.FILENAME = 'pods.json';
+
+function PodsJson(podsJsonPath) {
+ this.path = podsJsonPath;
+ this.contents = null;
+ this.__dirty = false;
+
+ var 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));
+ }
+
+ if (!fs.existsSync(this.path)) {
+ events.emit('verbose', util.format('pods.json: The file at %s does not exist.', this.path));
+ events.emit('verbose', 'Creating new pods.json in platforms/ios');
+ this.clear();
+ this.write();
+ } 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);
+ }
+}
+
+PodsJson.prototype.get = function(name) {
+ return this.contents[name];
+};
+
+PodsJson.prototype.remove = function(name) {
+ if (this.contents[name]) {
+ delete this.contents[name];
+ this.__dirty = true;
+ events.emit('verbose', util.format('Remove from pods.json for `%s`', name));
+ }
+};
+
+PodsJson.prototype.clear = function() {
+ this.contents = {};
+ this.__dirty = true;
+};
+
+PodsJson.prototype.destroy = function() {
+ fs.unlinkSync(this.path);
+ events.emit('verbose', util.format('Deleted `%s`', this.path));
+};
+
+PodsJson.prototype.write = function() {
+ if (this.contents) {
+ fs.writeFileSync(this.path, JSON.stringify(this.contents, null, 4));
+ this.__dirty = false;
+ events.emit('verbose', 'Wrote to pods.json.');
+ }
+};
+
+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);
+ if (val) {
+ val.count++;
+ this.setJson(val);
+ }
+};
+
+PodsJson.prototype.decrement = function(name) {
+ var val = this.get(name);
+ if (val) {
+ val.count--;
+ if (val.count <= 0) {
+ this.remove(name);
+ } else {
+ this.setJson(val);
+ }
+ }
+};
+
+PodsJson.prototype.setJson = function(name, json) {
+ this.contents[name] = json;
+ this.__dirty = true;
+ events.emit('verbose', util.format('Set pods.json for `%s`', name));
+};
+
+PodsJson.prototype.isDirty = function() {
+ return this.__dirty;
+};
+
+module.exports.PodsJson = PodsJson;
diff --git a/StoneIsland/platforms/ios/cordova/lib/build.js b/StoneIsland/platforms/ios/cordova/lib/build.js
index 2213ef8c..a26f1983 100755
--- a/StoneIsland/platforms/ios/cordova/lib/build.js
+++ b/StoneIsland/platforms/ios/cordova/lib/build.js
@@ -6,9 +6,9 @@
* 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
@@ -20,98 +20,170 @@
/*jshint node: true*/
var Q = require('q'),
- nopt = require('nopt'),
path = require('path'),
shell = require('shelljs'),
spawn = require('./spawn'),
- check_reqs = require('./check_reqs'),
- fs = require('fs');
+ fs = require('fs'),
+ plist = require('plist'),
+ util = require('util');
+
+var check_reqs;
+try {
+ check_reqs = require('./check_reqs');
+} catch (err) {
+ // For unit tests, check_reqs.js is not a sibling to build.js
+ check_reqs = require('../../../../lib/check_reqs');
+}
+
+var events = require('cordova-common').events;
var projectPath = path.join(__dirname, '..', '..');
var projectName = null;
-module.exports.run = function (argv) {
+// These are regular expressions to detect if the user is changing any of the built-in xcodebuildArgs
+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=.*)/
+};
- var args = nopt({
- // "archs": String, // TODO: add support for building different archs
- 'debug': Boolean,
- 'release': Boolean,
- 'device': Boolean,
- 'emulator': Boolean,
- 'codeSignIdentity': String,
- 'codeSignResourceRules': String,
- 'provisioningProfile': String,
- 'buildConfig' : String
- }, {'-r': '--release'}, argv);
+module.exports.run = function (buildOpts) {
- if (args.debug && args.release) {
- return Q.reject('Only one of "debug"/"release" options should be specified');
+ buildOpts = buildOpts || {};
+
+ if (buildOpts.debug && buildOpts.release) {
+ return Q.reject('Cannot specify "debug" and "release" options together.');
}
- if (args.device && args.emulator) {
- return Q.reject('Only one of "device"/"emulator" options should be specified');
+ if (buildOpts.device && buildOpts.emulator) {
+ return Q.reject('Cannot specify "device" and "emulator" options together.');
}
- if(args.buildConfig) {
- if(!fs.existsSync(args.buildConfig)) {
- return Q.reject('Build config file does not exist:' + args.buildConfig);
+ if(buildOpts.buildConfig) {
+ if(!fs.existsSync(buildOpts.buildConfig)) {
+ return Q.reject('Build config file does not exist:' + buildOpts.buildConfig);
}
- console.log('Reading build config file:', path.resolve(args.buildConfig));
- var buildConfig = JSON.parse(fs.readFileSync(args.buildConfig, 'utf-8'));
+ 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
if(buildConfig.ios) {
- var buildType = args.release ? 'release' : 'debug';
+ var buildType = buildOpts.release ? 'release' : 'debug';
var config = buildConfig.ios[buildType];
if(config) {
- ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile'].forEach(
+ ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType'].forEach(
function(key) {
- args[key] = args[key] || config[key];
+ buildOpts[key] = buildOpts[key] || config[key];
});
}
}
}
-
+
return check_reqs.run().then(function () {
return findXCodeProjectIn(projectPath);
}).then(function (name) {
projectName = name;
var extraConfig = '';
- if (args.codeSignIdentity) {
- extraConfig += 'CODE_SIGN_IDENTITY = ' + args.codeSignIdentity + '\n';
- extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + args.codeSignIdentity + '\n';
+ if (buildOpts.codeSignIdentity) {
+ extraConfig += 'CODE_SIGN_IDENTITY = ' + buildOpts.codeSignIdentity + '\n';
+ extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + buildOpts.codeSignIdentity + '\n';
}
- if (args.codeSignResourceRules) {
- extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + args.codeSignResourceRules + '\n';
+ if (buildOpts.codeSignResourceRules) {
+ extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + buildOpts.codeSignResourceRules + '\n';
}
- if (args.provisioningProfile) {
- extraConfig += 'PROVISIONING_PROFILE = ' + args.provisioningProfile + '\n';
+ if (buildOpts.provisioningProfile) {
+ extraConfig += 'PROVISIONING_PROFILE = ' + buildOpts.provisioningProfile + '\n';
+ }
+ if (buildOpts.developmentTeam) {
+ extraConfig += 'DEVELOPMENT_TEAM = ' + buildOpts.developmentTeam + '\n';
}
return Q.nfcall(fs.writeFile, path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8');
}).then(function () {
- var configuration = args.release ? 'Release' : 'Debug';
+ 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'));
+
+ var buildOutputDir = path.join(projectPath, 'build', 'device');
- console.log('Building project : ' + path.join(projectPath, projectName + '.xcodeproj'));
- console.log('\tConfiguration : ' + configuration);
- console.log('\tPlatform : ' + (args.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);
+ return spawn('xcodebuild', xcodebuildArgs, projectPath);
+ });
- var xcodebuildArgs = getXcodeArgs(projectName, projectPath, configuration, args.device);
- return spawn('xcodebuild', xcodebuildArgs, projectPath);
}).then(function () {
- if (!args.device) {
+ if (!buildOpts.device || buildOpts.noSign) {
return;
}
+
+ var exportOptions = {'compileBitcode': false, 'method': 'development'};
+
+ if (buildOpts.packageType) {
+ exportOptions.method = buildOpts.packageType;
+ }
+
+ if (buildOpts.developmentTeam) {
+ exportOptions.teamID = buildOpts.developmentTeam;
+ }
+
+ var exportOptionsPlist = plist.build(exportOptions);
+ var exportOptionsPath = path.join(projectPath, 'exportOptions.plist');
+
var buildOutputDir = path.join(projectPath, 'build', 'device');
- var pathToApp = path.join(buildOutputDir, projectName + '.app');
- var pathToIpa = path.join(buildOutputDir, projectName + '.ipa');
- var xcRunArgs = ['-sdk', 'iphoneos', 'PackageApplication',
- '-v', pathToApp,
- '-o', pathToIpa];
- if (args.codeSignIdentity) {
- xcRunArgs.concat('--sign', args.codeSignIdentity);
+
+
+ function checkSystemRuby() {
+ var ruby_cmd = shell.which('ruby');
+
+ if (ruby_cmd != '/usr/bin/ruby') {
+ events.emit('warn', 'Non-system Ruby in use. This may cause packaging to fail.\n' +
+ 'If you use RVM, please run `rvm use system`.\n' +
+ 'If you use chruby, please run `chruby system`.');
+ }
+ }
+
+ function packageArchive() {
+ var xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath);
+ return spawn('xcodebuild', xcodearchiveArgs, projectPath);
+ }
+
+ function unpackIPA() {
+ var 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);
}
- if (args.provisioningProfile) {
- xcRunArgs.concat('--embed', args.provisioningProfile);
+
+ function moveApp() {
+ var appFileInflated = path.join(buildOutputDir, 'Payload', projectName + '.app');
+ var appFile = path.join(buildOutputDir, projectName + '.app');
+ var 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);
+ });
}
- return spawn('xcrun', xcRunArgs, projectPath);
+
+ return Q.nfcall(fs.writeFile, exportOptionsPath, exportOptionsPlist, 'utf-8')
+ .then(checkSystemRuby)
+ .then(packageArchive)
+ .then(unpackIPA)
+ .then(moveApp);
});
};
@@ -125,12 +197,12 @@ function findXCodeProjectIn(projectPath) {
var xcodeProjFiles = shell.ls(projectPath).filter(function (name) {
return path.extname(name) === '.xcodeproj';
});
-
+
if (xcodeProjFiles.length === 0) {
return Q.reject('No Xcode project found in ' + projectPath);
}
if (xcodeProjFiles.length > 1) {
- console.warn('Found multiple .xcodeproj directories in \n' +
+ events.emit('warn','Found multiple .xcodeproj directories in \n' +
projectPath + '\nUsing first one');
}
@@ -148,38 +220,111 @@ module.exports.findXCodeProjectIn = findXCodeProjectIn;
* @param {Boolean} isDevice Flag that specify target for package (device/emulator)
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
-function getXcodeArgs(projectName, projectPath, configuration, isDevice) {
+function getXcodeBuildArgs(projectName, projectPath, configuration, isDevice, buildFlags) {
var xcodebuildArgs;
+ var options;
+ var buildActions;
+ var settings;
+ var 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) {
+ parseBuildFlag(flag, customArgs);
+ });
+ }
+ }
+
if (isDevice) {
- xcodebuildArgs = [
- '-xcconfig', path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-project', projectName + '.xcodeproj',
- 'ARCHS=armv7 armv7s arm64',
- '-target', projectName,
- '-configuration', configuration,
- '-sdk', 'iphoneos',
- 'build',
- 'VALID_ARCHS=armv7 armv7s arm64',
- 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'device'),
- 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ options = [
+ '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
+ '-workspace', customArgs.workspace || projectName + '.xcworkspace',
+ '-scheme', customArgs.scheme || projectName,
+ '-configuration', customArgs.configuration || configuration,
+ '-destination', customArgs.destination || 'generic/platform=iOS',
+ '-archivePath', customArgs.archivePath || projectName + '.xcarchive'
+ ];
+ 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')
];
+ // 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]);
+ }
} else { // emulator
- xcodebuildArgs = [
- '-xcconfig', path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-project', projectName + '.xcodeproj',
- 'ARCHS=i386',
- '-target', projectName ,
- '-configuration', configuration,
- '-sdk', 'iphonesimulator',
- 'build',
- 'VALID_ARCHS=i386',
- 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'emulator'),
- 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ options = [
+ '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
+ '-workspace', customArgs.project || projectName + '.xcworkspace',
+ '-scheme', customArgs.scheme || projectName,
+ '-configuration', customArgs.configuration || configuration,
+ '-sdk', customArgs.sdk || 'iphonesimulator',
+ '-destination', customArgs.destination || 'platform=iOS Simulator,name=iPhone 5s'
+ ];
+ 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')
];
+ // 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.archivePath) {
+ customArgs.otherFlags = customArgs.otherFlags.concat(['-archivePath', customArgs.archivePath]);
+ }
}
+ xcodebuildArgs = options.concat(buildActions).concat(settings).concat(customArgs.otherFlags);
return xcodebuildArgs;
}
+
+/**
+ * Returns array of arguments for xcodebuild
+ * @param {String} projectName Name of xcode project
+ * @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
+ * @return {Array} Array of arguments that could be passed directly to spawn method
+ */
+function getXcodeArchiveArgs(projectName, projectPath, outputPath, exportOptionsPath) {
+ return [
+ '-exportArchive',
+ '-archivePath', projectName + '.xcarchive',
+ '-exportOptionsPlist', exportOptionsPath,
+ '-exportPath', outputPath
+ ];
+}
+
+function parseBuildFlag(buildFlag, args) {
+ var matched;
+ for (var key in buildFlagMatchers) {
+ var found = buildFlag.match(buildFlagMatchers[key]);
+ if (found) {
+ matched = true;
+ // found[0] is the whole match, found[1] is the first match in parentheses.
+ args[key] = found[1];
+ events.emit('warn', util.format('Overriding xcodebuildArg: %s', buildFlag));
+ }
+ }
+
+ if (!matched) {
+ // If the flag starts with a '-' then it is an xcodebuild built-in option or a
+ // user-defined setting. The regex makes sure that we don't split a user-defined
+ // setting that is wrapped in quotes.
+ if (buildFlag[0] === '-' && !buildFlag.match(/^.*=(\".*\")|(\'.*\')$/)) {
+ args.otherFlags = args.otherFlags.concat(buildFlag.split(' '));
+ events.emit('warn', util.format('Adding xcodebuildArg: %s', buildFlag.split(' ')));
+ } else {
+ args.otherFlags.push(buildFlag);
+ events.emit('warn', util.format('Adding xcodebuildArg: %s', buildFlag));
+ }
+ }
+}
+
// help/usage function
module.exports.help = function help() {
console.log('');
@@ -198,6 +343,7 @@ module.exports.help = function help() {
console.log(' --codeSignIdentity : Type of signing identity used for code signing.');
console.log(' --codeSignResourceRules : Path to ResourceRules.plist.');
console.log(' --provisioningProfile : UUID of the profile.');
+ console.log(' --device --noSign : Builds project without application signing.');
console.log('');
console.log('examples:');
console.log(' build ');
diff --git a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
index d1f6333c..ae21f989 100755
--- a/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
+++ b/StoneIsland/platforms/ios/cordova/lib/check_reqs.js
@@ -19,22 +19,28 @@
var Q = require('q'),
shell = require('shelljs'),
+ util = require('util'),
versions = require('./versions');
-var XCODEBUILD_MIN_VERSION = '4.6.0';
+var XCODEBUILD_MIN_VERSION = '7.0.0';
var XCODEBUILD_NOT_FOUND_MESSAGE =
'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store';
-var IOS_SIM_MIN_VERSION = '3.0.0';
-var IOS_SIM_NOT_FOUND_MESSAGE =
- 'Please download, build and install version ' + IOS_SIM_MIN_VERSION + ' or greater' +
- ' from https://github.com/phonegap/ios-sim into your path, or do \'npm install -g ios-sim\'';
-
-var IOS_DEPLOY_MIN_VERSION = '1.4.0';
+var IOS_DEPLOY_MIN_VERSION = '1.9.0';
var 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\'';
+var COCOAPODS_MIN_VERSION = '1.0.1';
+var COCOAPODS_NOT_FOUND_MESSAGE =
+ 'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/';
+var 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.';
+var COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes
+var 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.';
+var COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.';
+
/**
* Checks if xcode util is available
* @return {Promise} Returns a promise either resolved with xcode version or rejected
@@ -51,14 +57,6 @@ module.exports.check_ios_deploy = function () {
return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE);
};
-/**
- * Checks if ios-sim util is available
- * @return {Promise} Returns a promise either resolved with ios-sim version or rejected
- */
-module.exports.check_ios_sim = function () {
- return checkTool('ios-sim', IOS_SIM_MIN_VERSION, IOS_SIM_NOT_FOUND_MESSAGE);
-};
-
module.exports.check_os = function () {
// Build iOS apps available for OSX platform only, so we reject on others platforms
return process.platform === 'darwin' ?
@@ -66,29 +64,81 @@ module.exports.check_os = function () {
Q.reject('Cordova tooling for iOS requires Apple OS X');
};
-module.exports.help = function () {
- console.log('Usage: check_reqs or node check_reqs');
+function check_cocoapod_tool() {
+ return checkTool('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods');
+}
+
+/**
+ * Checks if cocoapods repo size is what is expected
+ * @return {Promise} Returns a promise either resolved or rejected
+ */
+module.exports.check_cocoapods_repo_size = function () {
+ return check_cocoapod_tool()
+ .then(function() {
+ // check size of ~/.cocoapods repo
+ var commandString = util.format('du -sh %s/.cocoapods', process.env.HOME);
+ var command = shell.exec(commandString, { silent:true });
+ if (command.code !== 0) { // error, perhaps not found
+ return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output));
+ } else { // success, parse output
+ // command.output is e.g "750M path/to/.cocoapods", we just scan the number
+ return Q.resolve(parseFloat(command.output));
+ }
+ })
+ .then(function(repoSize) {
+ if (COCOAPODS_SYNCED_MIN_SIZE > repoSize) {
+ return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE);
+ } else {
+ return Q.resolve();
+ }
+ });
+};
+
+/**
+ * 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 () {
+ return check_cocoapod_tool()
+ // 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() {
+ var code = shell.exec('pod repo | grep -e "^0 repos"', { silent:true }).code;
+ return Q.resolve(code !== 0); // non-zero means it is synced (has 1 repo at least)
+ })
+ .then(function(repoIsSynced) {
+ if (repoIsSynced) {
+ // return check_cocoapods_repo_size();
+ // we could check the repo size above, but it takes too long.
+ return Q.resolve();
+ } else {
+ return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE);
+ }
+ });
};
/**
* Checks if specific tool is available.
- * @param {String} tool Tool name to check. Known tools are 'xcodebuild', 'ios-sim' and 'ios-deploy'
+ * @param {String} tool Tool name to check. Known tools are 'xcodebuild' and 'ios-deploy'
* @param {Number} minVersion Min allowed tool version.
* @param {String} message Message that will be used to reject promise.
+ * @param {String} toolFriendlyName Friendly name of the tool, to report to the user. Optional.
* @return {Promise} Returns a promise either resolved with tool version or rejected
*/
-function checkTool (tool, minVersion, message) {
+function checkTool (tool, minVersion, message, toolFriendlyName) {
+ toolFriendlyName = toolFriendlyName || tool;
+
// Check whether tool command is available at all
var tool_command = shell.which(tool);
if (!tool_command) {
- return Q.reject(tool + ' was not found. ' + (message || ''));
+ return Q.reject(toolFriendlyName + ' was not found. ' + (message || ''));
}
// check if tool version is greater than specified one
return versions.get_tool_version(tool).then(function (version) {
version = version.trim();
return versions.compareVersions(version, minVersion) >= 0 ?
Q.resolve(version) :
- Q.reject('Cordova needs ' + tool + ' version ' + minVersion +
+ Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion +
' or greater, you have version ' + version + '. ' + (message || ''));
});
}
@@ -120,7 +170,7 @@ module.exports.check_all = function() {
new Requirement('os', 'Apple OS X', true),
new Requirement('xcode', 'Xcode'),
new Requirement('ios-deploy', 'ios-deploy'),
- new Requirement('ios-sim', 'ios-sim')
+ new Requirement('CocoaPods', 'CocoaPods')
];
var result = [];
@@ -130,7 +180,7 @@ module.exports.check_all = function() {
module.exports.check_os,
module.exports.check_xcodebuild,
module.exports.check_ios_deploy,
- module.exports.check_ios_sim
+ module.exports.check_cocoapods
];
// Then execute requirement checks one-by-one
diff --git a/StoneIsland/platforms/ios/cordova/lib/clean.js b/StoneIsland/platforms/ios/cordova/lib/clean.js
index 6d955cf1..7c8cf56e 100755
--- a/StoneIsland/platforms/ios/cordova/lib/clean.js
+++ b/StoneIsland/platforms/ios/cordova/lib/clean.js
@@ -22,8 +22,7 @@
var Q = require('q'),
path = require('path'),
shell = require('shelljs'),
- spawn = require('./spawn'),
- check_reqs = require('./check_reqs');
+ spawn = require('./spawn');
var projectPath = path.join(__dirname, '..', '..');
@@ -36,9 +35,8 @@ module.exports.run = function() {
return Q.reject('No Xcode project found in ' + projectPath);
}
- return check_reqs.run().then(function() {
- return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Debug', '-alltargets', 'clean'], projectPath);
- }).then(function () {
+ 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'));
diff --git a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js b/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js
index 7a81b93e..7caa200f 100755
--- a/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js
+++ b/StoneIsland/platforms/ios/cordova/lib/copy-www-build-step.js
@@ -32,7 +32,6 @@ var BUILT_PRODUCTS_DIR = process.env.BUILT_PRODUCTS_DIR,
var path = require('path'),
fs = require('fs'),
shell = require('shelljs'),
- glob = require('glob'),
srcDir = 'www',
dstDir = path.join(BUILT_PRODUCTS_DIR, FULL_PRODUCT_NAME),
dstWwwDir = path.join(dstDir, 'www');
@@ -46,7 +45,7 @@ try {
fs.statSync(srcDir);
} catch (e) {
console.error('Path does not exist: ' + srcDir);
- process.exit(1);
+ process.exit(2);
}
// Code signing files must be removed or else there are
@@ -57,11 +56,16 @@ shell.rm('-rf', path.join(dstDir, 'PkgInfo'));
shell.rm('-rf', path.join(dstDir, 'embedded.mobileprovision'));
// Copy www dir recursively
+var code;
if(!!COPY_HIDDEN) {
- shell.mkdir('-p', dstWwwDir);
- shell.cp('-r', glob.sync(srcDir + '/**', { dot: true }), dstWwwDir);
+ code = shell.exec('rsync -Lra "' + srcDir + '" "' + dstDir + '"').code;
} else {
- shell.cp('-r', srcDir, dstDir);
+ 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.
diff --git a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
index 07dd1a48..87a5ad27 100755
--- a/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
+++ b/StoneIsland/platforms/ios/cordova/lib/list-emulator-images
@@ -22,6 +22,7 @@
/*jshint node: true*/
var Q = require('q'),
+ iossim = require('ios-sim'),
exec = require('child_process').exec,
check_reqs = require('./check_reqs');
@@ -30,15 +31,10 @@ var Q = require('q'),
* @return {Promise} Promise fulfilled with list of devices available for simulation
*/
function listEmulatorImages () {
- return check_reqs.check_ios_sim().then(function () {
- return Q.nfcall(exec, 'ios-sim showdevicetypes 2>&1 | ' +
- 'sed "s/com.apple.CoreSimulator.SimDeviceType.//g"');
- }).then(function (stdio) {
- // Exec promise resolves with array [stout, stderr], and we need stdout only
- return stdio[0].trim().split('\n');
- });
+ return Q.resolve(iossim.getdevicetypes());
}
+
exports.run = listEmulatorImages;
// Check if module is started as separate script.
diff --git a/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js
new file mode 100755
index 00000000..297e3863
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/plugman/pluginHandlers.js
@@ -0,0 +1,375 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
+// These frameworks are required by cordova-ios by default. We should never add/remove them.
+var keep_these_frameworks = [
+ 'MobileCoreServices.framework',
+ 'CoreGraphics.framework',
+ 'AssetsLibrary.framework'
+];
+
+var handlers = {
+ 'source-file':{
+ install:function(obj, plugin, project, options) {
+ installHelper('source-file', obj, plugin.dir, project.projectDir, plugin.id, options, project);
+ },
+ uninstall:function(obj, plugin, project, options) {
+ uninstallHelper('source-file', obj, project.projectDir, plugin.id, options, project);
+ }
+ },
+ 'header-file':{
+ install:function(obj, plugin, project, options) {
+ installHelper('header-file', obj, plugin.dir, project.projectDir, plugin.id, options, project);
+ },
+ uninstall:function(obj, plugin, project, options) {
+ uninstallHelper('header-file', obj, project.projectDir, plugin.id, options, project);
+ }
+ },
+ 'resource-file':{
+ install:function(obj, plugin, project, options) {
+ var src = obj.src,
+ srcFile = path.resolve(plugin.dir, src),
+ destFile = path.resolve(project.resources_dir, path.basename(src));
+ if (!fs.existsSync(srcFile)) 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 detination "' + destFile + '" for resource file specified by plugin ' + plugin.id + ' in iOS platform');
+ project.xcode.addResourceFile(path.join('Resources', path.basename(src)));
+ var link = !!(options && options.link);
+ copyFile(plugin.dir, src, project.projectDir, destFile, link);
+ },
+ uninstall:function(obj, plugin, project, options) {
+ var src = obj.src,
+ destFile = path.resolve(project.resources_dir, path.basename(src));
+ project.xcode.removeResourceFile(path.join('Resources', path.basename(src)));
+ shell.rm('-rf', destFile);
+ }
+ },
+ 'framework':{ // CB-5238 custom frameworks only
+ install:function(obj, plugin, project, options) {
+ var src = obj.src,
+ custom = obj.custom;
+ if (!custom) {
+ var keepFrameworks = keep_these_frameworks;
+
+ if (keepFrameworks.indexOf(src) < 0) {
+ if (obj.type === 'podspec') {
+ //podspec handled in Api.js
+ } else {
+ project.frameworks[src] = project.frameworks[src] || 0;
+ project.frameworks[src]++;
+ project.xcode.addFramework(src, {weak: obj.weak});
+ }
+ }
+ return;
+ }
+ var srcFile = path.resolve(plugin.dir, src),
+ 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 link = !!(options && options.link);
+ copyFile(plugin.dir, src, project.projectDir, targetDir, link); // frameworks are directories
+ // CB-10773 translate back slashes to forward on win32
+ var project_relative = fixPathSep(path.relative(project.projectDir, targetDir));
+ var pbxFile = project.xcode.addFramework(project_relative, {customFramework: true});
+ if (pbxFile) {
+ project.xcode.addToPbxEmbedFrameworksBuildPhase(pbxFile);
+ }
+ },
+ uninstall:function(obj, plugin, project, options) {
+ var src = obj.src;
+
+ if (!obj.custom) { //CB-9825 cocoapod integration for plugins
+ var 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 {
+ //this should be refactored
+ project.frameworks[src] = project.frameworks[src] || 1;
+ project.frameworks[src]--;
+ if (project.frameworks[src] < 1) {
+ // Only remove non-custom framework from xcode project
+ // if there is no references remains
+ project.xcode.removeFramework(src);
+ delete project.frameworks[src];
+ }
+ }
+ }
+ return;
+ }
+
+ var targetDir = fixPathSep(path.resolve(project.plugins_dir, plugin.id, path.basename(src))),
+ pbxFile = project.xcode.removeFramework(targetDir, {customFramework: true});
+ if (pbxFile) {
+ project.xcode.removeFromPbxEmbedFrameworksBuildPhase(pbxFile);
+ }
+ shell.rm('-rf', targetDir);
+ }
+ },
+ 'lib-file': {
+ install:function(obj, plugin, project, options) {
+ events.emit('verbose', '<lib-file> install is not supported for iOS plugins');
+ },
+ uninstall:function(obj, plugin, project, options) {
+ events.emit('verbose', '<lib-file> uninstall is not supported for iOS plugins');
+ }
+ },
+ 'asset':{
+ install:function(obj, plugin, project, options) {
+ if (!obj.src) {
+ throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
+ }
+ if (!obj.target) {
+ throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+ }
+
+ copyFile(plugin.dir, obj.src, project.www, obj.target);
+ if (options && options.usePlatformWww) copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
+ },
+ uninstall:function(obj, plugin, project, options) {
+ var target = obj.target;
+
+ if (!target) {
+ throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+ }
+
+ removeFile(project.www, target);
+ removeFileF(path.resolve(project.www, 'plugins', plugin.id));
+ if (options && options.usePlatformWww) {
+ removeFile(project.platformWww, target);
+ removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
+ }
+ }
+ },
+ '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)));
+
+ // Read in the file, prepend the cordova.define, and write it back out.
+ var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+ if (moduleSource.match(/.*\.json$/)) {
+ scriptContent = 'module.exports = ' + scriptContent;
+ }
+ 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));
+ 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));
+ fs.writeFileSync(platformWwwDestination, scriptContent, 'utf-8');
+ }
+ },
+ uninstall: function (obj, plugin, project, options) {
+ var 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) {
+ if (handlers[type] && handlers[type].install) {
+ return handlers[type].install;
+ }
+
+ events.emit('warn', '<' + type + '> is not supported for iOS plugins');
+};
+
+module.exports.getUninstaller = function(type) {
+ if (handlers[type] && handlers[type].uninstall) {
+ return handlers[type].uninstall;
+ }
+
+ 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));
+
+ var project_ref;
+ var link = !!(options && options.link);
+ if (link) {
+ var 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);
+ } else {
+ copyNewFile(plugin_dir, trueSrc, project_dir, destFile, link);
+ }
+ // Xcode won't save changes to a file if there is a symlink involved.
+ // 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));
+ } 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));
+ }
+
+ 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);
+ project.xcode.addFramework(project_relative, opt);
+ project.xcode.addToLibrarySearchPaths({path:project_ref});
+ } else {
+ 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));
+
+ var project_ref;
+ var link = !!(options && options.link);
+ if (link) {
+ var 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));
+ }
+
+ shell.rm('-rf', 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);
+ project.xcode.removeFramework(project_relative);
+ project.xcode.removeFromLibrarySearchPaths({path:project_ref});
+ } else {
+ project.xcode.removeSourceFile(project_ref);
+ }
+}
+
+var 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!');
+
+ // 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 + '"');
+
+ 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');
+
+ shell.mkdir('-p', path.dirname(dest));
+
+ if (link) {
+ symlinkFileOrDirTree(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);
+ }
+}
+
+// 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!');
+
+ copyFile(plugin_dir, src, project_dir, dest, !!link);
+}
+
+function symlinkFileOrDirTree(src, dest) {
+ if (fs.existsSync(dest)) {
+ shell.rm('-Rf', dest);
+ }
+
+ if (fs.statSync(src).isDirectory()) {
+ shell.mkdir('-p', dest);
+ fs.readdirSync(src).forEach(function(entry) {
+ symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
+ });
+ }
+ else {
+ fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), 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);
+}
+
+// deletes file/directory without checking
+function removeFileF (file) {
+ shell.rm('-Rf', file);
+}
+
+function removeFileAndParents (baseDir, destFile, stopper) {
+ stopper = stopper || '.';
+ var file = path.resolve(baseDir, destFile);
+ if (!fs.existsSync(file)) return;
+
+ removeFileF(file);
+
+ // check if directory is empty
+ var curDir = path.dirname(file);
+
+ while(curDir !== path.resolve(baseDir, stopper)) {
+ if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
+ fs.rmdirSync(curDir);
+ curDir = path.resolve(curDir, '..');
+ } else {
+ // directory not empty...do nothing
+ break;
+ }
+ }
+}
+
+function generateAttributeError(attribute, element, 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
new file mode 100755
index 00000000..8d1cda94
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/prepare.js
@@ -0,0 +1,1003 @@
+/**
+ 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 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;
+
+/*jshint sub:true*/
+
+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());
+
+ 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);
+ })
+ .then(function () {
+ updateIcons(cordovaProject, self.locations);
+ updateSplashScreens(cordovaProject, self.locations);
+ updateLaunchStoryboardImages(cordovaProject, self.locations);
+ })
+ .then(function () {
+ events.emit('verbose', 'Prepared iOS project successfully');
+ });
+};
+
+module.exports.clean = function (options) {
+ // A cordovaProject isn't passed into the clean() function, because it might have
+ // 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');
+ if ((options && options.noPrepare) || !fs.existsSync(projectConfigFile) ||
+ !fs.existsSync(this.locations.configXml)) {
+ return Q();
+ }
+
+ var 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);
+ });
+};
+
+/**
+ * Updates config files in project based on app's config.xml and config munge,
+ * generated by plugins.
+ *
+ * @param {ConfigParser} sourceConfig A project's configuration that will
+ * be merged into platform's config.xml
+ * @param {ConfigChanges} configMunger An initialized ConfigChanges instance
+ * for this platform.
+ * @param {Object} locations A map of locations for this platform
+ *
+ * @return {ConfigParser} An instance of ConfigParser, that
+ * represents current project's configuration. When returned, the
+ * 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);
+
+ // 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);
+
+ // Then apply config changes from global munge to all config files
+ // in project (including project's config)
+ configMunger.reapply_global_munge().save_all();
+
+ 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);
+ xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+ config.doc.getroot(), 'ios', /*clobber=*/true);
+
+ config.write();
+ return config;
+}
+
+/**
+ * Logs all file operations via the verbose event stream, indented.
+ */
+function logFileOp(message) {
+ events.emit('verbose', ' ' + message);
+}
+
+/**
+ * Updates platform 'www' directory by replacing it with contents of
+ * 'platform_www' and app www. Also copies project's overrides' folder into
+ * the platform 'www' folder
+ *
+ * @param {Object} cordovaProject An object which describes cordova project.
+ * @param {boolean} destinations An object that contains destinations
+ * paths for www files.
+ */
+function updateWww(cordovaProject, destinations) {
+ var 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');
+ 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);
+ events.emit(
+ 'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+ FileUpdater.mergeAndUpdateDir(
+ sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+/**
+ * Cleans all files from the platform 'www' directory.
+ */
+function cleanWww(projectRoot, locations) {
+ var 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(
+ [], targetDir, { rootDir: projectRoot, all: true }, logFileOp);
+}
+
+/**
+ * Updates project structure and AndroidManifest according to project's configuration.
+ *
+ * @param {ConfigParser} platformConfig A project's configuration that will
+ * be used to update project
+ * @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 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;
+
+ // Update version (bundle version)
+ infoPlist['CFBundleShortVersionString'] = version;
+ var CFBundleVersion = platformConfig.getAttribute('ios-CFBundleVersion') || default_CFBundleVersion(version);
+ infoPlist['CFBundleVersion'] = CFBundleVersion;
+
+ if (platformConfig.getAttribute('defaultlocale')) {
+ infoPlist['CFBundleDevelopmentRegion'] = platformConfig.getAttribute('defaultlocale');
+ }
+
+ // replace Info.plist ATS entries according to <access> and <allow-navigation> config.xml entries
+ var ats = writeATSEntries(platformConfig);
+ if (Object.keys(ats).length > 0) {
+ infoPlist['NSAppTransportSecurity'] = ats;
+ } else {
+ delete infoPlist['NSAppTransportSecurity'];
+ }
+
+ handleOrientationSettings(platformConfig, infoPlist);
+ updateProjectPlistForLaunchStoryboard(platformConfig, infoPlist);
+
+ var info_contents = plist.build(infoPlist);
+ 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);
+
+ return handleBuildSettings(platformConfig, locations).then(function() {
+ if (name == originalName) {
+ events.emit('verbose', 'iOS Product Name has not changed (still "' + originalName + '")');
+ return Q();
+ } else { // CB-11712 <name> was changed, we don't support it'
+ var 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'
+ ;
+
+ return Q.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' ];
+ break;
+ case 'landscape':
+ 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' ];
+ break;
+ case 'default':
+ infoPlist['UISupportedInterfaceOrientations'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
+ infoPlist['UISupportedInterfaceOrientations~ipad'] = [ 'UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown', 'UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight' ];
+ delete infoPlist['UIInterfaceOrientation'];
+ }
+}
+
+function handleBuildSettings(platformConfig, locations) {
+ var targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios'));
+ var deploymentTarget = platformConfig.getPreference('deployment-target', 'ios');
+
+ // no build settings provided, we don't need to parse and update .pbxproj file
+ if (!targetDevice && !deploymentTarget) {
+ return Q();
+ }
+
+ var proj = new xcode.project(locations.pbxproj);
+
+ try {
+ proj.parseSync();
+ } catch (err) {
+ return Q.reject(new CordovaError('Could not parse project.pbxproj: ' + err));
+ }
+
+ if (targetDevice) {
+ events.emit('verbose', 'Set TARGETED_DEVICE_FAMILY to ' + targetDevice + '.');
+ proj.updateBuildProperty('TARGETED_DEVICE_FAMILY', targetDevice);
+ }
+
+ if (deploymentTarget) {
+ events.emit('verbose', 'Set IPHONEOS_DEPLOYMENT_TARGET to "' + deploymentTarget + '".');
+ proj.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget);
+ }
+
+ fs.writeFileSync(locations.pbxproj, proj.writeSync(), 'utf-8');
+
+ return Q();
+}
+
+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-60@2x.png', width: 120, height: 120},
+ {dest: 'icon-60@3x.png', width: 180, height: 180},
+ {dest: 'icon-76.png', width: 76, height: 76},
+ {dest: 'icon-76@2x.png', width: 152, height: 152},
+ {dest: 'icon-small.png', width: 29, height: 29},
+ {dest: 'icon-small@2x.png', width: 58, height: 58},
+ {dest: 'icon-40.png', width: 40, height: 40},
+ {dest: 'icon-40@2x.png', width: 80, height: 80},
+ {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: 'icon-72.png', width: 72, height: 72},
+ {dest: 'icon-72@2x.png', width: 144, height: 144},
+ {dest: 'icon-50.png', width: 50, height: 50},
+ {dest: 'icon-50@2x.png', width: 100, height: 100},
+ {dest: 'icon-83.5@2x.png', width: 167, height: 167}
+ ];
+
+ var pathMap = {};
+ platformIcons.forEach(function (item) {
+ var icon = icons.getBySize(item.width, item.height) || icons.getDefault();
+ if (icon) {
+ var target = path.join(iconsDir, item.dest);
+ pathMap[target] = icon.src;
+ }
+ });
+ return pathMap;
+}
+
+function getIconsDir(projectRoot, platformProjDir) {
+ var iconsDir;
+ var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+
+ if (xcassetsExists) {
+ iconsDir = path.join(platformProjDir, 'Images.xcassets/AppIcon.appiconset/');
+ } else {
+ iconsDir = path.join(platformProjDir, 'Resources/icons/');
+ }
+
+ return iconsDir;
+}
+
+function updateIcons(cordovaProject, locations) {
+ var 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);
+ FileUpdater.updatePaths(
+ resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function cleanIcons(projectRoot, projectConfig, locations) {
+ var 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) {
+ resourceMap[targetIconPath] = null;
+ });
+ events.emit('verbose', 'Cleaning icons at ' + iconsDir);
+
+ // Source paths are removed from the map, so updatePaths() will delete the target files.
+ FileUpdater.updatePaths(
+ resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+ }
+}
+
+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;
+}
+
+function getSplashScreensDir(projectRoot, platformProjDir) {
+ var splashScreensDir;
+ var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+
+ if (xcassetsExists) {
+ splashScreensDir = path.join(platformProjDir, 'Images.xcassets/LaunchImage.launchimage/');
+ } else {
+ splashScreensDir = path.join(platformProjDir, 'Resources/splash/');
+ }
+
+ return splashScreensDir;
+}
+
+function updateSplashScreens(cordovaProject, locations) {
+ var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios');
+
+ if (splashScreens.length === 0) {
+ events.emit('verbose', 'This app does not have splash screens defined');
+ return;
+ }
+
+ 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);
+}
+
+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);
+
+ // Source paths are removed from the map, so updatePaths() will delete the target files.
+ FileUpdater.updatePaths(
+ resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+ }
+}
+
+/**
+ * Returns an array of images for each possible idiom, scale, and size class. The images themselves are
+ * located in the platform's splash images by their pattern (@scale~idiom~sizesize). All possible
+ * combinations are returned, but not all will have a `filename` property. If the latter isn't present,
+ * the device won't attempt to load an image matching the same traits. If the filename is present,
+ * the device will try to load the image if it corresponds to the traits.
+ *
+ * The resulting return looks like this:
+ *
+ * [
+ * {
+ * idiom: 'universal|ipad|iphone',
+ * scale: '1x|2x|3x',
+ * width: 'any|com',
+ * 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'
+ * }, ...
+ * ]
+ *
+ * @param {Array<Object>} splashScreens splash screens as defined in config.xml for this platform
+ * @param {string} launchStoryboardImagesDir project-root/Images.xcassets/LaunchStoryboard.imageset/
+ * @return {Array<Object>}
+ */
+function mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir) {
+ var platformLaunchStoryboardImages = [];
+ var idioms = ['universal', 'ipad', 'iphone'];
+ var scalesForIdiom = {
+ universal: ['1x', '2x', '3x'],
+ ipad: ['1x', '2x'],
+ iphone: ['1x', '2x', '3x']
+ };
+ var sizes = ['com', 'any'];
+
+ 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
+ };
+
+ /* 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;
+
+ /* 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);
+
+ if (launchStoryboardImage) {
+ item.filename = 'Default' + searchPattern + '.png';
+ item.src = launchStoryboardImage.src;
+ item.target = path.join(launchStoryboardImagesDir, item.filename);
+ }
+
+ platformLaunchStoryboardImages.push(item);
+ });
+ });
+ });
+ });
+ return platformLaunchStoryboardImages;
+}
+
+/**
+ * Returns a dictionary representing the source and destination paths for the launch storyboard images
+ * that need to be copied.
+ *
+ * The resulting return looks like this:
+ *
+ * {
+ * 'target-path': 'source-path',
+ * ...
+ * }
+ *
+ * @param {Array<Object>} splashScreens splash screens as defined in config.xml for this platform
+ * @param {string} launchStoryboardImagesDir project-root/Images.xcassets/LaunchStoryboard.imageset/
+ * @return {Object}
+ */
+function mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir) {
+ var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
+ var pathMap = {};
+ platformLaunchStoryboardImages.forEach(function (item) {
+ if (item.target) {
+ pathMap[item.target] = item.src;
+ }
+ });
+ return pathMap;
+}
+
+/**
+ * Builds the object that represents the contents.json file for the LaunchStoryboard image set.
+ *
+ * The resulting return looks like this:
+ *
+ * {
+ * images: [
+ * {
+ * idiom: 'universal|ipad|iphone',
+ * scale: '1x|2x|3x',
+ * width-class: undefined|'compact',
+ * height-class: undefined|'compact'
+ * }, ...
+ * ],
+ * info: {
+ * author: 'Xcode',
+ * version: 1
+ * }
+ * }
+ *
+ * A bit of minor logic is used to map from the array of images returned from mapLaunchStoryboardContents
+ * to the format requried by Xcode.
+ *
+ * @param {Array<Object>} splashScreens splash screens as defined in config.xml for this platform
+ * @param {string} launchStoryboardImagesDir project-root/Images.xcassets/LaunchStoryboard.imageset/
+ * @return {Object}
+ */
+function getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir) {
+ var IMAGESET_COMPACT_SIZE_CLASS = 'compact';
+ var CDV_ANY_SIZE_CLASS = 'any';
+
+ var platformLaunchStoryboardImages = mapLaunchStoryboardContents(splashScreens, launchStoryboardImagesDir);
+ var contentsJSON = {
+ images: [],
+ info: {
+ author: 'Xcode',
+ version: 1
+ }
+ };
+ contentsJSON.images = platformLaunchStoryboardImages.map(function(item) {
+ var newItem = {
+ idiom: item.idiom,
+ scale: item.scale
+ };
+
+ // Xcode doesn't want any size class property if the class is "any"
+ // If our size class is "com", Xcode wants "compact".
+ if (item.width !== CDV_ANY_SIZE_CLASS) {
+ newItem['width-class'] = IMAGESET_COMPACT_SIZE_CLASS;
+ }
+ if (item.height !== CDV_ANY_SIZE_CLASS) {
+ newItem['height-class'] = IMAGESET_COMPACT_SIZE_CLASS;
+ }
+
+ // Xcode doesn't want a filename property if there's no image for these traits
+ if (item.filename) {
+ newItem.filename = item.filename;
+ }
+ return newItem;
+ });
+ return contentsJSON;
+}
+
+/**
+ * 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 UI_LAUNCH_STORYBOARD_NAME = 'UILaunchStoryboardName';
+ var CDV_LAUNCH_STORYBOARD_NAME = 'CDVLaunchScreen';
+
+ var splashScreens = platformConfig.getSplashScreens('ios');
+ var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, ''); // note: we don't need a file path here; we're just counting
+ var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME];
+
+ events.emit('verbose', 'Current launch storyboard ' + currentLaunchStoryboard);
+
+
+ /* 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:
+ * var hasLaunchStoryboardImages = !!contentsJSON.images.find(function (item) {
+ * return item.filename !== undefined;
+ * });
+ */
+ var hasLaunchStoryboardImages = !!contentsJSON.images.reduce(function (p, c) {
+ return (c.filename !== undefined) ? c : p;
+ }, undefined);
+
+ 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 project 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 project to use launch images');
+ infoPlist[UI_LAUNCH_STORYBOARD_NAME] = undefined;
+ return;
+ }
+ events.emit('verbose', 'Not changing launch storyboard setting.');
+}
+
+/**
+ * Returns the directory for the Launch Storyboard image set, if image sets are being used. If they aren't
+ * being used, returns null.
+ *
+ * @param {string} projectRoot The project's root directory
+ * @param {string} platformProjDir The platform's project directory
+ */
+function getLaunchStoryboardImagesDir(projectRoot, platformProjDir) {
+ var launchStoryboardImagesDir;
+ var xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Images.xcassets/'));
+
+ if (xcassetsExists) {
+ launchStoryboardImagesDir = path.join(platformProjDir, 'Images.xcassets/LaunchStoryboard.imageset/');
+ } else {
+ // if we don't have a asset library for images, we can't do the storyboard.
+ launchStoryboardImagesDir = null;
+ }
+
+ return launchStoryboardImagesDir;
+}
+
+/**
+ * Update the images for the Launch Storyboard and updates the image set's contents.json file appropriately.
+ *
+ * @param {Object} cordovaProject The cordova project
+ * @param {Object} locations A dictionary containing useful location paths
+ */
+function updateLaunchStoryboardImages(cordovaProject, locations) {
+ var splashScreens = cordovaProject.projectConfig.getSplashScreens('ios');
+ var platformProjDir = locations.xcodeCordovaProj;
+ var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(cordovaProject.root, platformProjDir);
+
+ if (launchStoryboardImagesDir) {
+ var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
+ var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
+
+ events.emit('verbose', 'Updating launch storyboard images at ' + launchStoryboardImagesDir);
+ FileUpdater.updatePaths(
+ resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+
+ events.emit('verbose', 'Updating Storyboard image set contents.json');
+ fs.writeFileSync(path.join(launchStoryboardImagesDir, 'contents.json'),
+ JSON.stringify(contentsJSON, null, 2));
+ }
+}
+
+/**
+ * Removes the images from the launch storyboard's image set and updates the image set's contents.json
+ * file appropriately.
+ *
+ * @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 cleanLaunchStoryboardImages(projectRoot, projectConfig, locations) {
+ var splashScreens = projectConfig.getSplashScreens('ios');
+ var platformProjDir = locations.xcodeCordovaProj;
+ var launchStoryboardImagesDir = getLaunchStoryboardImagesDir(projectRoot, platformProjDir);
+ if (launchStoryboardImagesDir) {
+ var resourceMap = mapLaunchStoryboardResources(splashScreens, launchStoryboardImagesDir);
+ var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, launchStoryboardImagesDir);
+
+ Object.keys(resourceMap).forEach(function (targetPath) {
+ resourceMap[targetPath] = null;
+ });
+ 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) {
+ image.filename = undefined;
+ });
+
+ events.emit('verbose', 'Updating Storyboard image set contents.json');
+ fs.writeFileSync(path.join(launchStoryboardImagesDir, 'contents.json'),
+ JSON.stringify(contentsJSON, null, 2));
+ }
+}
+
+/**
+ * Queries ConfigParser object for the orientation <preference> value. Warns if
+ * global preference value is not supported by platform.
+ *
+ * @param {Object} platformConfig ConfigParser object
+ *
+ * @return {String} Global/platform-specific orientation in lower-case
+ * (or empty string if both are undefined).
+ */
+function getOrientationValue(platformConfig) {
+
+ var ORIENTATION_DEFAULT = 'default';
+
+ var orientation = platformConfig.getPreference('orientation');
+ if (!orientation) {
+ return '';
+ }
+
+ orientation = orientation.toLowerCase();
+
+ // Check if the given global orientation is supported
+ if (['default', 'portrait','landscape', 'all'].indexOf(orientation) >= 0) {
+ return orientation;
+ }
+
+ events.emit('warn', 'Unrecognized value for Orientation preference: ' + orientation +
+ '. Defaulting to value: ' + ORIENTATION_DEFAULT + '.');
+
+ return ORIENTATION_DEFAULT;
+}
+
+/*
+ Parses all <access> and <allow-navigation> entries and consolidates duplicates (for ATS).
+ Returns an object with a Hostname as the key, and the value an object with properties:
+ {
+ Hostname, // String
+ NSExceptionAllowsInsecureHTTPLoads, // boolean
+ NSIncludesSubdomains, // boolean
+ NSExceptionMinimumTLSVersion, // String
+ NSExceptionRequiresForwardSecrecy, // boolean
+ NSRequiresCertificateTransparency, // boolean
+
+ // the three below _only_ show when the Hostname is '*'
+ // if any of the three are set, it disables setting NSAllowsArbitraryLoads
+ // (Apple already enforces this in ATS)
+ NSAllowsArbitraryLoadsInWebContent, // boolean (default: false)
+ NSAllowsLocalNetworking, // boolean (default: false)
+ NSAllowsArbitraryLoadsInMedia, // boolean (default:false)
+ }
+*/
+function processAccessAndAllowNavigationEntries(config) {
+ var accesses = config.getAccesses();
+ var allow_navigations = config.getAllowNavigations();
+
+ return allow_navigations
+ // we concat allow_navigations and accesses, after processing accesses
+ .concat(accesses.map(function(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 = {
+ minimum_tls_version : currentElement.minimum_tls_version,
+ requires_forward_secrecy : currentElement.requires_forward_secrecy,
+ requires_certificate_transparency : currentElement.requires_certificate_transparency,
+ allows_arbitrary_loads_in_media : currentElement.allows_arbitrary_loads_in_media,
+ 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);
+
+ if (obj) {
+ // we 'union' duplicate entries
+ var item = previousReturn[obj.Hostname];
+ if (!item) {
+ item = {};
+ }
+ for(var o in obj) {
+ if (obj.hasOwnProperty(o)) {
+ item[o] = obj[o];
+ }
+ }
+ previousReturn[obj.Hostname] = item;
+ }
+ return previousReturn;
+ }, {});
+}
+
+/*
+ Parses a URL and returns an object with these keys:
+ {
+ Hostname, // String
+ NSExceptionAllowsInsecureHTTPLoads, // boolean (default: false)
+ NSIncludesSubdomains, // boolean (default: false)
+ NSExceptionMinimumTLSVersion, // String (default: 'TLSv1.2')
+ NSExceptionRequiresForwardSecrecy, // boolean (default: true)
+ NSRequiresCertificateTransparency, // boolean (default: false)
+
+ // the three below _only_ apply when the Hostname is '*'
+ // if any of the three are set, it disables setting NSAllowsArbitraryLoads
+ // (Apple already enforces this in ATS)
+ NSAllowsArbitraryLoadsInWebContent, // boolean (default: false)
+ NSAllowsLocalNetworking, // boolean (default: false)
+ NSAllowsArbitraryLoadsInMedia, // boolean (default:false)
+ }
+
+ 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 = {};
+ retObj.Hostname = href.hostname;
+
+ // Guiding principle: we only set values in retObj if they are NOT the default
+
+ if (url === '*') {
+ retObj.Hostname = '*';
+ var val;
+
+ val = (options.allows_arbitrary_loads_in_web_content === 'true');
+ if (options.allows_arbitrary_loads_in_web_content && val) { // default is false
+ retObj.NSAllowsArbitraryLoadsInWebContent = true;
+ }
+
+ val = (options.allows_arbitrary_loads_in_media === 'true');
+ if (options.allows_arbitrary_loads_in_media && val) { // default is false
+ retObj.NSAllowsArbitraryLoadsInMedia = true;
+ }
+
+ val = (options.allows_local_networking === 'true');
+ if (options.allows_local_networking && val) { // default is false
+ retObj.NSAllowsLocalNetworking = true;
+ }
+
+ return retObj;
+ }
+
+ 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) {
+ retObj.NSIncludesSubdomains = true;
+ retObj.Hostname = href.pathname.substring(subdomain1.length);
+ } else if (href.pathname.indexOf(subdomain2) === 0) {
+ retObj.NSIncludesSubdomains = true;
+ retObj.Hostname = href.pathname.substring(subdomain2.length);
+ } else if (href.pathname.indexOf(subdomain3) === 0) {
+ retObj.Hostname = href.pathname.substring(subdomain3.length);
+ } else {
+ // Handling "scheme:*" case to avoid creating of a blank key in NSExceptionDomains.
+ return null;
+ }
+ }
+
+ if (options.minimum_tls_version && options.minimum_tls_version !== 'TLSv1.2') { // default is TLSv1.2
+ retObj.NSExceptionMinimumTLSVersion = options.minimum_tls_version;
+ }
+
+ var 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');
+ if (options.requires_certificate_transparency && rct) { // default is false
+ retObj.NSRequiresCertificateTransparency = true;
+ }
+
+ // if the scheme is HTTP, we set NSExceptionAllowsInsecureHTTPLoads to YES. Default is NO
+ if (href.protocol === 'http:') {
+ retObj.NSExceptionAllowsInsecureHTTPLoads = true;
+ }
+ else if (!href.protocol && href.pathname.indexOf('*:/') === 0) { // wilcard in protocol
+ retObj.NSExceptionAllowsInsecureHTTPLoads = true;
+ }
+
+ return retObj;
+}
+
+
+/*
+ App Transport Security (ATS) writer from <access> and <allow-navigation> tags
+ in config.xml
+*/
+function writeATSEntries(config) {
+ var pObj = processAccessAndAllowNavigationEntries(config);
+
+ var ats = {};
+
+ for(var hostname in pObj) {
+ if (pObj.hasOwnProperty(hostname)) {
+ var 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;
+
+ // at least one of the overriding keys is present
+ if (entry.NSAllowsArbitraryLoadsInWebContent) {
+ ats['NSAllowsArbitraryLoadsInWebContent'] = true;
+ }
+ if (entry.NSAllowsArbitraryLoadsInMedia) {
+ ats['NSAllowsArbitraryLoadsInMedia'] = true;
+ }
+ if (entry.NSAllowsLocalNetworking) {
+ ats['NSAllowsLocalNetworking'] = true;
+ }
+
+ continue;
+ }
+
+ var exceptionDomain = {};
+
+ for(var key in entry) {
+ if (entry.hasOwnProperty(key) && key !== 'Hostname') {
+ exceptionDomain[key] = entry[key];
+ }
+ }
+
+ if (!ats['NSExceptionDomains']) {
+ ats['NSExceptionDomains'] = {};
+ }
+
+ ats['NSExceptionDomains'][hostname] = exceptionDomain;
+ }
+ }
+
+ return ats;
+}
+
+function folderExists(folderPath) {
+ try {
+ var stat = fs.statSync(folderPath);
+ return stat && stat.isDirectory();
+ } catch (e) {
+ return false;
+ }
+}
+
+// Construct a default value for CFBundleVersion as the version with any
+// -rclabel stripped=.
+function default_CFBundleVersion(version) {
+ return version.split('-')[0];
+}
+
+// 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"'};
+ if (map[value.toLowerCase()]) {
+ return map[value.toLowerCase()];
+ }
+ 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
new file mode 100755
index 00000000..aab38639
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/lib/projectFile.js
@@ -0,0 +1,136 @@
+/*
+ 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.
+*/
+
+/*jshint node: true*/
+
+var xcode = require('xcode');
+var plist = require('plist');
+var _ = require('underscore');
+var path = require('path');
+var fs = require('fs');
+var shell = require('shelljs');
+
+var pluginHandlers = require('./plugman/pluginHandlers');
+var CordovaError = require('cordova-common').CordovaError;
+
+var cachedProjectFiles = {};
+
+function parseProjectFile(locations) {
+ var project_dir = locations.root;
+ var pbxPath = locations.pbxproj;
+
+ if (cachedProjectFiles[project_dir]) {
+ return cachedProjectFiles[project_dir];
+ }
+
+ var 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');
+
+ 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 = {};
+ 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');
+
+ cachedProjectFiles[project_dir] = {
+ plugins_dir:pluginsDir,
+ resources_dir:resourcesDir,
+ xcode:xcodeproj,
+ xcode_path:xcode_dir,
+ pbx: pbxPath,
+ projectDir: project_dir,
+ platformWww: path.join(project_dir, 'platform_www'),
+ www: path.join(project_dir, 'www'),
+ write: function () {
+ 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);
+ return;
+ }
+ fs.writeFileSync(frameworks_file, JSON.stringify(this.frameworks, null, 4));
+ },
+ getPackageName: function() {
+ return plist.parse(fs.readFileSync(plist_file, 'utf8')).CFBundleIdentifier;
+ },
+ getInstaller: function (name) {
+ return pluginHandlers.getInstaller(name);
+ },
+ getUninstaller: function (name) {
+ return pluginHandlers.getUninstaller(name);
+ },
+ frameworks: frameworks
+ };
+ return cachedProjectFiles[project_dir];
+}
+
+function purgeProjectFileCache(project_dir) {
+ delete cachedProjectFiles[project_dir];
+}
+
+module.exports = {
+ parse: parseProjectFile,
+ purgeProjectFileCache: purgeProjectFileCache
+};
+
+xcode.project.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) {
+ return this.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks', target);
+};
+
+xcode.project.prototype.addToPbxEmbedFrameworksBuildPhase = function (file) {
+ var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
+ if (sources) {
+ sources.files.push(pbxBuildPhaseObj(file));
+ }
+};
+xcode.project.prototype.removeFromPbxEmbedFrameworksBuildPhase = function (file) {
+ var sources = this.pbxEmbedFrameworksBuildPhaseObj(file.target);
+ if (sources) {
+ sources.files = _.reject(sources.files, function(file){
+ return 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');
+function pbxBuildPhaseObj(file) {
+ var obj = Object.create(null);
+ obj.value = file.uuid;
+ obj.comment = longComment(file);
+ return obj;
+}
+
+function longComment(file) {
+ return util.format('%s in %s', file.basename, file.group);
+}
diff --git a/StoneIsland/platforms/ios/cordova/lib/run.js b/StoneIsland/platforms/ios/cordova/lib/run.js
index fcd39015..68c315a5 100755
--- a/StoneIsland/platforms/ios/cordova/lib/run.js
+++ b/StoneIsland/platforms/ios/cordova/lib/run.js
@@ -20,84 +20,103 @@
/*jshint node: true*/
var Q = require('q'),
- nopt = require('nopt'),
- path = require('path'),
- build = require('./build'),
- spawn = require('./spawn'),
+ path = require('path'),
+ iossim = require('ios-sim'),
+ build = require('./build'),
+ spawn = require('./spawn'),
check_reqs = require('./check_reqs');
+var events = require('cordova-common').events;
+
var cordovaPath = path.join(__dirname, '..');
var projectPath = path.join(__dirname, '..', '..');
-module.exports.run = function (argv) {
-
- // parse args here
- // --debug and --release args not parsed here
- // but still valid since they can be passed down to build command
- var args = nopt({
- // "archs": String, // TODO: add support for building different archs
- 'list': Boolean,
- 'nobuild': Boolean,
- 'device': Boolean, 'emulator': Boolean, 'target': String
- }, {}, argv);
+module.exports.run = function (runOptions) {
// Validate args
- if (args.device && args.emulator) {
+ if (runOptions.device && runOptions.emulator) {
return Q.reject('Only one of "device"/"emulator" options should be specified');
}
- // validate target device for ios-sim
- // Valid values for "--target" (case sensitive):
- var validTargets = ['iPhone-4s', 'iPhone-5', 'iPhone-5s', 'iPhone-6-Plus', 'iPhone-6',
- 'iPad-2', 'iPad-Retina', 'iPad-Air', 'Resizable-iPhone', 'Resizable-iPad'];
- if (!(args.device) && args.target && validTargets.indexOf(args.target.split(',')[0]) < 0 ) {
- return Q.reject(args.target + ' is not a valid target for emulator');
- }
-
// support for CB-8168 `cordova/run --list`
- if (args.list) {
- if (args.device) return listDevices();
- if (args.emulator) return listEmulators();
+ if (runOptions.list) {
+ if (runOptions.device) return listDevices();
+ if (runOptions.emulator) return listEmulators();
// if no --device or --emulator flag is specified, list both devices and emulators
return listDevices().then(function () {
return listEmulators();
});
}
- // check for either ios-sim or ios-deploy is available
- // depending on arguments provided
- var checkTools = args.device ? check_reqs.check_ios_deploy() : check_reqs.check_ios_sim();
+ var useDevice = !!runOptions.device;
- return checkTools.then(function () {
- // if --nobuild isn't specified then build app first
- if (!args.nobuild) {
- return build.run(argv);
+ return require('./list-devices').run()
+ .then(function (devices) {
+ if (devices.length > 0 && !(runOptions.emulator)) {
+ useDevice = true;
+ // we also explicitly set device flag in options as we pass
+ // those parameters to other api (build as an example)
+ runOptions.device = true;
+ return check_reqs.check_ios_deploy();
+ }
+ }).then(function () {
+ if (!runOptions.nobuild) {
+ return build.run(runOptions);
+ } else {
+ return Q.resolve();
}
}).then(function () {
return build.findXCodeProjectIn(projectPath);
}).then(function (projectName) {
- var appPath = path.join(projectPath, 'build', (args.device ? 'device' : 'emulator'), projectName + '.app');
+ var appPath = path.join(projectPath, 'build', 'emulator', projectName + '.app');
// select command to run and arguments depending whether
// we're running on device/emulator
- if (args.device) {
+ if (useDevice) {
return checkDeviceConnected().then(function () {
- return deployToDevice(appPath);
+ 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 = filterSupportedArgs(runOptions.argv.slice(2));
+ }
+ return deployToDevice(appPath, runOptions.target, extraArgs);
}, function () {
// if device connection check failed use emulator then
- return deployToSim(appPath, args.target);
+ return deployToSim(appPath, runOptions.target);
});
} else {
- return deployToSim(appPath, args.target);
+ return deployToSim(appPath, runOptions.target);
}
});
};
/**
+ * Filters the args array and removes supported args for the 'run' command.
+ *
+ * @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('|'));
+
+ args.forEach(function(element) {
+ // supported args not found, we add
+ // we do a regex search because --target can be "--target=XXX"
+ if (element.search(re) == -1) {
+ filtered.push(element);
+ }
+ }, this);
+
+ return filtered;
+}
+
+/**
* Checks if any iOS device is connected
* @return {Promise} Fullfilled when any device is connected, rejected otherwise
*/
function checkDeviceConnected() {
- return spawn('ios-deploy', ['-c']);
+ return spawn('ios-deploy', ['-c', '-t', '1']);
}
/**
@@ -106,9 +125,13 @@ function checkDeviceConnected() {
* @param {String} appPath Path to application package
* @return {Promise} Resolves when deploy succeeds otherwise rejects
*/
-function deployToDevice(appPath) {
+function deployToDevice(appPath, target, extraArgs) {
// Deploying to device...
- return spawn('ios-deploy', ['-d', '-b', appPath]);
+ if (target) {
+ return spawn('ios-deploy', ['--justlaunch', '-d', '-b', appPath, '-i', target].concat(extraArgs));
+ } else {
+ return spawn('ios-deploy', ['--justlaunch', '--no-wifi', '-d', '-b', appPath].concat(extraArgs));
+ }
}
/**
@@ -118,27 +141,38 @@ function deployToDevice(appPath) {
* @return {Promise} Resolves when deploy succeeds otherwise rejects
*/
function deployToSim(appPath, target) {
- // Select target device for emulator. Default is 'iPhone-6'
+ // Select target device for emulator. Default is 'iPhone-6'
if (!target) {
- target = 'iPhone-6';
- console.log('No target specified for emulator. Deploying to ' + target + ' simulator');
+ return require('./list-emulator-images').run()
+ .then(function (emulators) {
+ if (emulators.length > 0) {
+ target = emulators[0];
+ }
+ emulators.forEach(function (emulator) {
+ if (emulator.indexOf('iPhone') === 0) {
+ target = emulator;
+ }
+ });
+ events.emit('log','No target specified for emulator. Deploying to ' + target + ' simulator');
+ return startSim(appPath, target);
+ });
+ } else {
+ return startSim(appPath, target);
}
+}
+
+function startSim(appPath, target) {
var logPath = path.join(cordovaPath, 'console.log');
- var simArgs = ['launch', appPath,
- '--devicetypeid', 'com.apple.CoreSimulator.SimDeviceType.' + target,
- // We need to redirect simulator output here to use cordova/log command
- // TODO: Is there any other way to get emulator's output to use in log command?
- '--stderr', logPath, '--stdout', logPath,
- '--exit'];
- return spawn('ios-sim', simArgs);
+
+ return iossim.launch(appPath, 'com.apple.CoreSimulator.SimDeviceType.' + target, logPath, '--exit');
}
function listDevices() {
return require('./list-devices').run()
.then(function (devices) {
- console.log('Available iOS Devices:');
+ events.emit('log','Available iOS Devices:');
devices.forEach(function (device) {
- console.log('\t' + device);
+ events.emit('log','\t' + device);
});
});
}
@@ -146,9 +180,9 @@ function listDevices() {
function listEmulators() {
return require('./list-emulator-images').run()
.then(function (emulators) {
- console.log('Available iOS Virtual Devices:');
+ events.emit('log','Available iOS Simulators:');
emulators.forEach(function (emulator) {
- console.log('\t' + emulator);
+ events.emit('log','\t' + emulator);
});
});
}
diff --git a/StoneIsland/platforms/ios/cordova/lib/spawn.js b/StoneIsland/platforms/ios/cordova/lib/spawn.js
index 1cb31615..2162b9c7 100755
--- a/StoneIsland/platforms/ios/cordova/lib/spawn.js
+++ b/StoneIsland/platforms/ios/cordova/lib/spawn.js
@@ -43,7 +43,6 @@ module.exports = function(cmd, args, opt_cwd) {
}
});
} catch(e) {
- console.error('error caught: ' + 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 e22e499a..da31d4fa 100755
--- a/StoneIsland/platforms/ios/cordova/lib/versions.js
+++ b/StoneIsland/platforms/ios/cordova/lib/versions.js
@@ -111,6 +111,23 @@ exports.get_ios_deploy_version = function() {
};
/**
+ * Gets pod (CocoaPods) util version
+ * @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;
+};
+
+/**
* Gets ios-sim util version
* @return {Promise} Promise that either resolved with ios-sim version
* or rejected in case of error
@@ -138,7 +155,8 @@ exports.get_tool_version = function (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();
- default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\' and \'ios-deploy\'');
+ 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\'');
}
};
diff --git a/StoneIsland/platforms/ios/cordova/log.bat b/StoneIsland/platforms/ios/cordova/log.bat
new file mode 100755
index 00000000..4710e57e
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/log.bat
@@ -0,0 +1,19 @@
+:: 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
+
+@ECHO OFF
+ECHO WARN: The 'log' command is not available for cordova-ios on windows machines.>&2
diff --git a/StoneIsland/platforms/ios/cordova/loggingHelper.js b/StoneIsland/platforms/ios/cordova/loggingHelper.js
new file mode 100755
index 00000000..e353399c
--- /dev/null
+++ b/StoneIsland/platforms/ios/cordova/loggingHelper.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 CordovaLogger = require('cordova-common').CordovaLogger;
+
+module.exports = {
+ adjustLoggerLevel: function (opts) {
+ if (opts.verbose || (Array.isArray(opts) && opts.indexOf('--verbose') !== -1)) {
+ CordovaLogger.get().setLevel('verbose');
+ } else if (opts.silent || (Array.isArray(opts) && opts.indexOf('--silent') !== -1)) {
+ CordovaLogger.get().setLevel('error');
+ }
+ }
+};
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE b/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE
index 05a40109..19129e31 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE
+++ b/StoneIsland/platforms/ios/cordova/node_modules/nopt/LICENSE
@@ -1,23 +1,15 @@
-Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
-All rights reserved.
+The ISC License
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
+Copyright (c) Isaac Z. Schlueter and Contributors
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js b/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js
index 5309a00f..97707e78 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js
+++ b/StoneIsland/platforms/ios/cordova/node_modules/nopt/lib/nopt.js
@@ -207,7 +207,8 @@ function validate (data, k, val, type, typeDefs) {
for (var i = 0, l = types.length; i < l; i ++) {
debug("test type %j %j %j", k, val, types[i])
var t = typeDefs[types[i]]
- if (t && type === t.type) {
+ if (t &&
+ ((type && type.name && t.type && t.type.name) ? (type.name === t.type.name) : (type === t.type))) {
var d = {}
ok = false !== t.validate(d, k, val)
val = d[k]
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/LICENSE b/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/LICENSE
deleted file mode 100755
index 05a40109..00000000
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
-All rights reserved.
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/abbrev.js b/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/abbrev.js
deleted file mode 100755
index 69cfeac5..00000000
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/abbrev.js
+++ /dev/null
@@ -1,62 +0,0 @@
-
-module.exports = exports = abbrev.abbrev = abbrev
-
-abbrev.monkeyPatch = monkeyPatch
-
-function monkeyPatch () {
- Object.defineProperty(Array.prototype, 'abbrev', {
- value: function () { return abbrev(this) },
- enumerable: false, configurable: true, writable: true
- })
-
- Object.defineProperty(Object.prototype, 'abbrev', {
- value: function () { return abbrev(Object.keys(this)) },
- enumerable: false, configurable: true, writable: true
- })
-}
-
-function abbrev (list) {
- if (arguments.length !== 1 || !Array.isArray(list)) {
- list = Array.prototype.slice.call(arguments, 0)
- }
- for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
- args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
- }
-
- // sort them lexicographically, so that they're next to their nearest kin
- args = args.sort(lexSort)
-
- // walk through each, seeing how much it has in common with the next and previous
- var abbrevs = {}
- , prev = ""
- for (var i = 0, l = args.length ; i < l ; i ++) {
- var current = args[i]
- , next = args[i + 1] || ""
- , nextMatches = true
- , prevMatches = true
- if (current === next) continue
- for (var j = 0, cl = current.length ; j < cl ; j ++) {
- var curChar = current.charAt(j)
- nextMatches = nextMatches && curChar === next.charAt(j)
- prevMatches = prevMatches && curChar === prev.charAt(j)
- if (!nextMatches && !prevMatches) {
- j ++
- break
- }
- }
- prev = current
- if (j === cl) {
- abbrevs[current] = current
- continue
- }
- for (var a = current.substr(0, j) ; j <= cl ; j ++) {
- abbrevs[a] = current
- a += current.charAt(j)
- }
- }
- return abbrevs
-}
-
-function lexSort (a, b) {
- return a === b ? 0 : a > b ? 1 : -1
-}
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/package.json b/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/package.json
deleted file mode 100755
index 91f1dd9c..00000000
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/node_modules/abbrev/package.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "name": "abbrev",
- "version": "1.0.5",
- "description": "Like ruby's abbrev module, but in js",
- "author": {
- "name": "Isaac Z. Schlueter",
- "email": "i@izs.me"
- },
- "main": "abbrev.js",
- "scripts": {
- "test": "node test.js"
- },
- "repository": {
- "type": "git",
- "url": "http://github.com/isaacs/abbrev-js"
- },
- "license": {
- "type": "MIT",
- "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE"
- },
- "readme": "# abbrev-js\n\nJust like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).\n\nUsage:\n\n var abbrev = require(\"abbrev\");\n abbrev(\"foo\", \"fool\", \"folding\", \"flop\");\n \n // returns:\n { fl: 'flop'\n , flo: 'flop'\n , flop: 'flop'\n , fol: 'folding'\n , fold: 'folding'\n , foldi: 'folding'\n , foldin: 'folding'\n , folding: 'folding'\n , foo: 'foo'\n , fool: 'fool'\n }\n\nThis is handy for command-line scripts, or other cases where you want to be able to accept shorthands.\n",
- "readmeFilename": "README.md",
- "bugs": {
- "url": "https://github.com/isaacs/abbrev-js/issues"
- },
- "homepage": "https://github.com/isaacs/abbrev-js",
- "_id": "abbrev@1.0.5",
- "_shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03",
- "_from": "abbrev@1",
- "_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
-}
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json b/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json
index 62d0fe84..c0025bda 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json
+++ b/StoneIsland/platforms/ios/cordova/node_modules/nopt/package.json
@@ -1,41 +1,54 @@
{
- "name": "nopt",
- "version": "3.0.1",
- "description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.",
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"url": "http://blog.izs.me/"
},
- "main": "lib/nopt.js",
- "scripts": {
- "test": "tap test/*.js"
- },
- "repository": {
- "type": "git",
- "url": "http://github.com/isaacs/nopt"
- },
"bin": {
"nopt": "./bin/nopt.js"
},
- "license": {
- "type": "MIT",
- "url": "https://github.com/isaacs/nopt/raw/master/LICENSE"
+ "bugs": {
+ "url": "https://github.com/npm/nopt/issues"
},
"dependencies": {
"abbrev": "1"
},
+ "description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.",
"devDependencies": {
- "tap": "~0.4.8"
+ "tap": "^1.2.0"
},
- "readme": "If you want to write an option parser, and have it be good, there are\ntwo ways to do it. The Right Way, and the Wrong Way.\n\nThe Wrong Way is to sit down and write an option parser. We've all done\nthat.\n\nThe Right Way is to write some complex configurable program with so many\noptions that you go half-insane just trying to manage them all, and put\nit off with duct-tape solutions until you see exactly to the core of the\nproblem, and finally snap and write an awesome option parser.\n\nIf you want to write an option parser, don't write an option parser.\nWrite a package manager, or a source control system, or a service\nrestarter, or an operating system. You probably won't end up with a\ngood one of those, but if you don't give up, and you are relentless and\ndiligent enough in your procrastination, you may just end up with a very\nnice option parser.\n\n## USAGE\n\n // my-program.js\n var nopt = require(\"nopt\")\n , Stream = require(\"stream\").Stream\n , path = require(\"path\")\n , knownOpts = { \"foo\" : [String, null]\n , \"bar\" : [Stream, Number]\n , \"baz\" : path\n , \"bloo\" : [ \"big\", \"medium\", \"small\" ]\n , \"flag\" : Boolean\n , \"pick\" : Boolean\n , \"many\" : [String, Array]\n }\n , shortHands = { \"foofoo\" : [\"--foo\", \"Mr. Foo\"]\n , \"b7\" : [\"--bar\", \"7\"]\n , \"m\" : [\"--bloo\", \"medium\"]\n , \"p\" : [\"--pick\"]\n , \"f\" : [\"--flag\"]\n }\n // everything is optional.\n // knownOpts and shorthands default to {}\n // arg list defaults to process.argv\n // slice defaults to 2\n , parsed = nopt(knownOpts, shortHands, process.argv, 2)\n console.log(parsed)\n\nThis would give you support for any of the following:\n\n```bash\n$ node my-program.js --foo \"blerp\" --no-flag\n{ \"foo\" : \"blerp\", \"flag\" : false }\n\n$ node my-program.js ---bar 7 --foo \"Mr. Hand\" --flag\n{ bar: 7, foo: \"Mr. Hand\", flag: true }\n\n$ node my-program.js --foo \"blerp\" -f -----p\n{ foo: \"blerp\", flag: true, pick: true }\n\n$ node my-program.js -fp --foofoo\n{ foo: \"Mr. Foo\", flag: true, pick: true }\n\n$ node my-program.js --foofoo -- -fp # -- stops the flag parsing.\n{ foo: \"Mr. Foo\", argv: { remain: [\"-fp\"] } }\n\n$ node my-program.js --blatzk -fp # unknown opts are ok.\n{ blatzk: true, flag: true, pick: true }\n\n$ node my-program.js --blatzk=1000 -fp # but you need to use = if they have a value\n{ blatzk: 1000, flag: true, pick: true }\n\n$ node my-program.js --no-blatzk -fp # unless they start with \"no-\"\n{ blatzk: false, flag: true, pick: true }\n\n$ node my-program.js --baz b/a/z # known paths are resolved.\n{ baz: \"/Users/isaacs/b/a/z\" }\n\n# if Array is one of the types, then it can take many\n# values, and will always be an array. The other types provided\n# specify what types are allowed in the list.\n\n$ node my-program.js --many 1 --many null --many foo\n{ many: [\"1\", \"null\", \"foo\"] }\n\n$ node my-program.js --many foo\n{ many: [\"foo\"] }\n```\n\nRead the tests at the bottom of `lib/nopt.js` for more examples of\nwhat this puppy can do.\n\n## Types\n\nThe following types are supported, and defined on `nopt.typeDefs`\n\n* String: A normal string. No parsing is done.\n* path: A file system path. Gets resolved against cwd if not absolute.\n* url: A url. If it doesn't parse, it isn't accepted.\n* Number: Must be numeric.\n* Date: Must parse as a date. If it does, and `Date` is one of the options,\n then it will return a Date object, not a string.\n* Boolean: Must be either `true` or `false`. If an option is a boolean,\n then it does not need a value, and its presence will imply `true` as\n the value. To negate boolean flags, do `--no-whatever` or `--whatever\n false`\n* NaN: Means that the option is strictly not allowed. Any value will\n fail.\n* Stream: An object matching the \"Stream\" class in node. Valuable\n for use when validating programmatically. (npm uses this to let you\n supply any WriteStream on the `outfd` and `logfd` config options.)\n* Array: If `Array` is specified as one of the types, then the value\n will be parsed as a list of options. This means that multiple values\n can be specified, and that the value will always be an array.\n\nIf a type is an array of values not on this list, then those are\nconsidered valid values. For instance, in the example above, the\n`--bloo` option can only be one of `\"big\"`, `\"medium\"`, or `\"small\"`,\nand any other value will be rejected.\n\nWhen parsing unknown fields, `\"true\"`, `\"false\"`, and `\"null\"` will be\ninterpreted as their JavaScript equivalents.\n\nYou can also mix types and values, or multiple types, in a list. For\ninstance `{ blah: [Number, null] }` would allow a value to be set to\neither a Number or null. When types are ordered, this implies a\npreference, and the first type that can be used to properly interpret\nthe value will be used.\n\nTo define a new type, add it to `nopt.typeDefs`. Each item in that\nhash is an object with a `type` member and a `validate` method. The\n`type` member is an object that matches what goes in the type list. The\n`validate` method is a function that gets called with `validate(data,\nkey, val)`. Validate methods should assign `data[key]` to the valid\nvalue of `val` if it can be handled properly, or return boolean\n`false` if it cannot.\n\nYou can also call `nopt.clean(data, types, typeDefs)` to clean up a\nconfig object and remove its invalid properties.\n\n## Error Handling\n\nBy default, nopt outputs a warning to standard error when invalid\noptions are found. You can change this behavior by assigning a method\nto `nopt.invalidHandler`. This method will be called with\nthe offending `nopt.invalidHandler(key, val, types)`.\n\nIf no `nopt.invalidHandler` is assigned, then it will console.error\nits whining. If it is assigned to boolean `false` then the warning is\nsuppressed.\n\n## Abbreviations\n\nYes, they are supported. If you define options like this:\n\n```javascript\n{ \"foolhardyelephants\" : Boolean\n, \"pileofmonkeys\" : Boolean }\n```\n\nThen this will work:\n\n```bash\nnode program.js --foolhar --pil\nnode program.js --no-f --pileofmon\n# etc.\n```\n\n## Shorthands\n\nShorthands are a hash of shorter option names to a snippet of args that\nthey expand to.\n\nIf multiple one-character shorthands are all combined, and the\ncombination does not unambiguously match any other option or shorthand,\nthen they will be broken up into their constituent parts. For example:\n\n```json\n{ \"s\" : [\"--loglevel\", \"silent\"]\n, \"g\" : \"--global\"\n, \"f\" : \"--force\"\n, \"p\" : \"--parseable\"\n, \"l\" : \"--long\"\n}\n```\n\n```bash\nnpm ls -sgflp\n# just like doing this:\nnpm ls --loglevel silent --global --force --long --parseable\n```\n\n## The Rest of the args\n\nThe config object returned by nopt is given a special member called\n`argv`, which is an object with the following fields:\n\n* `remain`: The remaining args after all the parsing has occurred.\n* `original`: The args as they originally appeared.\n* `cooked`: The args after flags and shorthands are expanded.\n\n## Slicing\n\nNode programs are called with more or less the exact argv as it appears\nin C land, after the v8 and node-specific options have been plucked off.\nAs such, `argv[0]` is always `node` and `argv[1]` is always the\nJavaScript program being run.\n\nThat's usually not very useful to you. So they're sliced off by\ndefault. If you want them, then you can pass in `0` as the last\nargument, or any other number that you'd like to slice off the start of\nthe list.\n",
- "readmeFilename": "README.md",
- "bugs": {
- "url": "https://github.com/isaacs/nopt/issues"
+ "directories": {},
+ "dist": {
+ "shasum": "c6465dbf08abcd4db359317f79ac68a646b28ff9",
+ "tarball": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
+ },
+ "gitHead": "10a750c9bb99c1950160353459e733ac2aa18cb6",
+ "homepage": "https://github.com/npm/nopt#readme",
+ "license": "ISC",
+ "main": "lib/nopt.js",
+ "maintainers": [
+ {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ },
+ {
+ "name": "othiym23",
+ "email": "ogd@aoaioxxysz.net"
+ },
+ {
+ "name": "zkat",
+ "email": "kat@sykosomatic.org"
+ }
+ ],
+ "name": "nopt",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/npm/nopt.git"
+ },
+ "scripts": {
+ "test": "tap test/*.js"
},
- "homepage": "https://github.com/isaacs/nopt",
- "_id": "nopt@3.0.1",
- "_shasum": "bce5c42446a3291f47622a370abbf158fbbacbfd",
- "_from": "nopt@",
- "_resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.1.tgz"
-}
+ "version": "3.0.6"
+} \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/package.json b/StoneIsland/platforms/ios/cordova/node_modules/q/package.json
index 7b7f3c6c..5ad2a032 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/q/package.json
+++ b/StoneIsland/platforms/ios/cordova/node_modules/q/package.json
@@ -1,27 +1,12 @@
{
- "name": "q",
- "version": "1.0.1",
- "description": "A library for promises (CommonJS/Promises/A,B,D)",
- "homepage": "https://github.com/kriskowal/q",
"author": {
"name": "Kris Kowal",
"email": "kris@cixar.com",
"url": "https://github.com/kriskowal"
},
- "keywords": [
- "q",
- "promise",
- "promises",
- "promises-a",
- "promises-aplus",
- "deferred",
- "future",
- "async",
- "flow control",
- "fluent",
- "browser",
- "node"
- ],
+ "bugs": {
+ "url": "http://github.com/kriskowal/q/issues"
+ },
"contributors": [
{
"name": "Kris Kowal",
@@ -39,64 +24,56 @@
"url": "http://domenicdenicola.com"
}
],
- "bugs": {
- "url": "http://github.com/kriskowal/q/issues"
- },
- "license": {
- "type": "MIT",
- "url": "http://github.com/kriskowal/q/raw/master/LICENSE"
- },
- "main": "q.js",
- "repository": {
- "type": "git",
- "url": "git://github.com/kriskowal/q.git"
- },
- "engines": {
- "node": ">=0.6.0",
- "teleport": ">=0.2.0"
- },
"dependencies": {},
+ "description": "A library for promises (CommonJS/Promises/A,B,D)",
"devDependencies": {
- "jshint": "~2.1.9",
"cover": "*",
- "jasmine-node": "1.11.0",
- "opener": "*",
- "promises-aplus-tests": "1.x",
"grunt": "~0.4.1",
"grunt-cli": "~0.1.9",
- "grunt-contrib-uglify": "~0.2.2",
- "matcha": "~0.2.0"
- },
- "scripts": {
- "test": "jasmine-node spec && promises-aplus-tests spec/aplus-adapter",
- "test-browser": "opener spec/q-spec.html",
- "benchmark": "matcha",
- "lint": "jshint q.js",
- "cover": "cover run node_modules/jasmine-node/bin/jasmine-node spec && cover report html && opener cover_html/index.html",
- "minify": "grunt",
- "prepublish": "grunt"
- },
- "overlay": {
- "teleport": {
- "dependencies": {
- "system": ">=0.0.4"
- }
- }
+ "grunt-contrib-uglify": "~0.9.1",
+ "jasmine-node": "1.11.0",
+ "jshint": "~2.1.9",
+ "matcha": "~0.2.0",
+ "opener": "*",
+ "promises-aplus-tests": "1.x"
},
"directories": {
"test": "./spec"
},
- "_id": "q@1.0.1",
"dist": {
- "shasum": "11872aeedee89268110b10a718448ffb10112a14",
- "tarball": "http://registry.npmjs.org/q/-/q-1.0.1.tgz"
+ "shasum": "55705bcd93c5f3673530c2c2cbc0c2b3addc286e",
+ "tarball": "https://registry.npmjs.org/q/-/q-1.4.1.tgz"
},
- "_from": "q@",
- "_npmVersion": "1.4.4",
- "_npmUser": {
- "name": "kriskowal",
- "email": "kris.kowal@cixar.com"
+ "engines": {
+ "node": ">=0.6.0",
+ "teleport": ">=0.2.0"
},
+ "files": [
+ "LICENSE",
+ "q.js",
+ "queue.js"
+ ],
+ "gitHead": "d373079d3620152e3d60e82f27265a09ee0e81bd",
+ "homepage": "https://github.com/kriskowal/q",
+ "keywords": [
+ "q",
+ "promise",
+ "promises",
+ "promises-a",
+ "promises-aplus",
+ "deferred",
+ "future",
+ "async",
+ "flow control",
+ "fluent",
+ "browser",
+ "node"
+ ],
+ "license": {
+ "type": "MIT",
+ "url": "http://github.com/kriskowal/q/raw/master/LICENSE"
+ },
+ "main": "q.js",
"maintainers": [
{
"name": "kriskowal",
@@ -107,6 +84,28 @@
"email": "domenic@domenicdenicola.com"
}
],
- "_shasum": "11872aeedee89268110b10a718448ffb10112a14",
- "_resolved": "https://registry.npmjs.org/q/-/q-1.0.1.tgz"
-}
+ "name": "q",
+ "optionalDependencies": {},
+ "overlay": {
+ "teleport": {
+ "dependencies": {
+ "system": ">=0.0.4"
+ }
+ }
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/kriskowal/q.git"
+ },
+ "scripts": {
+ "benchmark": "matcha",
+ "cover": "cover run jasmine-node spec && cover report html && opener cover_html/index.html",
+ "lint": "jshint q.js",
+ "minify": "grunt",
+ "prepublish": "grunt",
+ "test": "jasmine-node spec && promises-aplus-tests spec/aplus-adapter",
+ "test-browser": "opener spec/q-spec.html"
+ },
+ "version": "1.4.1"
+} \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/q/q.js b/StoneIsland/platforms/ios/cordova/node_modules/q/q.js
index df36027e..cf5339e3 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/q/q.js
+++ b/StoneIsland/platforms/ios/cordova/node_modules/q/q.js
@@ -27,8 +27,7 @@
*/
(function (definition) {
- // Turn off strict mode for this function so we can assign to global.Q
- /* jshint strict: false */
+ "use strict";
// This file will function properly as a <script> tag, or a module
// using CommonJS and NodeJS or RequireJS module formats. In
@@ -40,7 +39,7 @@
bootstrap("promise", definition);
// CommonJS
- } else if (typeof exports === "object") {
+ } else if (typeof exports === "object" && typeof module === "object") {
module.exports = definition();
// RequireJS
@@ -56,8 +55,25 @@
}
// <script>
+ } else if (typeof window !== "undefined" || typeof self !== "undefined") {
+ // Prefer window over self for add-on scripts. Use self for
+ // non-windowed contexts.
+ var global = typeof window !== "undefined" ? window : self;
+
+ // Get the `window` object, save the previous Q global
+ // and initialize Q as a global.
+ var previousQ = global.Q;
+ global.Q = definition();
+
+ // Add a noConflict function so Q can be removed from the
+ // global namespace.
+ global.Q.noConflict = function () {
+ global.Q = previousQ;
+ return this;
+ };
+
} else {
- Q = definition();
+ throw new Error("This environment was not anticipated by Q. Please file a bug.");
}
})(function () {
@@ -89,57 +105,67 @@ var nextTick =(function () {
var flushing = false;
var requestTick = void 0;
var isNodeJS = false;
+ // queue for late tasks, used by unhandled rejection tracking
+ var laterQueue = [];
function flush() {
/* jshint loopfunc: true */
+ var task, domain;
while (head.next) {
head = head.next;
- var task = head.task;
+ task = head.task;
head.task = void 0;
- var domain = head.domain;
+ domain = head.domain;
if (domain) {
head.domain = void 0;
domain.enter();
}
+ runSingle(task, domain);
- try {
- task();
-
- } catch (e) {
- if (isNodeJS) {
- // In node, uncaught exceptions are considered fatal errors.
- // Re-throw them synchronously to interrupt flushing!
-
- // Ensure continuation if the uncaught exception is suppressed
- // listening "uncaughtException" events (as domains does).
- // Continue in next event to avoid tick recursion.
- if (domain) {
- domain.exit();
- }
- setTimeout(flush, 0);
- if (domain) {
- domain.enter();
- }
+ }
+ while (laterQueue.length) {
+ task = laterQueue.pop();
+ runSingle(task);
+ }
+ flushing = false;
+ }
+ // runs a single function in the async queue
+ function runSingle(task, domain) {
+ try {
+ task();
- throw e;
+ } catch (e) {
+ if (isNodeJS) {
+ // In node, uncaught exceptions are considered fatal errors.
+ // Re-throw them synchronously to interrupt flushing!
- } else {
- // In browsers, uncaught exceptions are not fatal.
- // Re-throw them asynchronously to avoid slow-downs.
- setTimeout(function() {
- throw e;
- }, 0);
+ // Ensure continuation if the uncaught exception is suppressed
+ // listening "uncaughtException" events (as domains does).
+ // Continue in next event to avoid tick recursion.
+ if (domain) {
+ domain.exit();
+ }
+ setTimeout(flush, 0);
+ if (domain) {
+ domain.enter();
}
- }
- if (domain) {
- domain.exit();
+ throw e;
+
+ } else {
+ // In browsers, uncaught exceptions are not fatal.
+ // Re-throw them asynchronously to avoid slow-downs.
+ setTimeout(function () {
+ throw e;
+ }, 0);
}
}
- flushing = false;
+ if (domain) {
+ domain.exit();
+ }
}
nextTick = function (task) {
@@ -155,9 +181,16 @@ var nextTick =(function () {
}
};
- if (typeof process !== "undefined" && process.nextTick) {
- // Node.js before 0.9. Note that some fake-Node environments, like the
- // Mocha test runner, introduce a `process` global without a `nextTick`.
+ if (typeof process === "object" &&
+ process.toString() === "[object process]" && process.nextTick) {
+ // Ensure Q is in a real Node environment, with a `process.nextTick`.
+ // To see through fake Node environments:
+ // * Mocha test runner - exposes a `process` global without a `nextTick`
+ // * Browserify - exposes a `process.nexTick` function that uses
+ // `setTimeout`. In this case `setImmediate` is preferred because
+ // it is faster. Browserify's `process.toString()` yields
+ // "[object Object]", while in a real Node environment
+ // `process.nextTick()` yields "[object process]".
isNodeJS = true;
requestTick = function () {
@@ -201,7 +234,16 @@ var nextTick =(function () {
setTimeout(flush, 0);
};
}
-
+ // runs a task after all other tasks have been run
+ // this is useful for unhandled rejection tracking that needs to happen
+ // after all `then`d tasks have been run.
+ nextTick.runAfter = function (task) {
+ laterQueue.push(task);
+ if (!flushing) {
+ flushing = true;
+ requestTick();
+ }
+ };
return nextTick;
})();
@@ -450,7 +492,7 @@ function Q(value) {
// If the object is already a Promise, return it directly. This enables
// the resolve function to both be used to created references from objects,
// but to tolerably coerce non-promises to promises.
- if (isPromise(value)) {
+ if (value instanceof Promise) {
return value;
}
@@ -474,6 +516,11 @@ Q.nextTick = nextTick;
*/
Q.longStackSupport = false;
+// enable long stacks if Q_DEBUG is set
+if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) {
+ Q.longStackSupport = true;
+}
+
/**
* Constructs a {promise, resolve, reject} object.
*
@@ -505,7 +552,7 @@ function defer() {
progressListeners.push(operands[1]);
}
} else {
- nextTick(function () {
+ Q.nextTick(function () {
resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
});
}
@@ -553,7 +600,7 @@ function defer() {
promise.source = newPromise;
array_reduce(messages, function (undefined, message) {
- nextTick(function () {
+ Q.nextTick(function () {
newPromise.promiseDispatch.apply(newPromise, message);
});
}, void 0);
@@ -591,7 +638,7 @@ function defer() {
}
array_reduce(progressListeners, function (undefined, progressListener) {
- nextTick(function () {
+ Q.nextTick(function () {
progressListener(progress);
});
}, void 0);
@@ -684,15 +731,15 @@ Promise.prototype.join = function (that) {
};
/**
- * Returns a promise for the first of an array of promises to become fulfilled.
+ * Returns a promise for the first of an array of promises to become settled.
* @param answers {Array[Any*]} promises to race
- * @returns {Any*} the first promise to be fulfilled
+ * @returns {Any*} the first promise to be settled
*/
Q.race = race;
function race(answerPs) {
- return promise(function(resolve, reject) {
+ return promise(function (resolve, reject) {
// Switch to this once we can assume at least ES5
- // answerPs.forEach(function(answerP) {
+ // answerPs.forEach(function (answerP) {
// Q(answerP).then(resolve, reject);
// });
// Use this in the meantime
@@ -806,7 +853,7 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
return typeof progressed === "function" ? progressed(value) : value;
}
- nextTick(function () {
+ Q.nextTick(function () {
self.promiseDispatch(function (value) {
if (done) {
return;
@@ -847,6 +894,30 @@ Promise.prototype.then = function (fulfilled, rejected, progressed) {
return deferred.promise;
};
+Q.tap = function (promise, callback) {
+ return Q(promise).tap(callback);
+};
+
+/**
+ * Works almost like "finally", but not called for rejections.
+ * Original resolution value is passed through callback unaffected.
+ * Callback may return a promise that will be awaited for.
+ * @param {Function} callback
+ * @returns {Q.Promise}
+ * @example
+ * doSomething()
+ * .then(...)
+ * .tap(console.log)
+ * .then(...);
+ */
+Promise.prototype.tap = function (callback) {
+ callback = Q(callback);
+
+ return this.then(function (value) {
+ return callback.fcall(value).thenResolve(value);
+ });
+};
+
/**
* Registers an observer on a promise.
*
@@ -912,9 +983,7 @@ function nearer(value) {
*/
Q.isPromise = isPromise;
function isPromise(object) {
- return isObject(object) &&
- typeof object.promiseDispatch === "function" &&
- typeof object.inspect === "function";
+ return object instanceof Promise;
}
Q.isPromiseAlike = isPromiseAlike;
@@ -968,6 +1037,7 @@ Promise.prototype.isRejected = function () {
// shimmed environments, this would naturally be a `Set`.
var unhandledReasons = [];
var unhandledRejections = [];
+var reportedUnhandledRejections = [];
var trackUnhandledRejections = true;
function resetUnhandledRejections() {
@@ -983,6 +1053,14 @@ function trackRejection(promise, reason) {
if (!trackUnhandledRejections) {
return;
}
+ if (typeof process === "object" && typeof process.emit === "function") {
+ Q.nextTick.runAfter(function () {
+ if (array_indexOf(unhandledRejections, promise) !== -1) {
+ process.emit("unhandledRejection", reason, promise);
+ reportedUnhandledRejections.push(promise);
+ }
+ });
+ }
unhandledRejections.push(promise);
if (reason && typeof reason.stack !== "undefined") {
@@ -999,6 +1077,15 @@ function untrackRejection(promise) {
var at = array_indexOf(unhandledRejections, promise);
if (at !== -1) {
+ if (typeof process === "object" && typeof process.emit === "function") {
+ Q.nextTick.runAfter(function () {
+ var atReport = array_indexOf(reportedUnhandledRejections, promise);
+ if (atReport !== -1) {
+ process.emit("rejectionHandled", unhandledReasons[at], promise);
+ reportedUnhandledRejections.splice(atReport, 1);
+ }
+ });
+ }
unhandledRejections.splice(at, 1);
unhandledReasons.splice(at, 1);
}
@@ -1092,7 +1179,7 @@ function fulfill(value) {
*/
function coerce(promise) {
var deferred = defer();
- nextTick(function () {
+ Q.nextTick(function () {
try {
promise.then(deferred.resolve, deferred.reject, deferred.notify);
} catch (exception) {
@@ -1193,7 +1280,7 @@ function async(makeGenerator) {
return reject(exception);
}
if (result.done) {
- return result.value;
+ return Q(result.value);
} else {
return when(result.value, callback, errback);
}
@@ -1204,7 +1291,7 @@ function async(makeGenerator) {
result = generator[verb](arg);
} catch (exception) {
if (isStopIteration(exception)) {
- return exception.value;
+ return Q(exception.value);
} else {
return reject(exception);
}
@@ -1300,7 +1387,7 @@ function dispatch(object, op, args) {
Promise.prototype.dispatch = function (op, args) {
var self = this;
var deferred = defer();
- nextTick(function () {
+ Q.nextTick(function () {
self.promiseDispatch(deferred.resolve, op, args);
});
return deferred.promise;
@@ -1473,7 +1560,7 @@ Promise.prototype.keys = function () {
Q.all = all;
function all(promises) {
return when(promises, function (promises) {
- var countDown = 0;
+ var pendingCount = 0;
var deferred = defer();
array_reduce(promises, function (undefined, promise, index) {
var snapshot;
@@ -1483,12 +1570,12 @@ function all(promises) {
) {
promises[index] = snapshot.value;
} else {
- ++countDown;
+ ++pendingCount;
when(
promise,
function (value) {
promises[index] = value;
- if (--countDown === 0) {
+ if (--pendingCount === 0) {
deferred.resolve(promises);
}
},
@@ -1499,7 +1586,7 @@ function all(promises) {
);
}
}, void 0);
- if (countDown === 0) {
+ if (pendingCount === 0) {
deferred.resolve(promises);
}
return deferred.promise;
@@ -1511,6 +1598,55 @@ Promise.prototype.all = function () {
};
/**
+ * Returns the first resolved promise of an array. Prior rejected promises are
+ * ignored. Rejects only if all promises are rejected.
+ * @param {Array*} an array containing values or promises for values
+ * @returns a promise fulfilled with the value of the first resolved promise,
+ * or a rejected promise if all promises are rejected.
+ */
+Q.any = any;
+
+function any(promises) {
+ if (promises.length === 0) {
+ return Q.resolve();
+ }
+
+ var deferred = Q.defer();
+ var pendingCount = 0;
+ array_reduce(promises, function (prev, current, index) {
+ var promise = promises[index];
+
+ pendingCount++;
+
+ when(promise, onFulfilled, onRejected, onProgress);
+ function onFulfilled(result) {
+ deferred.resolve(result);
+ }
+ function onRejected() {
+ pendingCount--;
+ if (pendingCount === 0) {
+ deferred.reject(new Error(
+ "Can't get fulfillment value from any promise, all " +
+ "promises were rejected."
+ ));
+ }
+ }
+ function onProgress(progress) {
+ deferred.notify({
+ index: index,
+ value: progress
+ });
+ }
+ }, undefined);
+
+ return deferred.promise;
+}
+
+Promise.prototype.any = function () {
+ return any(this);
+};
+
+/**
* Waits for all promises to be settled, either fulfilled or
* rejected. This is distinct from `all` since that would stop
* waiting at the first rejection. The promise returned by
@@ -1643,7 +1779,7 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
var onUnhandledError = function (error) {
// forward to a future turn so that ``when``
// does not catch it and turn it into a rejection.
- nextTick(function () {
+ Q.nextTick(function () {
makeStackTraceLong(error, promise);
if (Q.onerror) {
Q.onerror(error);
@@ -1670,18 +1806,22 @@ Promise.prototype.done = function (fulfilled, rejected, progress) {
* some milliseconds time out.
* @param {Any*} promise
* @param {Number} milliseconds timeout
- * @param {String} custom error message (optional)
+ * @param {Any*} custom error message or Error object (optional)
* @returns a promise for the resolution of the given promise if it is
* fulfilled before the timeout, otherwise rejected.
*/
-Q.timeout = function (object, ms, message) {
- return Q(object).timeout(ms, message);
+Q.timeout = function (object, ms, error) {
+ return Q(object).timeout(ms, error);
};
-Promise.prototype.timeout = function (ms, message) {
+Promise.prototype.timeout = function (ms, error) {
var deferred = defer();
var timeoutId = setTimeout(function () {
- deferred.reject(new Error(message || "Timed out after " + ms + " ms"));
+ if (!error || "string" === typeof error) {
+ error = new Error(error || "Timed out after " + ms + " ms");
+ error.code = "ETIMEDOUT";
+ }
+ deferred.reject(error);
}, ms);
this.then(function (value) {
@@ -1883,11 +2023,11 @@ function nodeify(object, nodeback) {
Promise.prototype.nodeify = function (nodeback) {
if (nodeback) {
this.then(function (value) {
- nextTick(function () {
+ Q.nextTick(function () {
nodeback(null, value);
});
}, function (error) {
- nextTick(function () {
+ Q.nextTick(function () {
nodeback(error);
});
});
@@ -1896,6 +2036,10 @@ Promise.prototype.nodeify = function (nodeback) {
}
};
+Q.noConflict = function() {
+ throw new Error("Q.noConflict only works when Q is used as a global");
+};
+
// All code before this point will be filtered from stack traces.
var qEndingLine = captureLine();
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json
index 674a1ffb..9827ccbc 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json
+++ b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/package.json
@@ -1,11 +1,29 @@
{
- "name": "shelljs",
- "version": "0.1.4",
"author": {
"name": "Artur Adib",
- "email": "aadib@mozilla.com"
+ "email": "arturadib@gmail.com"
},
+ "bin": {
+ "shjs": "./bin/shjs"
+ },
+ "bugs": {
+ "url": "https://github.com/arturadib/shelljs/issues"
+ },
+ "dependencies": {},
"description": "Portable Unix shell commands for Node.js",
+ "devDependencies": {
+ "jshint": "~2.1.11"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "c54982b996c76ef0c1e6b59fbdc5825f5b713113",
+ "tarball": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ },
+ "gitHead": "22d0975040b9b8234755dc6e692d6869436e8485",
+ "homepage": "http://github.com/arturadib/shelljs",
"keywords": [
"unix",
"shell",
@@ -14,35 +32,23 @@
"jake",
"synchronous"
],
+ "license": "BSD*",
+ "main": "./shell.js",
+ "maintainers": [
+ {
+ "name": "artur",
+ "email": "arturadib@gmail.com"
+ }
+ ],
+ "name": "shelljs",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/arturadib/shelljs.git"
},
- "homepage": "http://github.com/arturadib/shelljs",
- "main": "./shell.js",
"scripts": {
"test": "node scripts/run-tests"
},
- "bin": {
- "shjs": "./bin/shjs"
- },
- "dependencies": {},
- "devDependencies": {
- "jshint": "~1.1.0"
- },
- "optionalDependencies": {},
- "engines": {
- "node": "*"
- },
- "readme": "# ShellJS - Unix shell commands for Node.js [![Build Status](https://secure.travis-ci.org/arturadib/shelljs.png)](http://travis-ci.org/arturadib/shelljs)\n\nShellJS is a portable **(Windows/Linux/OS X)** implementation of Unix shell commands on top of the Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping its familiar and powerful commands. You can also install it globally so you can run it from outside Node projects - say goodbye to those gnarly Bash scripts!\n\nThe project is [unit-tested](http://travis-ci.org/arturadib/shelljs) and battled-tested in projects like:\n\n+ [PDF.js](http://github.com/mozilla/pdf.js) - Firefox's next-gen PDF reader\n+ [Firebug](http://getfirebug.com/) - Firefox's infamous debugger\n+ [JSHint](http://jshint.com) - Most popular JavaScript linter\n+ [Zepto](http://zeptojs.com) - jQuery-compatible JavaScript library for modern browsers\n+ [Yeoman](http://yeoman.io/) - Web application stack and development tool\n+ [Deployd.com](http://deployd.com) - Open source PaaS for quick API backend generation\n\nand [many more](https://npmjs.org/browse/depended/shelljs).\n\n## Installing\n\nVia npm:\n\n```bash\n$ npm install [-g] shelljs\n```\n\nIf the global option `-g` is specified, the binary `shjs` will be installed. This makes it possible to\nrun ShellJS scripts much like any shell script from the command line, i.e. without requiring a `node_modules` folder:\n\n```bash\n$ shjs my_script\n```\n\nYou can also just copy `shell.js` into your project's directory, and `require()` accordingly.\n\n\n## Examples\n\n### JavaScript\n\n```javascript\nrequire('shelljs/global');\n\nif (!which('git')) {\n echo('Sorry, this script requires git');\n exit(1);\n}\n\n// Copy files to release dir\nmkdir('-p', 'out/Release');\ncp('-R', 'stuff/*', 'out/Release');\n\n// Replace macros in each .js file\ncd('lib');\nls('*.js').forEach(function(file) {\n sed('-i', 'BUILD_VERSION', 'v0.1.2', file);\n sed('-i', /.*REMOVE_THIS_LINE.*\\n/, '', file);\n sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\\n/, cat('macro.js'), file);\n});\ncd('..');\n\n// Run external tool synchronously\nif (exec('git commit -am \"Auto-commit\"').code !== 0) {\n echo('Error: Git commit failed');\n exit(1);\n}\n```\n\n### CoffeeScript\n\n```coffeescript\nrequire 'shelljs/global'\n\nif not which 'git'\n echo 'Sorry, this script requires git'\n exit 1\n\n# Copy files to release dir\nmkdir '-p', 'out/Release'\ncp '-R', 'stuff/*', 'out/Release'\n\n# Replace macros in each .js file\ncd 'lib'\nfor file in ls '*.js'\n sed '-i', 'BUILD_VERSION', 'v0.1.2', file\n sed '-i', /.*REMOVE_THIS_LINE.*\\n/, '', file\n sed '-i', /.*REPLACE_LINE_WITH_MACRO.*\\n/, cat 'macro.js', file\ncd '..'\n\n# Run external tool synchronously\nif (exec 'git commit -am \"Auto-commit\"').code != 0\n echo 'Error: Git commit failed'\n exit 1\n```\n\n## Global vs. Local\n\nThe example above uses the convenience script `shelljs/global` to reduce verbosity. If polluting your global namespace is not desirable, simply require `shelljs`.\n\nExample:\n\n```javascript\nvar shell = require('shelljs');\nshell.echo('hello world');\n```\n\n## Make tool\n\nA convenience script `shelljs/make` is also provided to mimic the behavior of a Unix Makefile. In this case all shell objects are global, and command line arguments will cause the script to execute only the corresponding function in the global `target` object. To avoid redundant calls, target functions are executed only once per script.\n\nExample (CoffeeScript):\n\n```coffeescript\nrequire 'shelljs/make'\n\ntarget.all = ->\n target.bundle()\n target.docs()\n\ntarget.bundle = ->\n cd __dirname\n mkdir 'build'\n cd 'lib'\n (cat '*.js').to '../build/output.js'\n\ntarget.docs = ->\n cd __dirname\n mkdir 'docs'\n cd 'lib'\n for file in ls '*.js'\n text = grep '//@', file # extract special comments\n text.replace '//@', '' # remove comment tags\n text.to 'docs/my_docs.md'\n```\n\nTo run the target `all`, call the above script without arguments: `$ node make`. To run the target `docs`: `$ node make docs`, and so on.\n\n\n\n<!-- \n\n DO NOT MODIFY BEYOND THIS POINT - IT'S AUTOMATICALLY GENERATED\n\n-->\n\n\n## Command reference\n\n\nAll commands run synchronously, unless otherwise stated.\n\n\n### cd('dir')\nChanges to directory `dir` for the duration of the script\n\n### pwd()\nReturns the current directory.\n\n### ls([options ,] path [,path ...])\n### ls([options ,] path_array)\nAvailable options:\n\n+ `-R`: recursive\n+ `-A`: all files (include files beginning with `.`, except for `.` and `..`)\n\nExamples:\n\n```javascript\nls('projs/*.js');\nls('-R', '/users/me', '/tmp');\nls('-R', ['/users/me', '/tmp']); // same as above\n```\n\nReturns array of files in the given path, or in current directory if no path provided.\n\n### find(path [,path ...])\n### find(path_array)\nExamples:\n\n```javascript\nfind('src', 'lib');\nfind(['src', 'lib']); // same as above\nfind('.').filter(function(file) { return file.match(/\\.js$/); });\n```\n\nReturns array of all files (however deep) in the given paths.\n\nThe main difference from `ls('-R', path)` is that the resulting file names\ninclude the base directories, e.g. `lib/resources/file1` instead of just `file1`.\n\n### cp([options ,] source [,source ...], dest)\n### cp([options ,] source_array, dest)\nAvailable options:\n\n+ `-f`: force\n+ `-r, -R`: recursive\n\nExamples:\n\n```javascript\ncp('file1', 'dir1');\ncp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp');\ncp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above\n```\n\nCopies files. The wildcard `*` is accepted.\n\n### rm([options ,] file [, file ...])\n### rm([options ,] file_array)\nAvailable options:\n\n+ `-f`: force\n+ `-r, -R`: recursive\n\nExamples:\n\n```javascript\nrm('-rf', '/tmp/*');\nrm('some_file.txt', 'another_file.txt');\nrm(['some_file.txt', 'another_file.txt']); // same as above\n```\n\nRemoves files. The wildcard `*` is accepted.\n\n### mv(source [, source ...], dest')\n### mv(source_array, dest')\nAvailable options:\n\n+ `f`: force\n\nExamples:\n\n```javascript\nmv('-f', 'file', 'dir/');\nmv('file1', 'file2', 'dir/');\nmv(['file1', 'file2'], 'dir/'); // same as above\n```\n\nMoves files. The wildcard `*` is accepted.\n\n### mkdir([options ,] dir [, dir ...])\n### mkdir([options ,] dir_array)\nAvailable options:\n\n+ `p`: full path (will create intermediate dirs if necessary)\n\nExamples:\n\n```javascript\nmkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g');\nmkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above\n```\n\nCreates directories.\n\n### test(expression)\nAvailable expression primaries:\n\n+ `'-b', 'path'`: true if path is a block device\n+ `'-c', 'path'`: true if path is a character device\n+ `'-d', 'path'`: true if path is a directory\n+ `'-e', 'path'`: true if path exists\n+ `'-f', 'path'`: true if path is a regular file\n+ `'-L', 'path'`: true if path is a symbolic link\n+ `'-p', 'path'`: true if path is a pipe (FIFO)\n+ `'-S', 'path'`: true if path is a socket\n\nExamples:\n\n```javascript\nif (test('-d', path)) { /* do something with dir */ };\nif (!test('-f', path)) continue; // skip if it's a regular file\n```\n\nEvaluates expression using the available primaries and returns corresponding value.\n\n### cat(file [, file ...])\n### cat(file_array)\n\nExamples:\n\n```javascript\nvar str = cat('file*.txt');\nvar str = cat('file1', 'file2');\nvar str = cat(['file1', 'file2']); // same as above\n```\n\nReturns a string containing the given file, or a concatenated string\ncontaining the files if more than one file is given (a new line character is\nintroduced between each file). Wildcard `*` accepted.\n\n### 'string'.to(file)\n\nExamples:\n\n```javascript\ncat('input.txt').to('output.txt');\n```\n\nAnalogous to the redirection operator `>` in Unix, but works with JavaScript strings (such as\nthose returned by `cat`, `grep`, etc). _Like Unix redirections, `to()` will overwrite any existing file!_\n\n### sed([options ,] search_regex, replace_str, file)\nAvailable options:\n\n+ `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_\n\nExamples:\n\n```javascript\nsed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js');\nsed(/.*DELETE_THIS_LINE.*\\n/, '', 'source.js');\n```\n\nReads an input string from `file` and performs a JavaScript `replace()` on the input\nusing the given search regex and replacement string. Returns the new string after replacement.\n\n### grep([options ,] regex_filter, file [, file ...])\n### grep([options ,] regex_filter, file_array)\nAvailable options:\n\n+ `-v`: Inverse the sense of the regex and print the lines not matching the criteria.\n\nExamples:\n\n```javascript\ngrep('-v', 'GLOBAL_VARIABLE', '*.js');\ngrep('GLOBAL_VARIABLE', '*.js');\n```\n\nReads input string from given files and returns a string containing all lines of the\nfile that match the given `regex_filter`. Wildcard `*` accepted.\n\n### which(command)\n\nExamples:\n\n```javascript\nvar nodeExec = which('node');\n```\n\nSearches for `command` in the system's PATH. On Windows looks for `.exe`, `.cmd`, and `.bat` extensions.\nReturns string containing the absolute path to the command.\n\n### echo(string [,string ...])\n\nExamples:\n\n```javascript\necho('hello world');\nvar str = echo('hello world');\n```\n\nPrints string to stdout, and returns string with additional utility methods\nlike `.to()`.\n\n### dirs([options | '+N' | '-N'])\n\nAvailable options:\n\n+ `-c`: Clears the directory stack by deleting all of the elements.\n\nArguments:\n\n+ `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero.\n+ `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero.\n\nDisplay the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified.\n\nSee also: pushd, popd\n\n### pushd([options,] [dir | '-N' | '+N'])\n\nAvailable options:\n\n+ `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated.\n\nArguments:\n\n+ `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`.\n+ `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.\n+ `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.\n\nExamples:\n\n```javascript\n// process.cwd() === '/usr'\npushd('/etc'); // Returns /etc /usr\npushd('+1'); // Returns /usr /etc\n```\n\nSave the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack.\n\n### popd([options,] ['-N' | '+N'])\n\nAvailable options:\n\n+ `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.\n\nArguments:\n\n+ `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero.\n+ `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero.\n\nExamples:\n\n```javascript\necho(process.cwd()); // '/usr'\npushd('/etc'); // '/etc /usr'\necho(process.cwd()); // '/etc'\npopd(); // '/usr'\necho(process.cwd()); // '/usr'\n```\n\nWhen no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack.\n\n### exit(code)\nExits the current process with the given exit code.\n\n### env['VAR_NAME']\nObject containing environment variables (both getter and setter). Shortcut to process.env.\n\n### exec(command [, options] [, callback])\nAvailable options (all `false` by default):\n\n+ `async`: Asynchronous execution. Defaults to true if a callback is provided.\n+ `silent`: Do not echo program output to console.\n\nExamples:\n\n```javascript\nvar version = exec('node --version', {silent:true}).output;\n\nvar child = exec('some_long_running_process', {async:true});\nchild.stdout.on('data', function(data) {\n /* ... do something with data ... */\n});\n\nexec('some_long_running_process', function(code, output) {\n console.log('Exit code:', code);\n console.log('Program output:', output);\n});\n```\n\nExecutes the given `command` _synchronously_, unless otherwise specified.\nWhen in synchronous mode returns the object `{ code:..., output:... }`, containing the program's\n`output` (stdout + stderr) and its exit `code`. Otherwise returns the child process object, and\nthe `callback` gets the arguments `(code, output)`.\n\n**Note:** For long-lived processes, it's best to run `exec()` asynchronously as\nthe current synchronous implementation uses a lot of CPU. This should be getting\nfixed soon.\n\n### chmod(octal_mode || octal_string, file)\n### chmod(symbolic_mode, file)\n\nAvailable options:\n\n+ `-v`: output a diagnostic for every file processed\n+ `-c`: like verbose but report only when a change is made\n+ `-R`: change files and directories recursively\n\nExamples:\n\n```javascript\nchmod(755, '/Users/brandon');\nchmod('755', '/Users/brandon'); // same as above \nchmod('u+x', '/Users/brandon');\n```\n\nAlters the permissions of a file or directory by either specifying the\nabsolute permissions in octal form or expressing the changes in symbols.\nThis command tries to mimic the POSIX behavior as much as possible.\nNotable exceptions:\n\n+ In symbolic modes, 'a-r' and '-r' are identical. No consideration is\n given to the umask.\n+ There is no \"quiet\" option since default behavior is to run silent.\n\n## Configuration\n\n\n### config.silent\nExample:\n\n```javascript\nvar silentState = config.silent; // save old silent state\nconfig.silent = true;\n/* ... */\nconfig.silent = silentState; // restore old silent state\n```\n\nSuppresses all command output if `true`, except for `echo()` calls.\nDefault is `false`.\n\n### config.fatal\nExample:\n\n```javascript\nconfig.fatal = true;\ncp('this_file_does_not_exist', '/dev/null'); // dies here\n/* more commands... */\n```\n\nIf `true` the script will die on errors. Default is `false`.\n\n## Non-Unix commands\n\n\n### tempdir()\nSearches and returns string containing a writeable, platform-dependent temporary directory.\nFollows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).\n\n### error()\nTests if error occurred in the last command. Returns `null` if no error occurred,\notherwise returns string explaining the error\n",
- "readmeFilename": "README.md",
- "bugs": {
- "url": "https://github.com/arturadib/shelljs/issues"
- },
- "_id": "shelljs@0.1.4",
- "dist": {
- "shasum": "7a8aeaa3dc3c0be2e59d83168e83b4c4bc4dac95"
- },
- "_from": "shelljs@0.1.4",
- "_resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.1.4.tgz"
-}
+ "version": "0.5.3"
+} \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js
index 4190aa34..bdeb5597 100755
--- a/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js
+++ b/StoneIsland/platforms/ios/cordova/node_modules/shelljs/shell.js
@@ -6,1062 +6,88 @@
// http://github.com/arturadib/shelljs
//
-var fs = require('fs'),
- path = require('path'),
- util = require('util'),
- vm = require('vm'),
- child = require('child_process'),
- os = require('os');
-
-// Node shims for < v0.7
-fs.existsSync = fs.existsSync || path.existsSync;
-
-var config = {
- silent: false,
- fatal: false
-};
-
-var state = {
- error: null,
- currentCmd: 'shell.js',
- tempDir: null
- },
- platform = os.type().match(/^Win/) ? 'win' : 'unix';
+var common = require('./src/common');
//@
//@ All commands run synchronously, unless otherwise stated.
//@
+//@include ./src/cd
+var _cd = require('./src/cd');
+exports.cd = common.wrap('cd', _cd);
-//@
-//@ ### cd('dir')
-//@ Changes to directory `dir` for the duration of the script
-function _cd(options, dir) {
- if (!dir)
- error('directory not specified');
-
- if (!fs.existsSync(dir))
- error('no such file or directory: ' + dir);
-
- if (!fs.statSync(dir).isDirectory())
- error('not a directory: ' + dir);
-
- process.chdir(dir);
-}
-exports.cd = wrap('cd', _cd);
-
-//@
-//@ ### pwd()
-//@ Returns the current directory.
-function _pwd(options) {
- var pwd = path.resolve(process.cwd());
- return ShellString(pwd);
-}
-exports.pwd = wrap('pwd', _pwd);
-
-
-//@
-//@ ### ls([options ,] path [,path ...])
-//@ ### ls([options ,] path_array)
-//@ Available options:
-//@
-//@ + `-R`: recursive
-//@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`)
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ ls('projs/*.js');
-//@ ls('-R', '/users/me', '/tmp');
-//@ ls('-R', ['/users/me', '/tmp']); // same as above
-//@ ```
-//@
-//@ Returns array of files in the given path, or in current directory if no path provided.
-function _ls(options, paths) {
- options = parseOptions(options, {
- 'R': 'recursive',
- 'A': 'all',
- 'a': 'all_deprecated'
- });
-
- if (options.all_deprecated) {
- // We won't support the -a option as it's hard to image why it's useful
- // (it includes '.' and '..' in addition to '.*' files)
- // For backwards compatibility we'll dump a deprecated message and proceed as before
- log('ls: Option -a is deprecated. Use -A instead');
- options.all = true;
- }
-
- if (!paths)
- paths = ['.'];
- else if (typeof paths === 'object')
- paths = paths; // assume array
- else if (typeof paths === 'string')
- paths = [].slice.call(arguments, 1);
-
- var list = [];
-
- // Conditionally pushes file to list - returns true if pushed, false otherwise
- // (e.g. prevents hidden files to be included unless explicitly told so)
- function pushFile(file, query) {
- // hidden file?
- if (path.basename(file)[0] === '.') {
- // not explicitly asking for hidden files?
- if (!options.all && !(path.basename(query)[0] === '.' && path.basename(query).length > 1))
- return false;
- }
-
- if (platform === 'win')
- file = file.replace(/\\/g, '/');
-
- list.push(file);
- return true;
- }
-
- paths.forEach(function(p) {
- if (fs.existsSync(p)) {
- var stats = fs.statSync(p);
- // Simple file?
- if (stats.isFile()) {
- pushFile(p, p);
- return; // continue
- }
-
- // Simple dir?
- if (stats.isDirectory()) {
- // Iterate over p contents
- fs.readdirSync(p).forEach(function(file) {
- if (!pushFile(file, p))
- return;
-
- // Recursive?
- if (options.recursive) {
- var oldDir = _pwd();
- _cd('', p);
- if (fs.statSync(file).isDirectory())
- list = list.concat(_ls('-R'+(options.all?'A':''), file+'/*'));
- _cd('', oldDir);
- }
- });
- return; // continue
- }
- }
-
- // p does not exist - possible wildcard present
-
- var basename = path.basename(p);
- var dirname = path.dirname(p);
- // Wildcard present on an existing dir? (e.g. '/tmp/*.js')
- if (basename.search(/\*/) > -1 && fs.existsSync(dirname) && fs.statSync(dirname).isDirectory) {
- // Escape special regular expression chars
- var regexp = basename.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\.|\+|\?)/g, '\\$1');
- // Translates wildcard into regex
- regexp = '^' + regexp.replace(/\*/g, '.*') + '$';
- // Iterate over directory contents
- fs.readdirSync(dirname).forEach(function(file) {
- if (file.match(new RegExp(regexp))) {
- if (!pushFile(path.normalize(dirname+'/'+file), basename))
- return;
-
- // Recursive?
- if (options.recursive) {
- var pp = dirname + '/' + file;
- if (fs.lstatSync(pp).isDirectory())
- list = list.concat(_ls('-R'+(options.all?'A':''), pp+'/*'));
- } // recursive
- } // if file matches
- }); // forEach
- return;
- }
-
- error('no such file or directory: ' + p, true);
- });
-
- return list;
-}
-exports.ls = wrap('ls', _ls);
-
-
-//@
-//@ ### find(path [,path ...])
-//@ ### find(path_array)
-//@ Examples:
-//@
-//@ ```javascript
-//@ find('src', 'lib');
-//@ find(['src', 'lib']); // same as above
-//@ find('.').filter(function(file) { return file.match(/\.js$/); });
-//@ ```
-//@
-//@ Returns array of all files (however deep) in the given paths.
-//@
-//@ The main difference from `ls('-R', path)` is that the resulting file names
-//@ include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
-function _find(options, paths) {
- if (!paths)
- error('no path specified');
- else if (typeof paths === 'object')
- paths = paths; // assume array
- else if (typeof paths === 'string')
- paths = [].slice.call(arguments, 1);
-
- var list = [];
-
- function pushFile(file) {
- if (platform === 'win')
- file = file.replace(/\\/g, '/');
- list.push(file);
- }
-
- // why not simply do ls('-R', paths)? because the output wouldn't give the base dirs
- // to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory
-
- paths.forEach(function(file) {
- pushFile(file);
-
- if (fs.statSync(file).isDirectory()) {
- _ls('-RA', file+'/*').forEach(function(subfile) {
- pushFile(subfile);
- });
- }
- });
-
- return list;
-}
-exports.find = wrap('find', _find);
-
-
-//@
-//@ ### cp([options ,] source [,source ...], dest)
-//@ ### cp([options ,] source_array, dest)
-//@ Available options:
-//@
-//@ + `-f`: force
-//@ + `-r, -R`: recursive
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ cp('file1', 'dir1');
-//@ cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp');
-//@ cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above
-//@ ```
-//@
-//@ Copies files. The wildcard `*` is accepted.
-function _cp(options, sources, dest) {
- options = parseOptions(options, {
- 'f': 'force',
- 'R': 'recursive',
- 'r': 'recursive'
- });
-
- // Get sources, dest
- if (arguments.length < 3) {
- error('missing <source> and/or <dest>');
- } else if (arguments.length > 3) {
- sources = [].slice.call(arguments, 1, arguments.length - 1);
- dest = arguments[arguments.length - 1];
- } else if (typeof sources === 'string') {
- sources = [sources];
- } else if ('length' in sources) {
- sources = sources; // no-op for array
- } else {
- error('invalid arguments');
- }
-
- var exists = fs.existsSync(dest),
- stats = exists && fs.statSync(dest);
-
- // Dest is not existing dir, but multiple sources given
- if ((!exists || !stats.isDirectory()) && sources.length > 1)
- error('dest is not a directory (too many sources)');
-
- // Dest is an existing file, but no -f given
- if (exists && stats.isFile() && !options.force)
- error('dest file already exists: ' + dest);
-
- if (options.recursive) {
- // Recursive allows the shortcut syntax "sourcedir/" for "sourcedir/*"
- // (see Github issue #15)
- sources.forEach(function(src, i) {
- if (src[src.length - 1] === '/')
- sources[i] += '*';
- });
-
- // Create dest
- try {
- fs.mkdirSync(dest, parseInt('0777', 8));
- } catch (e) {
- // like Unix's cp, keep going even if we can't create dest dir
- }
- }
-
- sources = expand(sources);
-
- sources.forEach(function(src) {
- if (!fs.existsSync(src)) {
- error('no such file or directory: '+src, true);
- return; // skip file
- }
-
- // If here, src exists
- if (fs.statSync(src).isDirectory()) {
- if (!options.recursive) {
- // Non-Recursive
- log(src + ' is a directory (not copied)');
- } else {
- // Recursive
- // 'cp /a/source dest' should create 'source' in 'dest'
- var newDest = path.join(dest, path.basename(src)),
- checkDir = fs.statSync(src);
- try {
- fs.mkdirSync(newDest, checkDir.mode);
- } catch (e) {
- //if the directory already exists, that's okay
- if (e.code !== 'EEXIST') throw e;
- }
-
- cpdirSyncRecursive(src, newDest, {force: options.force});
- }
- return; // done with dir
- }
-
- // If here, src is a file
-
- // When copying to '/path/dir':
- // thisDest = '/path/dir/file1'
- var thisDest = dest;
- if (fs.existsSync(dest) && fs.statSync(dest).isDirectory())
- thisDest = path.normalize(dest + '/' + path.basename(src));
-
- if (fs.existsSync(thisDest) && !options.force) {
- error('dest file already exists: ' + thisDest, true);
- return; // skip file
- }
-
- copyFileSync(src, thisDest);
- }); // forEach(src)
-}
-exports.cp = wrap('cp', _cp);
-
-//@
-//@ ### rm([options ,] file [, file ...])
-//@ ### rm([options ,] file_array)
-//@ Available options:
-//@
-//@ + `-f`: force
-//@ + `-r, -R`: recursive
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ rm('-rf', '/tmp/*');
-//@ rm('some_file.txt', 'another_file.txt');
-//@ rm(['some_file.txt', 'another_file.txt']); // same as above
-//@ ```
-//@
-//@ Removes files. The wildcard `*` is accepted.
-function _rm(options, files) {
- options = parseOptions(options, {
- 'f': 'force',
- 'r': 'recursive',
- 'R': 'recursive'
- });
- if (!files)
- error('no paths given');
-
- if (typeof files === 'string')
- files = [].slice.call(arguments, 1);
- // if it's array leave it as it is
-
- files = expand(files);
-
- files.forEach(function(file) {
- if (!fs.existsSync(file)) {
- // Path does not exist, no force flag given
- if (!options.force)
- error('no such file or directory: '+file, true);
-
- return; // skip file
- }
-
- // If here, path exists
-
- var stats = fs.statSync(file);
- // Remove simple file
- if (stats.isFile()) {
-
- // Do not check for file writing permissions
- if (options.force) {
- _unlinkSync(file);
- return;
- }
-
- if (isWriteable(file))
- _unlinkSync(file);
- else
- error('permission denied: '+file, true);
-
- return;
- } // simple file
-
- // Path is an existing directory, but no -r flag given
- if (stats.isDirectory() && !options.recursive) {
- error('path is a directory', true);
- return; // skip path
- }
-
- // Recursively remove existing directory
- if (stats.isDirectory() && options.recursive) {
- rmdirSyncRecursive(file, options.force);
- }
- }); // forEach(file)
-} // rm
-exports.rm = wrap('rm', _rm);
-
-//@
-//@ ### mv(source [, source ...], dest')
-//@ ### mv(source_array, dest')
-//@ Available options:
-//@
-//@ + `f`: force
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ mv('-f', 'file', 'dir/');
-//@ mv('file1', 'file2', 'dir/');
-//@ mv(['file1', 'file2'], 'dir/'); // same as above
-//@ ```
-//@
-//@ Moves files. The wildcard `*` is accepted.
-function _mv(options, sources, dest) {
- options = parseOptions(options, {
- 'f': 'force'
- });
-
- // Get sources, dest
- if (arguments.length < 3) {
- error('missing <source> and/or <dest>');
- } else if (arguments.length > 3) {
- sources = [].slice.call(arguments, 1, arguments.length - 1);
- dest = arguments[arguments.length - 1];
- } else if (typeof sources === 'string') {
- sources = [sources];
- } else if ('length' in sources) {
- sources = sources; // no-op for array
- } else {
- error('invalid arguments');
- }
-
- sources = expand(sources);
-
- var exists = fs.existsSync(dest),
- stats = exists && fs.statSync(dest);
-
- // Dest is not existing dir, but multiple sources given
- if ((!exists || !stats.isDirectory()) && sources.length > 1)
- error('dest is not a directory (too many sources)');
-
- // Dest is an existing file, but no -f given
- if (exists && stats.isFile() && !options.force)
- error('dest file already exists: ' + dest);
-
- sources.forEach(function(src) {
- if (!fs.existsSync(src)) {
- error('no such file or directory: '+src, true);
- return; // skip file
- }
-
- // If here, src exists
-
- // When copying to '/path/dir':
- // thisDest = '/path/dir/file1'
- var thisDest = dest;
- if (fs.existsSync(dest) && fs.statSync(dest).isDirectory())
- thisDest = path.normalize(dest + '/' + path.basename(src));
-
- if (fs.existsSync(thisDest) && !options.force) {
- error('dest file already exists: ' + thisDest, true);
- return; // skip file
- }
-
- if (path.resolve(src) === path.dirname(path.resolve(thisDest))) {
- error('cannot move to self: '+src, true);
- return; // skip file
- }
-
- fs.renameSync(src, thisDest);
- }); // forEach(src)
-} // mv
-exports.mv = wrap('mv', _mv);
-
-//@
-//@ ### mkdir([options ,] dir [, dir ...])
-//@ ### mkdir([options ,] dir_array)
-//@ Available options:
-//@
-//@ + `p`: full path (will create intermediate dirs if necessary)
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ mkdir('-p', '/tmp/a/b/c/d', '/tmp/e/f/g');
-//@ mkdir('-p', ['/tmp/a/b/c/d', '/tmp/e/f/g']); // same as above
-//@ ```
-//@
-//@ Creates directories.
-function _mkdir(options, dirs) {
- options = parseOptions(options, {
- 'p': 'fullpath'
- });
- if (!dirs)
- error('no paths given');
-
- if (typeof dirs === 'string')
- dirs = [].slice.call(arguments, 1);
- // if it's array leave it as it is
-
- dirs.forEach(function(dir) {
- if (fs.existsSync(dir)) {
- if (!options.fullpath)
- error('path already exists: ' + dir, true);
- return; // skip dir
- }
-
- // Base dir does not exist, and no -p option given
- var baseDir = path.dirname(dir);
- if (!fs.existsSync(baseDir) && !options.fullpath) {
- error('no such file or directory: ' + baseDir, true);
- return; // skip dir
- }
-
- if (options.fullpath)
- mkdirSyncRecursive(dir);
- else
- fs.mkdirSync(dir, parseInt('0777', 8));
- });
-} // mkdir
-exports.mkdir = wrap('mkdir', _mkdir);
-
-//@
-//@ ### test(expression)
-//@ Available expression primaries:
-//@
-//@ + `'-b', 'path'`: true if path is a block device
-//@ + `'-c', 'path'`: true if path is a character device
-//@ + `'-d', 'path'`: true if path is a directory
-//@ + `'-e', 'path'`: true if path exists
-//@ + `'-f', 'path'`: true if path is a regular file
-//@ + `'-L', 'path'`: true if path is a symbolic link
-//@ + `'-p', 'path'`: true if path is a pipe (FIFO)
-//@ + `'-S', 'path'`: true if path is a socket
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ if (test('-d', path)) { /* do something with dir */ };
-//@ if (!test('-f', path)) continue; // skip if it's a regular file
-//@ ```
-//@
-//@ Evaluates expression using the available primaries and returns corresponding value.
-function _test(options, path) {
- if (!path)
- error('no path given');
-
- // hack - only works with unary primaries
- options = parseOptions(options, {
- 'b': 'block',
- 'c': 'character',
- 'd': 'directory',
- 'e': 'exists',
- 'f': 'file',
- 'L': 'link',
- 'p': 'pipe',
- 'S': 'socket'
- });
-
- var canInterpret = false;
- for (var key in options)
- if (options[key] === true) {
- canInterpret = true;
- break;
- }
-
- if (!canInterpret)
- error('could not interpret expression');
-
- if (options.link) {
- try {
- return fs.lstatSync(path).isSymbolicLink();
- } catch(e) {
- return false;
- }
- }
-
- if (!fs.existsSync(path))
- return false;
-
- if (options.exists)
- return true;
-
- var stats = fs.statSync(path);
-
- if (options.block)
- return stats.isBlockDevice();
-
- if (options.character)
- return stats.isCharacterDevice();
-
- if (options.directory)
- return stats.isDirectory();
-
- if (options.file)
- return stats.isFile();
-
- if (options.pipe)
- return stats.isFIFO();
-
- if (options.socket)
- return stats.isSocket();
-} // test
-exports.test = wrap('test', _test);
-
-
-//@
-//@ ### cat(file [, file ...])
-//@ ### cat(file_array)
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ var str = cat('file*.txt');
-//@ var str = cat('file1', 'file2');
-//@ var str = cat(['file1', 'file2']); // same as above
-//@ ```
-//@
-//@ Returns a string containing the given file, or a concatenated string
-//@ containing the files if more than one file is given (a new line character is
-//@ introduced between each file). Wildcard `*` accepted.
-function _cat(options, files) {
- var cat = '';
-
- if (!files)
- error('no paths given');
-
- if (typeof files === 'string')
- files = [].slice.call(arguments, 1);
- // if it's array leave it as it is
-
- files = expand(files);
-
- files.forEach(function(file) {
- if (!fs.existsSync(file))
- error('no such file or directory: ' + file);
-
- cat += fs.readFileSync(file, 'utf8') + '\n';
- });
-
- if (cat[cat.length-1] === '\n')
- cat = cat.substring(0, cat.length-1);
-
- return ShellString(cat);
-}
-exports.cat = wrap('cat', _cat);
-
-//@
-//@ ### 'string'.to(file)
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ cat('input.txt').to('output.txt');
-//@ ```
-//@
-//@ Analogous to the redirection operator `>` in Unix, but works with JavaScript strings (such as
-//@ those returned by `cat`, `grep`, etc). _Like Unix redirections, `to()` will overwrite any existing file!_
-function _to(options, file) {
- if (!file)
- error('wrong arguments');
-
- if (!fs.existsSync( path.dirname(file) ))
- error('no such file or directory: ' + path.dirname(file));
-
- try {
- fs.writeFileSync(file, this.toString(), 'utf8');
- } catch(e) {
- error('could not write to file (code '+e.code+'): '+file, true);
- }
-}
-// In the future, when Proxies are default, we can add methods like `.to()` to primitive strings.
-// For now, this is a dummy function to bookmark places we need such strings
-function ShellString(str) {
- return str;
-}
-String.prototype.to = wrap('to', _to);
-
-//@
-//@ ### sed([options ,] search_regex, replace_str, file)
-//@ Available options:
-//@
-//@ + `-i`: Replace contents of 'file' in-place. _Note that no backups will be created!_
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ sed('-i', 'PROGRAM_VERSION', 'v0.1.3', 'source.js');
-//@ sed(/.*DELETE_THIS_LINE.*\n/, '', 'source.js');
-//@ ```
-//@
-//@ Reads an input string from `file` and performs a JavaScript `replace()` on the input
-//@ using the given search regex and replacement string. Returns the new string after replacement.
-function _sed(options, regex, replacement, file) {
- options = parseOptions(options, {
- 'i': 'inplace'
- });
-
- if (typeof replacement === 'string')
- replacement = replacement; // no-op
- else if (typeof replacement === 'number')
- replacement = replacement.toString(); // fallback
- else
- error('invalid replacement string');
-
- if (!file)
- error('no file given');
-
- if (!fs.existsSync(file))
- error('no such file or directory: ' + file);
-
- var result = fs.readFileSync(file, 'utf8').replace(regex, replacement);
- if (options.inplace)
- fs.writeFileSync(file, result, 'utf8');
-
- return ShellString(result);
-}
-exports.sed = wrap('sed', _sed);
-
-//@
-//@ ### grep([options ,] regex_filter, file [, file ...])
-//@ ### grep([options ,] regex_filter, file_array)
-//@ Available options:
-//@
-//@ + `-v`: Inverse the sense of the regex and print the lines not matching the criteria.
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ grep('-v', 'GLOBAL_VARIABLE', '*.js');
-//@ grep('GLOBAL_VARIABLE', '*.js');
-//@ ```
-//@
-//@ Reads input string from given files and returns a string containing all lines of the
-//@ file that match the given `regex_filter`. Wildcard `*` accepted.
-function _grep(options, regex, files) {
- options = parseOptions(options, {
- 'v': 'inverse'
- });
-
- if (!files)
- error('no paths given');
-
- if (typeof files === 'string')
- files = [].slice.call(arguments, 2);
- // if it's array leave it as it is
-
- files = expand(files);
-
- var grep = '';
- files.forEach(function(file) {
- if (!fs.existsSync(file)) {
- error('no such file or directory: ' + file, true);
- return;
- }
-
- var contents = fs.readFileSync(file, 'utf8'),
- lines = contents.split(/\r*\n/);
- lines.forEach(function(line) {
- var matched = line.match(regex);
- if ((options.inverse && !matched) || (!options.inverse && matched))
- grep += line + '\n';
- });
- });
-
- return ShellString(grep);
-}
-exports.grep = wrap('grep', _grep);
-
-
-//@
-//@ ### which(command)
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ var nodeExec = which('node');
-//@ ```
-//@
-//@ Searches for `command` in the system's PATH. On Windows looks for `.exe`, `.cmd`, and `.bat` extensions.
-//@ Returns string containing the absolute path to the command.
-function _which(options, cmd) {
- if (!cmd)
- error('must specify command');
-
- var pathEnv = process.env.path || process.env.Path || process.env.PATH,
- pathArray = splitPath(pathEnv),
- where = null;
-
- // No relative/absolute paths provided?
- if (cmd.search(/\//) === -1) {
- // Search for command in PATH
- pathArray.forEach(function(dir) {
- if (where)
- return; // already found it
-
- var attempt = path.resolve(dir + '/' + cmd);
- if (fs.existsSync(attempt)) {
- where = attempt;
- return;
- }
-
- if (platform === 'win') {
- var baseAttempt = attempt;
- attempt = baseAttempt + '.exe';
- if (fs.existsSync(attempt)) {
- where = attempt;
- return;
- }
- attempt = baseAttempt + '.cmd';
- if (fs.existsSync(attempt)) {
- where = attempt;
- return;
- }
- attempt = baseAttempt + '.bat';
- if (fs.existsSync(attempt)) {
- where = attempt;
- return;
- }
- } // if 'win'
- });
- }
-
- // Command not found anywhere?
- if (!fs.existsSync(cmd) && !where)
- return null;
-
- where = where || path.resolve(cmd);
-
- return ShellString(where);
-}
-exports.which = wrap('which', _which);
-
-//@
-//@ ### echo(string [,string ...])
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ echo('hello world');
-//@ var str = echo('hello world');
-//@ ```
-//@
-//@ Prints string to stdout, and returns string with additional utility methods
-//@ like `.to()`.
-function _echo() {
- var messages = [].slice.call(arguments, 0);
- console.log.apply(this, messages);
- return ShellString(messages.join(' '));
-}
-exports.echo = _echo; // don't wrap() as it could parse '-options'
-
-// Pushd/popd/dirs internals
-var _dirStack = [];
-
-function _isStackIndex(index) {
- return (/^[\-+]\d+$/).test(index);
-}
+//@include ./src/pwd
+var _pwd = require('./src/pwd');
+exports.pwd = common.wrap('pwd', _pwd);
-function _parseStackIndex(index) {
- if (_isStackIndex(index)) {
- if (Math.abs(index) < _dirStack.length + 1) { // +1 for pwd
- return (/^-/).test(index) ? Number(index) - 1 : Number(index);
- } else {
- error(index + ': directory stack index out of range');
- }
- } else {
- error(index + ': invalid number');
- }
-}
+//@include ./src/ls
+var _ls = require('./src/ls');
+exports.ls = common.wrap('ls', _ls);
-function _actualDirStack() {
- return [process.cwd()].concat(_dirStack);
-}
+//@include ./src/find
+var _find = require('./src/find');
+exports.find = common.wrap('find', _find);
-//@
-//@ ### dirs([options | '+N' | '-N'])
-//@
-//@ Available options:
-//@
-//@ + `-c`: Clears the directory stack by deleting all of the elements.
-//@
-//@ Arguments:
-//@
-//@ + `+N`: Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options), starting with zero.
-//@ + `-N`: Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options), starting with zero.
-//@
-//@ Display the list of currently remembered directories. Returns an array of paths in the stack, or a single path if +N or -N was specified.
-//@
-//@ See also: pushd, popd
-function _dirs(options, index) {
- if (_isStackIndex(options)) {
- index = options;
- options = '';
- }
+//@include ./src/cp
+var _cp = require('./src/cp');
+exports.cp = common.wrap('cp', _cp);
- options = parseOptions(options, {
- 'c' : 'clear'
- });
+//@include ./src/rm
+var _rm = require('./src/rm');
+exports.rm = common.wrap('rm', _rm);
- if (options['clear']) {
- _dirStack = [];
- return _dirStack;
- }
+//@include ./src/mv
+var _mv = require('./src/mv');
+exports.mv = common.wrap('mv', _mv);
- var stack = _actualDirStack();
+//@include ./src/mkdir
+var _mkdir = require('./src/mkdir');
+exports.mkdir = common.wrap('mkdir', _mkdir);
- if (index) {
- index = _parseStackIndex(index);
+//@include ./src/test
+var _test = require('./src/test');
+exports.test = common.wrap('test', _test);
- if (index < 0) {
- index = stack.length + index;
- }
+//@include ./src/cat
+var _cat = require('./src/cat');
+exports.cat = common.wrap('cat', _cat);
- log(stack[index]);
- return stack[index];
- }
+//@include ./src/to
+var _to = require('./src/to');
+String.prototype.to = common.wrap('to', _to);
- log(stack.join(' '));
+//@include ./src/toEnd
+var _toEnd = require('./src/toEnd');
+String.prototype.toEnd = common.wrap('toEnd', _toEnd);
- return stack;
-}
-exports.dirs = wrap("dirs", _dirs);
+//@include ./src/sed
+var _sed = require('./src/sed');
+exports.sed = common.wrap('sed', _sed);
-//@
-//@ ### pushd([options,] [dir | '-N' | '+N'])
-//@
-//@ Available options:
-//@
-//@ + `-n`: Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated.
-//@
-//@ Arguments:
-//@
-//@ + `dir`: Makes the current working directory be the top of the stack, and then executes the equivalent of `cd dir`.
-//@ + `+N`: Brings the Nth directory (counting from the left of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-//@ + `-N`: Brings the Nth directory (counting from the right of the list printed by dirs, starting with zero) to the top of the list by rotating the stack.
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ // process.cwd() === '/usr'
-//@ pushd('/etc'); // Returns /etc /usr
-//@ pushd('+1'); // Returns /usr /etc
-//@ ```
-//@
-//@ Save the current directory on the top of the directory stack and then cd to `dir`. With no arguments, pushd exchanges the top two directories. Returns an array of paths in the stack.
-function _pushd(options, dir) {
- if (_isStackIndex(options)) {
- dir = options;
- options = '';
- }
+//@include ./src/grep
+var _grep = require('./src/grep');
+exports.grep = common.wrap('grep', _grep);
- options = parseOptions(options, {
- 'n' : 'no-cd'
- });
+//@include ./src/which
+var _which = require('./src/which');
+exports.which = common.wrap('which', _which);
- var dirs = _actualDirStack();
+//@include ./src/echo
+var _echo = require('./src/echo');
+exports.echo = _echo; // don't common.wrap() as it could parse '-options'
- if (dir === '+0') {
- return dirs; // +0 is a noop
- } else if (!dir) {
- if (dirs.length > 1) {
- dirs = dirs.splice(1, 1).concat(dirs);
- } else {
- return error('no other directory');
- }
- } else if (_isStackIndex(dir)) {
- var n = _parseStackIndex(dir);
- dirs = dirs.slice(n).concat(dirs.slice(0, n));
- } else {
- if (options['no-cd']) {
- dirs.splice(1, 0, dir);
- } else {
- dirs.unshift(dir);
- }
- }
+//@include ./src/dirs
+var _dirs = require('./src/dirs').dirs;
+exports.dirs = common.wrap("dirs", _dirs);
+var _pushd = require('./src/dirs').pushd;
+exports.pushd = common.wrap('pushd', _pushd);
+var _popd = require('./src/dirs').popd;
+exports.popd = common.wrap("popd", _popd);
- if (options['no-cd']) {
- dirs = dirs.slice(1);
- } else {
- dir = path.resolve(dirs.shift());
- _cd('', dir);
- }
-
- _dirStack = dirs;
- return _dirs('');
-}
-exports.pushd = wrap('pushd', _pushd);
-
-//@
-//@ ### popd([options,] ['-N' | '+N'])
-//@
-//@ Available options:
-//@
-//@ + `-n`: Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.
-//@
-//@ Arguments:
-//@
-//@ + `+N`: Removes the Nth directory (counting from the left of the list printed by dirs), starting with zero.
-//@ + `-N`: Removes the Nth directory (counting from the right of the list printed by dirs), starting with zero.
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ echo(process.cwd()); // '/usr'
-//@ pushd('/etc'); // '/etc /usr'
-//@ echo(process.cwd()); // '/etc'
-//@ popd(); // '/usr'
-//@ echo(process.cwd()); // '/usr'
-//@ ```
-//@
-//@ When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; i.e., popd is equivalent to popd +0. Returns an array of paths in the stack.
-function _popd(options, index) {
- if (_isStackIndex(options)) {
- index = options;
- options = '';
- }
-
- options = parseOptions(options, {
- 'n' : 'no-cd'
- });
-
- if (!_dirStack.length) {
- return error('directory stack empty');
- }
-
- index = _parseStackIndex(index || '+0');
-
- if (options['no-cd'] || index > 0 || _dirStack.length + index === 0) {
- index = index > 0 ? index - 1 : index;
- _dirStack.splice(index, 1);
- } else {
- var dir = path.resolve(_dirStack.shift());
- _cd('', dir);
- }
-
- return _dirs('');
-}
-exports.popd = wrap("popd", _popd);
+//@include ./src/ln
+var _ln = require('./src/ln');
+exports.ln = common.wrap('ln', _ln);
//@
//@ ### exit(code)
@@ -1073,288 +99,47 @@ exports.exit = process.exit;
//@ Object containing environment variables (both getter and setter). Shortcut to process.env.
exports.env = process.env;
-//@
-//@ ### exec(command [, options] [, callback])
-//@ Available options (all `false` by default):
-//@
-//@ + `async`: Asynchronous execution. Defaults to true if a callback is provided.
-//@ + `silent`: Do not echo program output to console.
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ var version = exec('node --version', {silent:true}).output;
-//@
-//@ var child = exec('some_long_running_process', {async:true});
-//@ child.stdout.on('data', function(data) {
-//@ /* ... do something with data ... */
-//@ });
-//@
-//@ exec('some_long_running_process', function(code, output) {
-//@ console.log('Exit code:', code);
-//@ console.log('Program output:', output);
-//@ });
-//@ ```
-//@
-//@ Executes the given `command` _synchronously_, unless otherwise specified.
-//@ When in synchronous mode returns the object `{ code:..., output:... }`, containing the program's
-//@ `output` (stdout + stderr) and its exit `code`. Otherwise returns the child process object, and
-//@ the `callback` gets the arguments `(code, output)`.
-//@
-//@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as
-//@ the current synchronous implementation uses a lot of CPU. This should be getting
-//@ fixed soon.
-function _exec(command, options, callback) {
- if (!command)
- error('must specify command');
-
- // Callback is defined instead of options.
- if (typeof options === 'function') {
- callback = options;
- options = { async: true };
- }
-
- // Callback is defined with options.
- if (typeof options === 'object' && typeof callback === 'function') {
- options.async = true;
- }
-
- options = extend({
- silent: config.silent,
- async: false
- }, options);
+//@include ./src/exec
+var _exec = require('./src/exec');
+exports.exec = common.wrap('exec', _exec, {notUnix:true});
- if (options.async)
- return execAsync(command, options, callback);
- else
- return execSync(command, options);
-}
-exports.exec = wrap('exec', _exec, {notUnix:true});
+//@include ./src/chmod
+var _chmod = require('./src/chmod');
+exports.chmod = common.wrap('chmod', _chmod);
-var PERMS = (function (base) {
- return {
- OTHER_EXEC : base.EXEC,
- OTHER_WRITE : base.WRITE,
- OTHER_READ : base.READ,
- GROUP_EXEC : base.EXEC << 3,
- GROUP_WRITE : base.WRITE << 3,
- GROUP_READ : base.READ << 3,
- OWNER_EXEC : base.EXEC << 6,
- OWNER_WRITE : base.WRITE << 6,
- OWNER_READ : base.READ << 6,
-
- // Literal octal numbers are apparently not allowed in "strict" javascript. Using parseInt is
- // the preferred way, else a jshint warning is thrown.
- STICKY : parseInt('01000', 8),
- SETGID : parseInt('02000', 8),
- SETUID : parseInt('04000', 8),
-
- TYPE_MASK : parseInt('0770000', 8)
- };
-})({
- EXEC : 1,
- WRITE : 2,
- READ : 4
-});
-
-
-//@
-//@ ### chmod(octal_mode || octal_string, file)
-//@ ### chmod(symbolic_mode, file)
-//@
-//@ Available options:
//@
-//@ + `-v`: output a diagnostic for every file processed//@
-//@ + `-c`: like verbose but report only when a change is made//@
-//@ + `-R`: change files and directories recursively//@
-//@
-//@ Examples:
-//@
-//@ ```javascript
-//@ chmod(755, '/Users/brandon');
-//@ chmod('755', '/Users/brandon'); // same as above
-//@ chmod('u+x', '/Users/brandon');
-//@ ```
-//@
-//@ Alters the permissions of a file or directory by either specifying the
-//@ absolute permissions in octal form or expressing the changes in symbols.
-//@ This command tries to mimic the POSIX behavior as much as possible.
-//@ Notable exceptions:
+//@ ## Non-Unix commands
//@
-//@ + In symbolic modes, 'a-r' and '-r' are identical. No consideration is
-//@ given to the umask.
-//@ + There is no "quiet" option since default behavior is to run silent.
-function _chmod(options, mode, filePattern) {
- if (!filePattern) {
- if (options.length > 0 && options.charAt(0) === '-') {
- // Special case where the specified file permissions started with - to subtract perms, which
- // get picked up by the option parser as command flags.
- // If we are down by one argument and options starts with -, shift everything over.
- filePattern = mode;
- mode = options;
- options = '';
- }
- else {
- error('You must specify a file.');
- }
- }
-
- options = parseOptions(options, {
- 'R': 'recursive',
- 'c': 'changes',
- 'v': 'verbose'
- });
-
- if (typeof filePattern === 'string') {
- filePattern = [ filePattern ];
- }
-
- var files;
-
- if (options.recursive) {
- files = [];
- expand(filePattern).forEach(function addFile(expandedFile) {
- var stat = fs.lstatSync(expandedFile);
-
- if (!stat.isSymbolicLink()) {
- files.push(expandedFile);
-
- if (stat.isDirectory()) { // intentionally does not follow symlinks.
- fs.readdirSync(expandedFile).forEach(function (child) {
- addFile(expandedFile + '/' + child);
- });
- }
- }
- });
- }
- else {
- files = expand(filePattern);
- }
-
- files.forEach(function innerChmod(file) {
- file = path.resolve(file);
- if (!fs.existsSync(file)) {
- error('File not found: ' + file);
- }
- // When recursing, don't follow symlinks.
- if (options.recursive && fs.lstatSync(file).isSymbolicLink()) {
- return;
- }
+//@include ./src/tempdir
+var _tempDir = require('./src/tempdir');
+exports.tempdir = common.wrap('tempdir', _tempDir);
- var perms = fs.statSync(file).mode;
- var type = perms & PERMS.TYPE_MASK;
- var newPerms = perms;
+//@include ./src/error
+var _error = require('./src/error');
+exports.error = _error;
- if (isNaN(parseInt(mode, 8))) {
- // parse options
- mode.split(',').forEach(function (symbolicMode) {
- /*jshint regexdash:true */
- var pattern = /([ugoa]*)([=\+-])([rwxXst]*)/i;
- var matches = pattern.exec(symbolicMode);
-
- if (matches) {
- var applyTo = matches[1];
- var operator = matches[2];
- var change = matches[3];
-
- var changeOwner = applyTo.indexOf('u') != -1 || applyTo === 'a' || applyTo === '';
- var changeGroup = applyTo.indexOf('g') != -1 || applyTo === 'a' || applyTo === '';
- var changeOther = applyTo.indexOf('o') != -1 || applyTo === 'a' || applyTo === '';
-
- var changeRead = change.indexOf('r') != -1;
- var changeWrite = change.indexOf('w') != -1;
- var changeExec = change.indexOf('x') != -1;
- var changeSticky = change.indexOf('t') != -1;
- var changeSetuid = change.indexOf('s') != -1;
-
- var mask = 0;
- if (changeOwner) {
- mask |= (changeRead ? PERMS.OWNER_READ : 0) + (changeWrite ? PERMS.OWNER_WRITE : 0) + (changeExec ? PERMS.OWNER_EXEC : 0) + (changeSetuid ? PERMS.SETUID : 0);
- }
- if (changeGroup) {
- mask |= (changeRead ? PERMS.GROUP_READ : 0) + (changeWrite ? PERMS.GROUP_WRITE : 0) + (changeExec ? PERMS.GROUP_EXEC : 0) + (changeSetuid ? PERMS.SETGID : 0);
- }
- if (changeOther) {
- mask |= (changeRead ? PERMS.OTHER_READ : 0) + (changeWrite ? PERMS.OTHER_WRITE : 0) + (changeExec ? PERMS.OTHER_EXEC : 0);
- }
-
- // Sticky bit is special - it's not tied to user, group or other.
- if (changeSticky) {
- mask |= PERMS.STICKY;
- }
-
- switch (operator) {
- case '+':
- newPerms |= mask;
- break;
-
- case '-':
- newPerms &= ~mask;
- break;
-
- case '=':
- newPerms = type + mask;
-
- // According to POSIX, when using = to explicitly set the permissions, setuid and setgid can never be cleared.
- if (fs.statSync(file).isDirectory()) {
- newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
- }
- break;
- }
-
- if (options.verbose) {
- log(file + ' -> ' + newPerms.toString(8));
- }
-
- if (perms != newPerms) {
- if (!options.verbose && options.changes) {
- log(file + ' -> ' + newPerms.toString(8));
- }
- fs.chmodSync(file, newPerms);
- }
- }
- else {
- error('Invalid symbolic mode change: ' + symbolicMode);
- }
- });
- }
- else {
- // they gave us a full number
- newPerms = type + parseInt(mode, 8);
-
- // POSIX rules are that setuid and setgid can only be added using numeric form, but not cleared.
- if (fs.statSync(file).isDirectory()) {
- newPerms |= (PERMS.SETUID + PERMS.SETGID) & perms;
- }
-
- fs.chmodSync(file, newPerms);
- }
- });
-}
-exports.chmod = wrap('chmod', _chmod);
//@
//@ ## Configuration
//@
-
-
-exports.config = config;
+exports.config = common.config;
//@
//@ ### config.silent
//@ Example:
//@
//@ ```javascript
-//@ var silentState = config.silent; // save old silent state
-//@ config.silent = true;
+//@ var sh = require('shelljs');
+//@ var silentState = sh.config.silent; // save old silent state
+//@ sh.config.silent = true;
//@ /* ... */
-//@ config.silent = silentState; // restore old silent state
+//@ sh.config.silent = silentState; // restore old silent state
//@ ```
//@
//@ Suppresses all command output if `true`, except for `echo()` calls.
@@ -1365,537 +150,10 @@ exports.config = config;
//@ Example:
//@
//@ ```javascript
+//@ require('shelljs/global');
//@ config.fatal = true;
//@ cp('this_file_does_not_exist', '/dev/null'); // dies here
//@ /* more commands... */
//@ ```
//@
//@ If `true` the script will die on errors. Default is `false`.
-
-
-
-
-//@
-//@ ## Non-Unix commands
-//@
-
-
-
-
-
-
-//@
-//@ ### tempdir()
-//@ Searches and returns string containing a writeable, platform-dependent temporary directory.
-//@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).
-exports.tempdir = wrap('tempdir', tempDir);
-
-
-//@
-//@ ### error()
-//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
-//@ otherwise returns string explaining the error
-exports.error = function() {
- return state.error;
-};
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////////////////////
-//
-// Auxiliary functions (internal use only)
-//
-
-function log() {
- if (!config.silent)
- console.log.apply(this, arguments);
-}
-
-function deprecate(what, msg) {
- console.log('*** ShellJS.'+what+': This function is deprecated.', msg);
-}
-
-function write(msg) {
- if (!config.silent)
- process.stdout.write(msg);
-}
-
-// Shows error message. Throws unless _continue or config.fatal are true
-function error(msg, _continue) {
- if (state.error === null)
- state.error = '';
- state.error += state.currentCmd + ': ' + msg + '\n';
-
- log(state.error);
-
- if (config.fatal)
- process.exit(1);
-
- if (!_continue)
- throw '';
-}
-
-// Returns {'alice': true, 'bob': false} when passed:
-// parseOptions('-a', {'a':'alice', 'b':'bob'});
-function parseOptions(str, map) {
- if (!map)
- error('parseOptions() internal error: no map given');
-
- // All options are false by default
- var options = {};
- for (var letter in map)
- options[map[letter]] = false;
-
- if (!str)
- return options; // defaults
-
- if (typeof str !== 'string')
- error('parseOptions() internal error: wrong str');
-
- // e.g. match[1] = 'Rf' for str = '-Rf'
- var match = str.match(/^\-(.+)/);
- if (!match)
- return options;
-
- // e.g. chars = ['R', 'f']
- var chars = match[1].split('');
-
- chars.forEach(function(c) {
- if (c in map)
- options[map[c]] = true;
- else
- error('option not recognized: '+c);
- });
-
- return options;
-}
-
-// Common wrapper for all Unix-like commands
-function wrap(cmd, fn, options) {
- return function() {
- var retValue = null;
-
- state.currentCmd = cmd;
- state.error = null;
-
- try {
- var args = [].slice.call(arguments, 0);
-
- if (options && options.notUnix) {
- retValue = fn.apply(this, args);
- } else {
- if (args.length === 0 || typeof args[0] !== 'string' || args[0][0] !== '-')
- args.unshift(''); // only add dummy option if '-option' not already present
- retValue = fn.apply(this, args);
- }
- } catch (e) {
- if (!state.error) {
- // If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
- console.log('shell.js: internal error');
- console.log(e.stack || e);
- process.exit(1);
- }
- if (config.fatal)
- throw e;
- }
-
- state.currentCmd = 'shell.js';
- return retValue;
- };
-} // wrap
-
-// Buffered file copy, synchronous
-// (Using readFileSync() + writeFileSync() could easily cause a memory overflow
-// with large files)
-function copyFileSync(srcFile, destFile) {
- if (!fs.existsSync(srcFile))
- error('copyFileSync: no such file or directory: ' + srcFile);
-
- var BUF_LENGTH = 64*1024,
- buf = new Buffer(BUF_LENGTH),
- bytesRead = BUF_LENGTH,
- pos = 0,
- fdr = null,
- fdw = null;
-
- try {
- fdr = fs.openSync(srcFile, 'r');
- } catch(e) {
- error('copyFileSync: could not read src file ('+srcFile+')');
- }
-
- try {
- fdw = fs.openSync(destFile, 'w');
- } catch(e) {
- error('copyFileSync: could not write to dest file (code='+e.code+'):'+destFile);
- }
-
- while (bytesRead === BUF_LENGTH) {
- bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
- fs.writeSync(fdw, buf, 0, bytesRead);
- pos += bytesRead;
- }
-
- fs.closeSync(fdr);
- fs.closeSync(fdw);
-}
-
-// Recursively copies 'sourceDir' into 'destDir'
-// Adapted from https://github.com/ryanmcgrath/wrench-js
-//
-// Copyright (c) 2010 Ryan McGrath
-// Copyright (c) 2012 Artur Adib
-//
-// Licensed under the MIT License
-// http://www.opensource.org/licenses/mit-license.php
-function cpdirSyncRecursive(sourceDir, destDir, opts) {
- if (!opts) opts = {};
-
- /* Create the directory where all our junk is moving to; read the mode of the source directory and mirror it */
- var checkDir = fs.statSync(sourceDir);
- try {
- fs.mkdirSync(destDir, checkDir.mode);
- } catch (e) {
- //if the directory already exists, that's okay
- if (e.code !== 'EEXIST') throw e;
- }
-
- var files = fs.readdirSync(sourceDir);
-
- for(var i = 0; i < files.length; i++) {
- var currFile = fs.lstatSync(sourceDir + "/" + files[i]);
-
- if (currFile.isDirectory()) {
- /* recursion this thing right on back. */
- cpdirSyncRecursive(sourceDir + "/" + files[i], destDir + "/" + files[i], opts);
- } else if (currFile.isSymbolicLink()) {
- var symlinkFull = fs.readlinkSync(sourceDir + "/" + files[i]);
- fs.symlinkSync(symlinkFull, destDir + "/" + files[i]);
- } else {
- /* At this point, we've hit a file actually worth copying... so copy it on over. */
- if (fs.existsSync(destDir + "/" + files[i]) && !opts.force) {
- log('skipping existing file: ' + files[i]);
- } else {
- copyFileSync(sourceDir + "/" + files[i], destDir + "/" + files[i]);
- }
- }
-
- } // for files
-} // cpdirSyncRecursive
-
-// Recursively removes 'dir'
-// Adapted from https://github.com/ryanmcgrath/wrench-js
-//
-// Copyright (c) 2010 Ryan McGrath
-// Copyright (c) 2012 Artur Adib
-//
-// Licensed under the MIT License
-// http://www.opensource.org/licenses/mit-license.php
-function rmdirSyncRecursive(dir, force) {
- var files;
-
- files = fs.readdirSync(dir);
-
- // Loop through and delete everything in the sub-tree after checking it
- for(var i = 0; i < files.length; i++) {
- var file = dir + "/" + files[i],
- currFile = fs.lstatSync(file);
-
- if(currFile.isDirectory()) { // Recursive function back to the beginning
- rmdirSyncRecursive(file, force);
- }
-
- else if(currFile.isSymbolicLink()) { // Unlink symlinks
- if (force || isWriteable(file)) {
- try {
- _unlinkSync(file);
- } catch (e) {
- error('could not remove file (code '+e.code+'): ' + file, true);
- }
- }
- }
-
- else // Assume it's a file - perhaps a try/catch belongs here?
- if (force || isWriteable(file)) {
- try {
- _unlinkSync(file);
- } catch (e) {
- error('could not remove file (code '+e.code+'): ' + file, true);
- }
- }
- }
-
- // Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
- // Huzzah for the shopkeep.
-
- var result;
- try {
- result = fs.rmdirSync(dir);
- } catch(e) {
- error('could not remove directory (code '+e.code+'): ' + dir, true);
- }
-
- return result;
-} // rmdirSyncRecursive
-
-// Recursively creates 'dir'
-function mkdirSyncRecursive(dir) {
- var baseDir = path.dirname(dir);
-
- // Base dir exists, no recursion necessary
- if (fs.existsSync(baseDir)) {
- fs.mkdirSync(dir, parseInt('0777', 8));
- return;
- }
-
- // Base dir does not exist, go recursive
- mkdirSyncRecursive(baseDir);
-
- // Base dir created, can create dir
- fs.mkdirSync(dir, parseInt('0777', 8));
-}
-
-// e.g. 'shelljs_a5f185d0443ca...'
-function randomFileName() {
- function randomHash(count) {
- if (count === 1)
- return parseInt(16*Math.random(), 10).toString(16);
- else {
- var hash = '';
- for (var i=0; i<count; i++)
- hash += randomHash(1);
- return hash;
- }
- }
-
- return 'shelljs_'+randomHash(20);
-}
-
-// Returns false if 'dir' is not a writeable directory, 'dir' otherwise
-function writeableDir(dir) {
- if (!dir || !fs.existsSync(dir))
- return false;
-
- if (!fs.statSync(dir).isDirectory())
- return false;
-
- var testFile = dir+'/'+randomFileName();
- try {
- fs.writeFileSync(testFile, ' ');
- _unlinkSync(testFile);
- return dir;
- } catch (e) {
- return false;
- }
-}
-
-// Cross-platform method for getting an available temporary directory.
-// Follows the algorithm of Python's tempfile.tempdir
-// http://docs.python.org/library/tempfile.html#tempfile.tempdir
-function tempDir() {
- if (state.tempDir)
- return state.tempDir; // from cache
-
- state.tempDir = writeableDir(process.env['TMPDIR']) ||
- writeableDir(process.env['TEMP']) ||
- writeableDir(process.env['TMP']) ||
- writeableDir(process.env['Wimp$ScrapDir']) || // RiscOS
- writeableDir('C:\\TEMP') || // Windows
- writeableDir('C:\\TMP') || // Windows
- writeableDir('\\TEMP') || // Windows
- writeableDir('\\TMP') || // Windows
- writeableDir('/tmp') ||
- writeableDir('/var/tmp') ||
- writeableDir('/usr/tmp') ||
- writeableDir('.'); // last resort
-
- return state.tempDir;
-}
-
-// Wrapper around exec() to enable echoing output to console in real time
-function execAsync(cmd, opts, callback) {
- var output = '';
-
- var options = extend({
- silent: config.silent
- }, opts);
-
- var c = child.exec(cmd, {env: process.env, maxBuffer: 20*1024*1024}, function(err) {
- if (callback)
- callback(err ? err.code : 0, output);
- });
-
- c.stdout.on('data', function(data) {
- output += data;
- if (!options.silent)
- process.stdout.write(data);
- });
-
- c.stderr.on('data', function(data) {
- output += data;
- if (!options.silent)
- process.stdout.write(data);
- });
-
- return c;
-}
-
-// Hack to run child_process.exec() synchronously (sync avoids callback hell)
-// Uses a custom wait loop that checks for a flag file, created when the child process is done.
-// (Can't do a wait loop that checks for internal Node variables/messages as
-// Node is single-threaded; callbacks and other internal state changes are done in the
-// event loop).
-function execSync(cmd, opts) {
- var stdoutFile = path.resolve(tempDir()+'/'+randomFileName()),
- codeFile = path.resolve(tempDir()+'/'+randomFileName()),
- scriptFile = path.resolve(tempDir()+'/'+randomFileName()),
- sleepFile = path.resolve(tempDir()+'/'+randomFileName());
-
- var options = extend({
- silent: config.silent
- }, opts);
-
- var previousStdoutContent = '';
- // Echoes stdout changes from running process, if not silent
- function updateStdout() {
- if (options.silent || !fs.existsSync(stdoutFile))
- return;
-
- var stdoutContent = fs.readFileSync(stdoutFile, 'utf8');
- // No changes since last time?
- if (stdoutContent.length <= previousStdoutContent.length)
- return;
-
- process.stdout.write(stdoutContent.substr(previousStdoutContent.length));
- previousStdoutContent = stdoutContent;
- }
-
- function escape(str) {
- return (str+'').replace(/([\\"'])/g, "\\$1").replace(/\0/g, "\\0");
- }
-
- cmd += ' > '+stdoutFile+' 2>&1'; // works on both win/unix
-
- var script =
- "var child = require('child_process')," +
- " fs = require('fs');" +
- "child.exec('"+escape(cmd)+"', {env: process.env, maxBuffer: 20*1024*1024}, function(err) {" +
- " fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0');" +
- "});";
-
- if (fs.existsSync(scriptFile)) _unlinkSync(scriptFile);
- if (fs.existsSync(stdoutFile)) _unlinkSync(stdoutFile);
- if (fs.existsSync(codeFile)) _unlinkSync(codeFile);
-
- fs.writeFileSync(scriptFile, script);
- child.exec('"'+process.execPath+'" '+scriptFile, {
- env: process.env,
- cwd: exports.pwd(),
- maxBuffer: 20*1024*1024
- });
-
- // The wait loop
- // sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
- // (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
- // CPU usage, though apparently not so much on Windows)
- while (!fs.existsSync(codeFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
- while (!fs.existsSync(stdoutFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); }
-
- // At this point codeFile exists, but it's not necessarily flushed yet.
- // Keep reading it until it is.
- var code = parseInt('', 10);
- while (isNaN(code)) {
- code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10);
- }
-
- var stdout = fs.readFileSync(stdoutFile, 'utf8');
-
- // No biggie if we can't erase the files now -- they're in a temp dir anyway
- try { _unlinkSync(scriptFile); } catch(e) {}
- try { _unlinkSync(stdoutFile); } catch(e) {}
- try { _unlinkSync(codeFile); } catch(e) {}
- try { _unlinkSync(sleepFile); } catch(e) {}
-
- // True if successful, false if not
- var obj = {
- code: code,
- output: stdout
- };
- return obj;
-} // execSync()
-
-// Expands wildcards with matching file names. For a given array of file names 'list', returns
-// another array containing all file names as per ls(list[i]).
-// For example:
-// expand(['file*.js']) = ['file1.js', 'file2.js', ...]
-// (if the files 'file1.js', 'file2.js', etc, exist in the current dir)
-function expand(list) {
- var expanded = [];
- list.forEach(function(listEl) {
- // Wildcard present?
- if (listEl.search(/\*/) > -1) {
- _ls('', listEl).forEach(function(file) {
- expanded.push(file);
- });
- } else {
- expanded.push(listEl);
- }
- });
- return expanded;
-}
-
-// Cross-platform method for splitting environment PATH variables
-function splitPath(p) {
- if (!p)
- return [];
-
- if (platform === 'win')
- return p.split(';');
- else
- return p.split(':');
-}
-
-// extend(target_obj, source_obj1 [, source_obj2 ...])
-// Shallow extend, e.g.:
-// extend({A:1}, {b:2}, {c:3}) returns {A:1, b:2, c:3}
-function extend(target) {
- var sources = [].slice.call(arguments, 1);
- sources.forEach(function(source) {
- for (var key in source)
- target[key] = source[key];
- });
-
- return target;
-}
-
-// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e.
-// file can be unlinked even if it's read-only, see joyent/node#3006
-function _unlinkSync(file) {
- try {
- fs.unlinkSync(file);
- } catch(e) {
- // Try to override file permission
- if (e.code === 'EPERM') {
- fs.chmodSync(file, '0666');
- fs.unlinkSync(file);
- } else {
- throw e;
- }
- }
-}
-
-// Hack to determine if file has write permissions for current user
-// Avoids having to check user, group, etc, but it's probably slow
-function isWriteable(file) {
- var writePermission = true;
- try {
- var __fd = fs.openSync(file, 'a');
- fs.closeSync(__fd);
- } catch(e) {
- writePermission = false;
- }
-
- return writePermission;
-}
diff --git a/StoneIsland/platforms/ios/cordova/run b/StoneIsland/platforms/ios/cordova/run
index d2c376d5..470384b5 100755
--- a/StoneIsland/platforms/ios/cordova/run
+++ b/StoneIsland/platforms/ios/cordova/run
@@ -19,18 +19,45 @@
under the License.
*/
-var args = process.argv,
- run = require('./lib/run');
+
+var args = process.argv;
+var Api = require('./Api');
+var nopt = require('nopt');
// Handle help flag
-if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(args[2]) > -1) {
- run.help();
-} else {
- run.run(args).done(function() {
+if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+ require('./lib/run').help();
+ process.exit(0);
+}
+
+// Parse arguments (includes build params as well)
+var opts = nopt({
+ 'verbose' : Boolean,
+ 'silent' : Boolean,
+ 'debug': Boolean,
+ 'release': Boolean,
+ 'nobuild': Boolean,
+ 'archs': String,
+ 'list': Boolean,
+ 'device': Boolean,
+ 'emulator': Boolean,
+ 'target' : String,
+ 'codeSignIdentity': String,
+ 'codeSignResourceRules': String,
+ 'provisioningProfile': String,
+ 'buildConfig' : String,
+ 'noSign' : Boolean
+}, { 'd' : '--verbose' }, args);
+
+// Make options compatible with PlatformApi build method spec
+opts.argv = opts.argv.remain;
+
+require('./loggingHelper').adjustLoggerLevel(opts);
+
+new Api().run(opts).done(function() {
console.log('** RUN SUCCEEDED **');
}, function (err) {
var errorMessage = (err && err.stack) ? err.stack : err;
console.error(errorMessage);
process.exit(2);
});
-} \ No newline at end of file
diff --git a/StoneIsland/platforms/ios/cordova/run.bat b/StoneIsland/platforms/ios/cordova/run.bat
index 0d10321a..8a3cad2a 100755
--- a/StoneIsland/platforms/ios/cordova/run.bat
+++ b/StoneIsland/platforms/ios/cordova/run.bat
@@ -14,12 +14,6 @@
:: KIND, either express or implied. See the License for the
:: specific language governing permissions and limitations
:: under the License
+
@ECHO OFF
-SET script_path="%~dp0run"
-IF EXIST %script_path% (
- node %script_path% %*
-) ELSE (
- ECHO.
- ECHO ERROR: Could not find 'run' script in 'cordova' folder, aborting...>&2
- EXIT /B 1
-)
+ECHO WARN: The `run` is not available for cordova-ios on windows machines.>&2
diff --git a/StoneIsland/platforms/ios/cordova/version b/StoneIsland/platforms/ios/cordova/version
index 542a2173..99ce9729 100755
--- a/StoneIsland/platforms/ios/cordova/version
+++ b/StoneIsland/platforms/ios/cordova/version
@@ -25,6 +25,11 @@
Note: it does not work if the --shared option was used to create the project.
*/
-var VERSION="3.9.2"
+// Coho updates this line
+var VERSION="4.3.0";
-console.log(VERSION);
+module.exports.version = VERSION;
+
+if (!module.parent) {
+ console.log(VERSION);
+}