diff options
Diffstat (limited to 'cordova/lib')
| -rwxr-xr-x | cordova/lib/Podfile.js | 245 | ||||
| -rwxr-xr-x | cordova/lib/PodsJson.js | 115 | ||||
| -rwxr-xr-x | cordova/lib/build.js | 412 | ||||
| -rwxr-xr-x | cordova/lib/check_reqs.js | 228 | ||||
| -rwxr-xr-x | cordova/lib/clean.js | 42 | ||||
| -rwxr-xr-x | cordova/lib/copy-www-build-step.js | 73 | ||||
| -rwxr-xr-x | cordova/lib/list-devices | 67 | ||||
| -rwxr-xr-x | cordova/lib/list-emulator-build-targets | 107 | ||||
| -rwxr-xr-x | cordova/lib/list-emulator-images | 47 | ||||
| -rwxr-xr-x | cordova/lib/list-started-emulators | 50 | ||||
| -rwxr-xr-x | cordova/lib/plugman/pluginHandlers.js | 400 | ||||
| -rwxr-xr-x | cordova/lib/prepare.js | 1153 | ||||
| -rwxr-xr-x | cordova/lib/projectFile.js | 134 | ||||
| -rwxr-xr-x | cordova/lib/run.js | 244 | ||||
| -rwxr-xr-x | cordova/lib/spawn.js | 47 | ||||
| -rwxr-xr-x | cordova/lib/start-emulator | 30 | ||||
| -rwxr-xr-x | cordova/lib/versions.js | 194 |
17 files changed, 0 insertions, 3588 deletions
diff --git a/cordova/lib/Podfile.js b/cordova/lib/Podfile.js deleted file mode 100755 index 49173c4..0000000 --- a/cordova/lib/Podfile.js +++ /dev/null @@ -1,245 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var events = require('cordova-common').events; -var Q = require('q'); -var superspawn = require('cordova-common').superspawn; -var CordovaError = require('cordova-common').CordovaError; - -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 \'([^\']*)\'\\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, ''); /* eslint no-useless-escape : 0 */ - obj[m[1]] = podSpec; // i.e pod 'Foo', '1.2' ==> { 'Foo' : '1.2'} - } - - return obj; - }, {}); -}; - -Podfile.prototype.escapeSingleQuotes = function (string) { - return string.replace('\'', '\\\''); -}; - -Podfile.prototype.getTemplate = function () { - // Escaping possible ' in the project name - var projectName = this.escapeSingleQuotes(this.projectName); - 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', - projectName, projectName, this.podToken); -}; - -Podfile.prototype.addSpec = function (name, spec) { - name = name || ''; - // optional - spec = spec; /* eslint no-self-assign : 0 */ - - 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 (toolOptions) { - toolOptions = toolOptions || {}; - - // 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(toolOptions); -}; - -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 (toolOptions) { - return self.before_install(toolOptions); - }) - .then(function (toolOptions) { - if (toolOptions.ignore) { - events.emit('verbose', '==== pod install start ====\n'); - events.emit('verbose', toolOptions.ignoreMessage); - return Q.resolve(); - } else { - 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; diff --git a/cordova/lib/PodsJson.js b/cordova/lib/PodsJson.js deleted file mode 100755 index 0470527..0000000 --- a/cordova/lib/PodsJson.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var events = require('cordova-common').events; -var 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/cordova/lib/build.js b/cordova/lib/build.js deleted file mode 100755 index b68262e..0000000 --- a/cordova/lib/build.js +++ /dev/null @@ -1,412 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -var Q = require('q'); -var path = require('path'); -var shell = require('shelljs'); -var spawn = require('./spawn'); -var fs = require('fs'); -var plist = require('plist'); -var util = require('util'); - -var check_reqs = require('./check_reqs'); -var projectFile = require('./projectFile'); - -var events = require('cordova-common').events; - -var projectPath = path.join(__dirname, '..', '..'); -var projectName = null; - -// These are regular expressions to detect if the user is changing any of the built-in xcodebuildArgs -/* eslint-disable no-useless-escape */ -var buildFlagMatchers = { - 'xcconfig': /^\-xcconfig\s*(.*)$/, - 'workspace': /^\-workspace\s*(.*)/, - 'scheme': /^\-scheme\s*(.*)/, - 'configuration': /^\-configuration\s*(.*)/, - 'sdk': /^\-sdk\s*(.*)/, - 'destination': /^\-destination\s*(.*)/, - 'archivePath': /^\-archivePath\s*(.*)/, - 'configuration_build_dir': /^(CONFIGURATION_BUILD_DIR=.*)/, - 'shared_precomps_dir': /^(SHARED_PRECOMPS_DIR=.*)/ -}; -/* eslint-enable no-useless-escape */ - -/** - * Returns a promise that resolves to the default simulator target; the logic here - * matches what `cordova emulate ios` does. - * - * The return object has two properties: `name` (the Xcode destination name), - * `identifier` (the simctl identifier), and `simIdentifier` (essentially the cordova emulate target) - * - * @return {Promise} - */ -function getDefaultSimulatorTarget () { - return require('./list-emulator-build-targets').run() - .then(function (emulators) { - var targetEmulator; - if (emulators.length > 0) { - targetEmulator = emulators[0]; - } - emulators.forEach(function (emulator) { - if (emulator.name.indexOf('iPhone') === 0) { - targetEmulator = emulator; - } - }); - return targetEmulator; - }); -} - -module.exports.run = function (buildOpts) { - var emulatorTarget = ''; - - buildOpts = buildOpts || {}; - - if (buildOpts.debug && buildOpts.release) { - return Q.reject('Cannot specify "debug" and "release" options together.'); - } - - if (buildOpts.device && buildOpts.emulator) { - return Q.reject('Cannot specify "device" and "emulator" options together.'); - } - - if (buildOpts.buildConfig) { - if (!fs.existsSync(buildOpts.buildConfig)) { - return Q.reject('Build config file does not exist:' + buildOpts.buildConfig); - } - 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 = buildOpts.release ? 'release' : 'debug'; - var config = buildConfig.ios[buildType]; - if (config) { - ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType', 'buildFlag', 'iCloudContainerEnvironment', 'automaticProvisioning'].forEach( - function (key) { - buildOpts[key] = buildOpts[key] || config[key]; - }); - } - } - } - - return require('./list-devices').run() - .then(function (devices) { - if (devices.length > 0 && !(buildOpts.emulator)) { - // we also explicitly set device flag in options as we pass - // those parameters to other api (build as an example) - buildOpts.device = true; - return check_reqs.check_ios_deploy(); - } - }).then(function () { - // CB-12287: Determine the device we should target when building for a simulator - if (!buildOpts.device) { - var newTarget = buildOpts.target || ''; - - if (newTarget) { - // only grab the device name, not the runtime specifier - newTarget = newTarget.split(',')[0]; - } - // a target was given to us, find the matching Xcode destination name - var promise = require('./list-emulator-build-targets').targetForSimIdentifier(newTarget); - return promise.then(function (theTarget) { - if (!theTarget) { - return getDefaultSimulatorTarget().then(function (defaultTarget) { - emulatorTarget = defaultTarget.name; - events.emit('log', 'Building for ' + emulatorTarget + ' Simulator'); - return emulatorTarget; - }); - } else { - emulatorTarget = theTarget.name; - events.emit('log', 'Building for ' + emulatorTarget + ' Simulator'); - return emulatorTarget; - } - }); - } - }).then(function () { - return check_reqs.run(); - }).then(function () { - return findXCodeProjectIn(projectPath); - }).then(function (name) { - projectName = name; - var extraConfig = ''; - if (buildOpts.codeSignIdentity) { - extraConfig += 'CODE_SIGN_IDENTITY = ' + buildOpts.codeSignIdentity + '\n'; - extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + buildOpts.codeSignIdentity + '\n'; - } - if (buildOpts.codeSignResourceRules) { - extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + buildOpts.codeSignResourceRules + '\n'; - } - 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 = 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', (buildOpts.device ? 'device' : 'emulator')); - - // remove the build/device folder before building - return spawn('rm', [ '-rf', buildOutputDir ], projectPath) - .then(function () { - var xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag, emulatorTarget); - return spawn('xcodebuild', xcodebuildArgs, projectPath); - }); - - }).then(function () { - if (!buildOpts.device || buildOpts.noSign) { - return; - } - - var locations = { - root: projectPath, - pbxproj: path.join(projectPath, projectName + '.xcodeproj', 'project.pbxproj') - }; - - var bundleIdentifier = projectFile.parse(locations).getPackageName(); - var exportOptions = {'compileBitcode': false, 'method': 'development'}; - - if (buildOpts.packageType) { - exportOptions.method = buildOpts.packageType; - } - - if (buildOpts.iCloudContainerEnvironment) { - exportOptions.iCloudContainerEnvironment = buildOpts.iCloudContainerEnvironment; - } - - if (buildOpts.developmentTeam) { - exportOptions.teamID = buildOpts.developmentTeam; - } - - if (buildOpts.provisioningProfile && bundleIdentifier) { - exportOptions.provisioningProfiles = { [ bundleIdentifier ]: String(buildOpts.provisioningProfile) }; - exportOptions.signingStyle = 'manual'; - } - - if (buildOpts.codeSignIdentity) { - exportOptions.signingCertificate = buildOpts.codeSignIdentity; - } - - var exportOptionsPlist = plist.build(exportOptions); - var exportOptionsPath = path.join(projectPath, 'exportOptions.plist'); - - var buildOutputDir = path.join(projectPath, 'build', 'device'); - - 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, buildOpts.automaticProvisioning); - return spawn('xcodebuild', xcodearchiveArgs, projectPath); - } - - return Q.nfcall(fs.writeFile, exportOptionsPath, exportOptionsPlist, 'utf-8') - .then(checkSystemRuby) - .then(packageArchive); - }); -}; - -/** - * Searches for first XCode project in specified folder - * @param {String} projectPath Path where to search project - * @return {Promise} Promise either fulfilled with project name or rejected - */ -function findXCodeProjectIn (projectPath) { - // 'Searching for Xcode project in ' + 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) { - events.emit('warn', 'Found multiple .xcodeproj directories in \n' + - projectPath + '\nUsing first one'); - } - - var projectName = path.basename(xcodeProjFiles[0], '.xcodeproj'); - return Q.resolve(projectName); -} - -module.exports.findXCodeProjectIn = findXCodeProjectIn; - -/** - * 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} configuration Configuration name: debug|release - * @param {Boolean} isDevice Flag that specify target for package (device/emulator) - * @param {Array} buildFlags - * @param {String} emulatorTarget Target for emulator (rather than default) - * @return {Array} Array of arguments that could be passed directly to spawn method - */ -function getXcodeBuildArgs (projectName, projectPath, configuration, isDevice, buildFlags, emulatorTarget) { - var xcodebuildArgs; - var options; - var buildActions; - var settings; - var customArgs = {}; - 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) { - 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 - 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=' + emulatorTarget - ]; - 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 - * @param {Boolean} autoProvisioning Whether to allow Xcode to automatically update provisioning - * @return {Array} Array of arguments that could be passed directly to spawn method - */ -function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath, autoProvisioning) { - return [ - '-exportArchive', - '-archivePath', projectName + '.xcarchive', - '-exportOptionsPlist', exportOptionsPath, - '-exportPath', outputPath - ].concat(autoProvisioning ? ['-allowProvisioningUpdates'] : []); -} - -function parseBuildFlag (buildFlag, args) { - var matched; - for (var key in buildFlagMatchers) { - var found = buildFlag.match(buildFlagMatchers[key]); - 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. - /* eslint-disable no-useless-escape */ - 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(''); - console.log('Usage: build [--debug | --release] [--archs=\"<list of architectures...>\"]'); - console.log(' [--device | --simulator] [--codeSignIdentity=\"<identity>\"]'); - console.log(' [--codeSignResourceRules=\"<resourcerules path>\"]'); - console.log(' [--developmentTeam=\"<Team ID>\"]'); - console.log(' [--provisioningProfile=\"<provisioning profile>\"]'); - console.log(' --help : Displays this dialog.'); - console.log(' --debug : Builds project in debug mode. (Default)'); - console.log(' --release : Builds project in release mode.'); - console.log(' -r : Shortcut :: builds project in release mode.'); - /* eslint-enable no-useless-escape */ - // TODO: add support for building different archs - // console.log(" --archs : Builds project binaries for specific chip architectures (`anycpu`, `arm`, `x86`, `x64`)."); - console.log(' --device, --simulator'); - console.log(' : Specifies, what type of project to build'); - console.log(' --codeSignIdentity : Type of signing identity used for code signing.'); - console.log(' --codeSignResourceRules : Path to ResourceRules.plist.'); - console.log(' --developmentTeam : New for Xcode 8. The development team (Team ID)'); - console.log(' to use for code signing.'); - console.log(' --provisioningProfile : UUID of the profile.'); - console.log(' --device --noSign : Builds project without application signing.'); - console.log(''); - console.log('examples:'); - console.log(' build '); - console.log(' build --debug'); - console.log(' build --release'); - console.log(' build --codeSignIdentity="iPhone Distribution" --provisioningProfile="926c2bd6-8de9-4c2f-8407-1016d2d12954"'); - // TODO: add support for building different archs - // console.log(" build --release --archs=\"armv7\""); - console.log(''); - process.exit(0); -}; diff --git a/cordova/lib/check_reqs.js b/cordova/lib/check_reqs.js deleted file mode 100755 index 21a2208..0000000 --- a/cordova/lib/check_reqs.js +++ /dev/null @@ -1,228 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -'use strict'; - -const Q = require('q'); -const shell = require('shelljs'); -const util = require('util'); -const versions = require('./versions'); - -const SUPPORTED_OS_PLATFORMS = [ 'darwin' ]; - -const XCODEBUILD_MIN_VERSION = '7.0.0'; -const XCODEBUILD_NOT_FOUND_MESSAGE = - 'Please install version ' + XCODEBUILD_MIN_VERSION + ' or greater from App Store'; - -const IOS_DEPLOY_MIN_VERSION = '1.9.2'; -const IOS_DEPLOY_NOT_FOUND_MESSAGE = - 'Please download, build and install version ' + IOS_DEPLOY_MIN_VERSION + ' or greater' + - ' from https://github.com/phonegap/ios-deploy into your path, or do \'npm install -g ios-deploy\''; - -const COCOAPODS_MIN_VERSION = '1.0.1'; -const COCOAPODS_NOT_FOUND_MESSAGE = - 'Please install version ' + COCOAPODS_MIN_VERSION + ' or greater from https://cocoapods.org/'; -const COCOAPODS_NOT_SYNCED_MESSAGE = - 'The CocoaPods repo has not been synced yet, this will take a long time (approximately 500MB as of Sept 2016). Please run `pod setup` first to sync the repo.'; -const COCOAPODS_SYNCED_MIN_SIZE = 475; // in megabytes -const COCOAPODS_SYNC_ERROR_MESSAGE = - 'The CocoaPods repo has been created, but there appears to be a sync error. The repo size should be at least ' + COCOAPODS_SYNCED_MIN_SIZE + '. Please run `pod setup --verbose` to sync the repo.'; -const COCOAPODS_REPO_NOT_FOUND_MESSAGE = 'The CocoaPods repo at ~/.cocoapods was not found.'; - -/** - * Checks if xcode util is available - * @return {Promise} Returns a promise either resolved with xcode version or rejected - */ -module.exports.run = module.exports.check_xcodebuild = function () { - return checkTool('xcodebuild', XCODEBUILD_MIN_VERSION, XCODEBUILD_NOT_FOUND_MESSAGE); -}; - -/** - * Checks if ios-deploy util is available - * @return {Promise} Returns a promise either resolved with ios-deploy version or rejected - */ -module.exports.check_ios_deploy = function () { - return checkTool('ios-deploy', IOS_DEPLOY_MIN_VERSION, IOS_DEPLOY_NOT_FOUND_MESSAGE); -}; - -module.exports.check_os = function () { - // Build iOS apps available for OSX platform only, so we reject on others platforms - return os_platform_is_supported() ? - Q.resolve(process.platform) : - Q.reject('Cordova tooling for iOS requires Apple macOS'); -}; - -function os_platform_is_supported () { - return (SUPPORTED_OS_PLATFORMS.indexOf(process.platform) !== -1); -} - -function check_cocoapod_tool (toolChecker) { - toolChecker = toolChecker || checkTool; - if (os_platform_is_supported()) { // CB-12856 - return toolChecker('pod', COCOAPODS_MIN_VERSION, COCOAPODS_NOT_FOUND_MESSAGE, 'CocoaPods'); - } else { - return Q.resolve({ - 'ignore': true, - 'ignoreMessage': `CocoaPods check and installation ignored on ${process.platform}` - }); - } -} - -/** - * Checks if cocoapods repo size is what is expected - * @return {Promise} Returns a promise either resolved or rejected - */ -module.exports.check_cocoapods_repo_size = function () { - return check_cocoapod_tool() - .then(function (toolOptions) { - // check size of ~/.cocoapods repo - let commandString = util.format('du -sh %s/.cocoapods', process.env.HOME); - let command = shell.exec(commandString, { silent: true }); - // command.output is e.g "750M path/to/.cocoapods", we just scan the number - let size = toolOptions.ignore ? 0 : parseFloat(command.output); - - if (toolOptions.ignore || command.code === 0) { // success, parse output - return Q.resolve(size, toolOptions); - } else { // error, perhaps not found - return Q.reject(util.format('%s (%s)', COCOAPODS_REPO_NOT_FOUND_MESSAGE, command.output)); - } - }) - .then(function (repoSize, toolOptions) { - if (toolOptions.ignore || COCOAPODS_SYNCED_MIN_SIZE <= repoSize) { // success, expected size - return Q.resolve(toolOptions); - } else { - return Q.reject(COCOAPODS_SYNC_ERROR_MESSAGE); - } - }); -}; - -/** - * Checks if cocoapods is available, and whether the repo is synced (because it takes a long time to download) - * @return {Promise} Returns a promise either resolved or rejected - */ -module.exports.check_cocoapods = function (toolChecker) { - return check_cocoapod_tool(toolChecker) - // check whether the cocoapods repo has been synced through `pod repo` command - // a value of '0 repos' means it hasn't been synced - .then(function (toolOptions) { - let code = shell.exec('pod repo | grep -e "^0 repos"', { silent: true }).code; - let repoIsSynced = (code !== 0); - - if (toolOptions.ignore || repoIsSynced) { - // return check_cocoapods_repo_size(); - // we could check the repo size above, but it takes too long. - return Q.resolve(toolOptions); - } else { - return Q.reject(COCOAPODS_NOT_SYNCED_MESSAGE); - } - }); -}; - -/** - * Checks if specific tool is available. - * @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, toolFriendlyName) { - toolFriendlyName = toolFriendlyName || tool; - - // Check whether tool command is available at all - let tool_command = shell.which(tool); - if (!tool_command) { - 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': version }) : - Q.reject('Cordova needs ' + toolFriendlyName + ' version ' + minVersion + - ' or greater, you have version ' + version + '. ' + (message || '')); - }); -} - -/** - * Object that represents one of requirements for current platform. - * @param {String} id The unique identifier for this requirements. - * @param {String} name The name of requirements. Human-readable field. - * @param {Boolean} isFatal Marks the requirement as fatal. If such requirement will fail - * next requirements' checks will be skipped. - */ -let Requirement = function (id, name, isFatal) { - this.id = id; - this.name = name; - this.installed = false; - this.metadata = {}; - this.isFatal = isFatal || false; -}; - -/** - * Methods that runs all checks one by one and returns a result of checks - * as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method - * - * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled. - */ -module.exports.check_all = function () { - - const requirements = [ - new Requirement('os', 'Apple macOS', true), - new Requirement('xcode', 'Xcode'), - new Requirement('ios-deploy', 'ios-deploy'), - new Requirement('CocoaPods', 'CocoaPods') - ]; - - let result = []; - let fatalIsHit = false; - - let checkFns = [ - module.exports.check_os, - module.exports.check_xcodebuild, - module.exports.check_ios_deploy, - module.exports.check_cocoapods - ]; - - // Then execute requirement checks one-by-one - return checkFns.reduce(function (promise, checkFn, idx) { - return promise.then(function () { - // If fatal requirement is failed, - // we don't need to check others - if (fatalIsHit) return Q(); - - let requirement = requirements[idx]; - return checkFn() - .then(function (version) { - requirement.installed = true; - requirement.metadata.version = version; - result.push(requirement); - }, function (err) { - if (requirement.isFatal) fatalIsHit = true; - requirement.metadata.reason = err; - result.push(requirement); - }); - }); - }, Q()) - .then(function () { - // When chain is completed, return requirements array to upstream API - return result; - }); -}; diff --git a/cordova/lib/clean.js b/cordova/lib/clean.js deleted file mode 100755 index 20e8ac6..0000000 --- a/cordova/lib/clean.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -var Q = require('q'); -var path = require('path'); -var shell = require('shelljs'); -var spawn = require('./spawn'); - -var projectPath = path.join(__dirname, '..', '..'); - -module.exports.run = function () { - var projectName = shell.ls(projectPath).filter(function (name) { - return path.extname(name) === '.xcodeproj'; - })[0]; - - if (!projectName) { - return Q.reject('No Xcode project found in ' + projectPath); - } - - return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Debug', '-alltargets', 'clean'], projectPath) - .then(function () { - return spawn('xcodebuild', ['-project', projectName, '-configuration', 'Release', '-alltargets', 'clean'], projectPath); - }).then(function () { - return shell.rm('-rf', path.join(projectPath, 'build')); - }); -}; diff --git a/cordova/lib/copy-www-build-step.js b/cordova/lib/copy-www-build-step.js deleted file mode 100755 index e05aacf..0000000 --- a/cordova/lib/copy-www-build-step.js +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -// This script copies the www directory into the Xcode project. - -// This script should not be called directly. -// It is called as a build step from Xcode. - -var BUILT_PRODUCTS_DIR = process.env.BUILT_PRODUCTS_DIR; -var FULL_PRODUCT_NAME = process.env.FULL_PRODUCT_NAME; -var COPY_HIDDEN = process.env.COPY_HIDDEN; -var PROJECT_FILE_PATH = process.env.PROJECT_FILE_PATH; - -var path = require('path'); -var fs = require('fs'); -var shell = require('shelljs'); -var srcDir = 'www'; -var dstDir = path.join(BUILT_PRODUCTS_DIR, FULL_PRODUCT_NAME); -var dstWwwDir = path.join(dstDir, 'www'); - -if (!BUILT_PRODUCTS_DIR) { - console.error('The script is meant to be run as an Xcode build step and relies on env variables set by Xcode.'); - process.exit(1); -} - -try { - fs.statSync(srcDir); -} catch (e) { - console.error('Path does not exist: ' + srcDir); - process.exit(2); -} - -// Code signing files must be removed or else there are -// resource signing errors. -shell.rm('-rf', dstWwwDir); -shell.rm('-rf', path.join(dstDir, '_CodeSignature')); -shell.rm('-rf', path.join(dstDir, 'PkgInfo')); -shell.rm('-rf', path.join(dstDir, 'embedded.mobileprovision')); - -// Copy www dir recursively -var code; -if (COPY_HIDDEN) { - code = shell.exec('rsync -Lra "' + srcDir + '" "' + dstDir + '"').code; -} else { - code = shell.exec('rsync -Lra --exclude="- .*" "' + srcDir + '" "' + dstDir + '"').code; -} - -if (code !== 0) { - console.error('Error occured on copying www. Code: ' + code); - process.exit(3); -} - -// Copy the config.xml file. -shell.cp('-f', path.join(path.dirname(PROJECT_FILE_PATH), path.basename(PROJECT_FILE_PATH, '.xcodeproj'), 'config.xml'), - dstDir); diff --git a/cordova/lib/list-devices b/cordova/lib/list-devices deleted file mode 100755 index 047d595..0000000 --- a/cordova/lib/list-devices +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - - -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Gets list of connected iOS devices - * @return {Promise} Promise fulfilled with list of available iOS devices - */ -function listDevices() { - var commands = [ - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPad/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPad"}\''), - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPhone/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPhone"}\''), - Q.nfcall(exec, 'system_profiler SPUSBDataType | sed -n -e \'/iPod/,/Serial/p\' | grep "Serial Number:" | awk -F ": " \'{print $2 " iPod"}\'') - ]; - - // wrap al lexec calls into promises and wait until they're fullfilled - return Q.all(commands).then(function (results) { - var accumulator = []; - results.forEach(function (result) { - var devicefound; - // Each command promise resolves with array [stout, stderr], and we need stdout only - // Append stdout lines to accumulator - devicefound = result[0].trim().split('\n'); - if(devicefound && devicefound.length) { - devicefound.forEach(function(device) { - if (device) { - accumulator.push(device); - } - }); - } - }); - return accumulator; - }); -} - -exports.run = listDevices; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listDevices().then(function (devices) { - devices.forEach(function (device) { - console.log(device); - }); - }); -}
\ No newline at end of file diff --git a/cordova/lib/list-emulator-build-targets b/cordova/lib/list-emulator-build-targets deleted file mode 100755 index c0d566f..0000000 --- a/cordova/lib/list-emulator-build-targets +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - - -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Returns a list of available simulator build targets of the form - * - * [ - * { name: <xcode-destination-name>, - * identifier: <simctl-identifier>, - * simIdentifier: <cordova emulate target> - * } - * ] - * - */ -function listEmulatorBuildTargets () { - return Q.nfcall(exec, 'xcrun simctl list --json') - .then(function(stdio) { - return JSON.parse(stdio[0]); - }) - .then(function(simInfo) { - var devices = simInfo.devices; - var deviceTypes = simInfo.devicetypes; - return deviceTypes.reduce(function (typeAcc, deviceType) { - if (!deviceType.name.match(/^[iPad|iPhone]/)) { - // ignore targets we don't support (like Apple Watch or Apple TV) - return typeAcc; - } - var availableDevices = Object.keys(devices).reduce(function (availAcc, deviceCategory) { - var availableDevicesInCategory = devices[deviceCategory]; - availableDevicesInCategory.forEach(function (device) { - if (device.name === deviceType.name.replace(/\-inch/g, ' inch') && - device.availability.toLowerCase().indexOf('unavailable') < 0) { - availAcc.push(device); - } - }); - return availAcc; - }, []); - // we only want device types that have at least one available device - // (regardless of OS); this filters things out like iPhone 4s, which - // is present in deviceTypes, but probably not available on the user's - // system. - if (availableDevices.length > 0) { - typeAcc.push(deviceType); - } - return typeAcc; - }, []); - }) - .then(function(filteredTargets) { - // the simIdentifier, or cordova emulate target name, is the very last part - // of identifier. - return filteredTargets.map(function (target) { - var identifierPieces = target.identifier.split("."); - target.simIdentifier = identifierPieces[identifierPieces.length-1]; - return target; - }); - }); -} - -exports.run = listEmulatorBuildTargets; - -/** - * Given a simIdentifier, return the matching target. - * - * @param {string} simIdentifier a target, like "iPhone-SE" - * @return {Object} the matching target, or undefined if no match - */ -exports.targetForSimIdentifier = function(simIdentifier) { - return listEmulatorBuildTargets() - .then(function(targets) { - return targets.reduce(function(acc, target) { - if (!acc && target.simIdentifier.toLowerCase() === simIdentifier.toLowerCase()) { - acc = target; - } - return acc; - }, undefined); - }); -} - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listEmulatorBuildTargets().then(function (targets) { - console.log(JSON.stringify(targets, null, 2)); - }); -} diff --git a/cordova/lib/list-emulator-images b/cordova/lib/list-emulator-images deleted file mode 100755 index d8be576..0000000 --- a/cordova/lib/list-emulator-images +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - - -var Q = require('q'), - iossim = require('ios-sim'), - exec = require('child_process').exec, - check_reqs = require('./check_reqs'); - -/** - * Gets list of iOS devices available for simulation - * @return {Promise} Promise fulfilled with list of devices available for simulation - */ -function listEmulatorImages () { - return Q.resolve(iossim.getdevicetypes()); -} - - -exports.run = listEmulatorImages; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listEmulatorImages().then(function (names) { - names.forEach(function (name) { - console.log(name); - }); - }); -} diff --git a/cordova/lib/list-started-emulators b/cordova/lib/list-started-emulators deleted file mode 100755 index 710fa2f..0000000 --- a/cordova/lib/list-started-emulators +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - - -var Q = require('q'), - exec = require('child_process').exec; - -/** - * Gets list of running iOS simulators - * @return {Promise} Promise fulfilled with list of running iOS simulators - */ -function listStartedEmulators () { - // wrap exec call into promise - return Q.nfcall(exec, 'ps aux | grep -i "[i]OS Simulator"') - .then(function () { - return Q.nfcall(exec, 'defaults read com.apple.iphonesimulator "SimulateDevice"'); - }).then(function (stdio) { - return stdio[0].trim().split('\n'); - }); -} - -exports.run = listStartedEmulators; - -// Check if module is started as separate script. -// If so, then invoke main method and print out results. -if (!module.parent) { - listStartedEmulators().then(function (emulators) { - emulators.forEach(function (emulator) { - console.log(emulator); - }); - }); -} diff --git a/cordova/lib/plugman/pluginHandlers.js b/cordova/lib/plugman/pluginHandlers.js deleted file mode 100755 index 1f6920f..0000000 --- a/cordova/lib/plugman/pluginHandlers.js +++ /dev/null @@ -1,400 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ -'use strict'; -var fs = require('fs'); -var path = require('path'); -var shell = require('shelljs'); -var util = require('util'); -var events = require('cordova-common').events; -var CordovaError = require('cordova-common').CordovaError; - -// 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; - var target = obj.target; - var srcFile = path.resolve(plugin.dir, src); - - if (!target) { - target = path.basename(src); - } - var destFile = path.resolve(project.resources_dir, target); - - if (!fs.existsSync(srcFile)) { - throw new CordovaError('Cannot find resource file "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform'); - } - if (fs.existsSync(destFile)) { - throw new CordovaError('File already exists at destination "' + destFile + '" for resource file specified by plugin ' + plugin.id + ' in iOS platform'); - } - project.xcode.addResourceFile(path.join('Resources', target)); - var link = !!(options && options.link); - copyFile(plugin.dir, src, project.projectDir, destFile, link); - }, - uninstall: function (obj, plugin, project, options) { - var src = obj.src; - var target = obj.target; - - if (!target) { - target = path.basename(src); - } - var destFile = path.resolve(project.resources_dir, target); - - project.xcode.removeResourceFile(path.join('Resources', target)); - shell.rm('-rf', destFile); - } - }, - 'framework': { // CB-5238 custom frameworks only - install: function (obj, plugin, project, options) { - var src = obj.src; - var custom = !!(obj.custom); // convert to boolean (if truthy/falsy) - var embed = !!(obj.embed); // convert to boolean (if truthy/falsy) - var link = !embed; // either link or embed can be true, but not both. the other has to be false - - 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]++; - let opt = { customFramework: false, embed: false, link: true, weak: obj.weak }; - events.emit('verbose', util.format('Adding non-custom framework to project... %s -> %s', src, JSON.stringify(opt))); - project.xcode.addFramework(src, opt); - events.emit('verbose', util.format('Non-custom framework added to project. %s -> %s', src, JSON.stringify(opt))); - } - } - return; - } - var srcFile = path.resolve(plugin.dir, src); - var targetDir = path.resolve(project.plugins_dir, plugin.id, path.basename(src)); - if (!fs.existsSync(srcFile)) throw new CordovaError('Cannot find framework "' + srcFile + '" for plugin ' + plugin.id + ' in iOS platform'); - if (fs.existsSync(targetDir)) throw new CordovaError('Framework "' + targetDir + '" for plugin ' + plugin.id + ' already exists in iOS platform'); - var symlink = !!(options && options.link); - copyFile(plugin.dir, src, project.projectDir, targetDir, symlink); // frameworks are directories - // CB-10773 translate back slashes to forward on win32 - var project_relative = fixPathSep(path.relative(project.projectDir, targetDir)); - // CB-11233 create Embed Frameworks Build Phase if does not exist - var existsEmbedFrameworks = project.xcode.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks'); - if (!existsEmbedFrameworks && embed) { - events.emit('verbose', '"Embed Frameworks" Build Phase (Embedded Binaries) does not exist, creating it.'); - project.xcode.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', null, 'frameworks'); - } - let opt = { customFramework: true, embed: embed, link: link, sign: true }; - events.emit('verbose', util.format('Adding custom framework to project... %s -> %s', src, JSON.stringify(opt))); - project.xcode.addFramework(project_relative, opt); - events.emit('verbose', util.format('Custom framework added to project. %s -> %s', src, JSON.stringify(opt))); - }, - uninstall: function (obj, plugin, project, options) { - var src = obj.src; - - 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))); - var 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) { - linkFileOrDirTree(src, dest); - } else if (fs.statSync(src).isDirectory()) { - // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq - shell.cp('-Rf', path.join(src, '/*'), dest); - } else { - shell.cp('-f', src, dest); - } -} - -// 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 linkFileOrDirTree (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) { - linkFileOrDirTree(path.join(src, entry), path.join(dest, entry)); - }); - } else { - fs.linkSync(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/cordova/lib/prepare.js b/cordova/lib/prepare.js deleted file mode 100755 index de345dd..0000000 --- a/cordova/lib/prepare.js +++ /dev/null @@ -1,1153 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -'use strict'; -var Q = require('q'); -var fs = require('fs'); -var path = require('path'); -var shell = require('shelljs'); -var xcode = require('xcode'); -var unorm = require('unorm'); -var plist = require('plist'); -var URL = require('url'); -var events = require('cordova-common').events; -var xmlHelpers = require('cordova-common').xmlHelpers; -var ConfigParser = require('cordova-common').ConfigParser; -var CordovaError = require('cordova-common').CordovaError; -var PlatformJson = require('cordova-common').PlatformJson; -var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger; -var PluginInfoProvider = require('cordova-common').PluginInfoProvider; -var FileUpdater = require('cordova-common').FileUpdater; -var projectFile = require('./projectFile'); - -// launch storyboard and related constants -var LAUNCHIMAGE_BUILD_SETTING = 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME'; -var LAUNCHIMAGE_BUILD_SETTING_VALUE = 'LaunchImage'; -var UI_LAUNCH_STORYBOARD_NAME = 'UILaunchStoryboardName'; -var CDV_LAUNCH_STORYBOARD_NAME = 'CDVLaunchScreen'; -var IMAGESET_COMPACT_SIZE_CLASS = 'compact'; -var CDV_ANY_SIZE_CLASS = 'any'; - -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); - updateFileResources(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); - cleanFileResources(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 displayName = platformConfig.shortName && platformConfig.shortName(); - - 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'); - } - - if (displayName) { - infoPlist['CFBundleDisplayName'] = displayName; - } - - // 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, infoPlist).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, infoPlist) { - var targetDevice = parseTargetDevicePreference(platformConfig.getPreference('target-device', 'ios')); - var deploymentTarget = platformConfig.getPreference('deployment-target', 'ios'); - var needUpdatedBuildSettingsForLaunchStoryboard = checkIfBuildSettingsNeedUpdatedForLaunchStoryboard(platformConfig, infoPlist); - - // no build settings provided and we don't need to update build settings for launch storyboards, - // then we don't need to parse and update .pbxproj file - if (!targetDevice && !deploymentTarget && !needUpdatedBuildSettingsForLaunchStoryboard) { - return Q(); - } - - var proj = new xcode.project(locations.pbxproj); /* eslint new-cap : 0 */ - - try { - proj.parseSync(); - } catch (err) { - return Q.reject(new CordovaError('Could not parse project.pbxproj: ' + err)); - } - - if (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); - } - - updateBuildSettingsForLaunchStoryboard(proj, platformConfig, infoPlist); - - 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-20.png', width: 20, height: 20}, - {dest: '[email protected]', width: 40, height: 40}, - {dest: '[email protected]', width: 60, height: 60}, - {dest: 'icon-40.png', width: 40, height: 40}, - {dest: '[email protected]', width: 80, height: 80}, - {dest: 'icon-50.png', width: 50, height: 50}, - {dest: '[email protected]', width: 100, height: 100}, - {dest: '[email protected]', width: 120, height: 120}, - {dest: '[email protected]', width: 180, height: 180}, - {dest: 'icon-72.png', width: 72, height: 72}, - {dest: '[email protected]', width: 144, height: 144}, - {dest: 'icon-76.png', width: 76, height: 76}, - {dest: '[email protected]', width: 152, height: 152}, - {dest: '[email protected]', width: 167, height: 167}, - {dest: 'icon-1024.png', width: 1024, height: 1024}, - {dest: 'icon-small.png', width: 29, height: 29}, - {dest: '[email protected]', width: 58, height: 58}, - {dest: '[email protected]', width: 87, height: 87}, - {dest: 'icon.png', width: 57, height: 57}, - {dest: '[email protected]', width: 114, height: 114}, - {dest: '[email protected]', width: 48, height: 48}, - {dest: '[email protected]', width: 55, height: 55}, - {dest: '[email protected]', width: 58, height: 58}, - {dest: '[email protected]', width: 87, height: 87}, - {dest: '[email protected]', width: 80, height: 80}, - {dest: '[email protected]', width: 88, height: 88}, - {dest: '[email protected]', width: 172, height: 172}, - {dest: '[email protected]', width: 196, height: 196} - ]; - - 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}, - {dest: 'Default-2436h.png', width: 1125, height: 2436}, - {dest: 'Default-Landscape-2436h.png', width: 2436, height: 1125} - ]; - - 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); - } -} - -function updateFileResources (cordovaProject, locations) { - const platformDir = path.relative(cordovaProject.root, locations.root); - const files = cordovaProject.projectConfig.getFileResources('ios'); - - const project = projectFile.parse(locations); - - // if there are resource-file elements in config.xml - if (files.length === 0) { - events.emit('verbose', 'This app does not have additional resource files defined'); - return; - } - - let resourceMap = {}; - files.forEach(function (res) { - let src = res.src; - let target = res.target; - - if (!target) { - target = src; - } - - let targetPath = path.join(project.resources_dir, target); - targetPath = path.relative(cordovaProject.root, targetPath); - - project.xcode.addResourceFile(target); - - resourceMap[targetPath] = src; - }); - - events.emit('verbose', 'Updating resource files at ' + platformDir); - FileUpdater.updatePaths( - resourceMap, { rootDir: cordovaProject.root }, logFileOp); - - project.write(); -} - -function cleanFileResources (projectRoot, projectConfig, locations) { - const platformDir = path.relative(projectRoot, locations.root); - const files = projectConfig.getFileResources('ios', true); - if (files.length > 0) { - events.emit('verbose', 'Cleaning resource files at ' + platformDir); - - const project = projectFile.parse(locations); - - var resourceMap = {}; - files.forEach(function (res) { - let src = res.src; - let target = res.target; - - if (!target) { - target = src; - } - - let targetPath = path.join(project.resources_dir, target); - targetPath = path.relative(projectRoot, targetPath); - const resfile = path.join('Resources', path.basename(targetPath)); - project.xcode.removeResourceFile(resfile); - - resourceMap[targetPath] = null; - }); - - FileUpdater.updatePaths( - resourceMap, {rootDir: projectRoot, all: true}, logFileOp); - - project.write(); - } -} - -/** - * 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 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; -} - -/** - * Determines if the project's build settings may need to be updated for launch storyboard support - * - */ -function checkIfBuildSettingsNeedUpdatedForLaunchStoryboard (platformConfig, infoPlist) { - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig); - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - - if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) { - // don't need legacy launch images if we are using our launch storyboard - // so we do need to update the project file - events.emit('verbose', 'Need to update build settings because project is using our launch storyboard.'); - return true; - } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) { - // we do need to ensure legacy launch images are used if there's no launch storyboard present - // so we do need to update the project file - events.emit('verbose', 'Need to update build settings because project is using legacy launch images and no storyboard.'); - return true; - } - events.emit('verbose', 'No need to update build settings for launch storyboard support.'); - return false; -} - -function updateBuildSettingsForLaunchStoryboard (proj, platformConfig, infoPlist) { - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - var hasLegacyLaunchImages = platformHasLegacyLaunchImages(platformConfig); - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - - if (hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME && !hasLegacyLaunchImages) { - // don't need legacy launch images if we are using our launch storyboard - events.emit('verbose', 'Removed ' + LAUNCHIMAGE_BUILD_SETTING + ' because project is using our launch storyboard.'); - proj.removeBuildProperty(LAUNCHIMAGE_BUILD_SETTING); - } else if (hasLegacyLaunchImages && !currentLaunchStoryboard) { - // we do need to ensure legacy launch images are used if there's no launch storyboard present - events.emit('verbose', 'Set ' + LAUNCHIMAGE_BUILD_SETTING + ' to ' + LAUNCHIMAGE_BUILD_SETTING_VALUE + ' because project is using legacy launch images and no storyboard.'); - proj.updateBuildProperty(LAUNCHIMAGE_BUILD_SETTING, LAUNCHIMAGE_BUILD_SETTING_VALUE); - } else { - events.emit('verbose', 'Did not update build settings for launch storyboard support.'); - } -} - -function splashScreensHaveLaunchStoryboardImages (contentsJSON) { - /* do we have any launch images do we have for our launch storyboard? - * Again, for old Node versions, the below code is equivalent to this: - * return !!contentsJSON.images.find(function (item) { - * return item.filename !== undefined; - * }); - */ - return !!contentsJSON.images.reduce(function (p, c) { - return (c.filename !== undefined) ? c : p; - }, undefined); -} - -function platformHasLaunchStoryboardImages (platformConfig) { - var splashScreens = platformConfig.getSplashScreens('ios'); - var contentsJSON = getLaunchStoryboardContentsJSON(splashScreens, ''); // note: we don't need a file path here; we're just counting - return splashScreensHaveLaunchStoryboardImages(contentsJSON); -} - -function platformHasLegacyLaunchImages (platformConfig) { - var splashScreens = platformConfig.getSplashScreens('ios'); - return !!splashScreens.reduce(function (p, c) { - return (c.width !== undefined || c.height !== undefined) ? c : p; - }, undefined); -} - -/** - * Updates the project's plist based upon our launch storyboard images. If there are no images, then we should - * fall back to the regular launch images that might be supplied (that is, our app will be scaled on an iPad Pro), - * and if there are some images, we need to alter the UILaunchStoryboardName property to point to - * CDVLaunchScreen. - * - * There's some logic here to avoid overwriting changes the user might have made to their plist if they are using - * their own launch storyboard. - */ -function updateProjectPlistForLaunchStoryboard (platformConfig, infoPlist) { - var currentLaunchStoryboard = infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - events.emit('verbose', 'Current launch storyboard ' + currentLaunchStoryboard); - - var hasLaunchStoryboardImages = platformHasLaunchStoryboardImages(platformConfig); - - if (hasLaunchStoryboardImages && !currentLaunchStoryboard) { - // only change the launch storyboard if we have images to use AND the current value is blank - // if it's not blank, we've either done this before, or the user has their own launch storyboard - events.emit('verbose', 'Changing info plist to use our launch storyboard'); - infoPlist[UI_LAUNCH_STORYBOARD_NAME] = CDV_LAUNCH_STORYBOARD_NAME; - return; - } - - if (!hasLaunchStoryboardImages && currentLaunchStoryboard === CDV_LAUNCH_STORYBOARD_NAME) { - // only revert to using the launch images if we have don't have any images for the launch storyboard - // but only clear it if current launch storyboard is our storyboard; the user might be using their - // own storyboard instead. - events.emit('verbose', 'Changing info plist to use legacy launch images'); - delete infoPlist[UI_LAUNCH_STORYBOARD_NAME]; - return; - } - events.emit('verbose', 'Not changing launch storyboard setting in info plist.'); -} - -/** - * Returns the directory for the Launch Storyboard image set, if image sets are being used. If they aren't - * being used, returns null. - * - * @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 = path.relative(cordovaProject.root, 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(cordovaProject.root, 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 = path.relative(projectRoot, 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(projectRoot, 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) - NSAllowsArbitraryLoadsForMedia, // 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_for_media: currentElement.allows_arbitrary_loads_in_media || currentElement.allows_arbitrary_loads_for_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) - NSAllowsArbitraryLoadsForMedia, // 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_for_media === 'true'); - if (options.allows_arbitrary_loads_for_media && val) { // default is false - retObj.NSAllowsArbitraryLoadsForMedia = 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.NSAllowsArbitraryLoadsForMedia) { - ats['NSAllowsArbitraryLoadsForMedia'] = 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/cordova/lib/projectFile.js b/cordova/lib/projectFile.js deleted file mode 100755 index 8a3f7e5..0000000 --- a/cordova/lib/projectFile.js +++ /dev/null @@ -1,134 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var 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/cordova/lib/run.js b/cordova/lib/run.js deleted file mode 100755 index 3a6246e..0000000 --- a/cordova/lib/run.js +++ /dev/null @@ -1,244 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var Q = require('q'); -var path = require('path'); -var iossim = require('ios-sim'); -var build = require('./build'); -var spawn = require('./spawn'); -var 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 (runOptions) { - - // Validate args - if (runOptions.device && runOptions.emulator) { - return Q.reject('Only one of "device"/"emulator" options should be specified'); - } - - // support for CB-8168 `cordova/run --list` - if (runOptions.list) { - if (runOptions.device) return module.exports.listDevices(); - if (runOptions.emulator) return module.exports.listEmulators(); - // if no --device or --emulator flag is specified, list both devices and emulators - return module.exports.listDevices().then(function () { - return module.exports.listEmulators(); - }); - } - - var useDevice = !!runOptions.device; - - 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', 'emulator', projectName + '.app'); - var buildOutputDir = path.join(projectPath, 'build', 'device'); - - // select command to run and arguments depending whether - // we're running on device/emulator - if (useDevice) { - return module.exports.checkDeviceConnected() - .then(function () { - // Unpack IPA - 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); - }) - .then(function () { - // Uncompress IPA (zip file) - var appFileInflated = path.join(buildOutputDir, 'Payload', projectName + '.app'); - var appFile = path.join(buildOutputDir, projectName + '.app'); - var payloadFolder = path.join(buildOutputDir, 'Payload'); - - // 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); - }); - }) - .then(function () { - appPath = path.join(projectPath, 'build', 'device', projectName + '.app'); - var extraArgs = []; - if (runOptions.argv) { - // argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args - extraArgs = module.exports.filterSupportedArgs(runOptions.argv.slice(2)); - } - return module.exports.deployToDevice(appPath, runOptions.target, extraArgs); - }, function () { - // if device connection check failed use emulator then - return module.exports.deployToSim(appPath, runOptions.target); - }); - } else { - return module.exports.deployToSim(appPath, runOptions.target); - } - }); -}; - -module.exports.filterSupportedArgs = filterSupportedArgs; -module.exports.checkDeviceConnected = checkDeviceConnected; -module.exports.deployToDevice = deployToDevice; -module.exports.deployToSim = deployToSim; -module.exports.startSim = startSim; -module.exports.listDevices = listDevices; -module.exports.listEmulators = listEmulators; - -/** - * 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', '-t', '1']); -} - -/** - * Deploy specified app package to connected device - * using ios-deploy command - * @param {String} appPath Path to application package - * @return {Promise} Resolves when deploy succeeds otherwise rejects - */ -function deployToDevice (appPath, target, extraArgs) { - // Deploying to device... - 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)); - } -} - -/** - * Deploy specified app package to ios-sim simulator - * @param {String} appPath Path to application package - * @param {String} target Target device type - * @return {Promise} Resolves when deploy succeeds otherwise rejects - */ -function deployToSim (appPath, target) { - // Select target device for emulator. Default is 'iPhone-6' - if (!target) { - 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'); - - return iossim.launch(appPath, 'com.apple.CoreSimulator.SimDeviceType.' + target, logPath, '--exit'); -} - -function listDevices () { - return require('./list-devices').run() - .then(function (devices) { - events.emit('log', 'Available iOS Devices:'); - devices.forEach(function (device) { - events.emit('log', '\t' + device); - }); - }); -} - -function listEmulators () { - return require('./list-emulator-images').run() - .then(function (emulators) { - events.emit('log', 'Available iOS Simulators:'); - emulators.forEach(function (emulator) { - events.emit('log', '\t' + emulator); - }); - }); -} - -module.exports.help = function () { - console.log('\nUsage: run [ --device | [ --emulator [ --target=<id> ] ] ] [ --debug | --release | --nobuild ]'); - // TODO: add support for building different archs - // console.log(" [ --archs=\"<list of target architectures>\" ] "); - console.log(' --device : Deploys and runs the project on the connected device.'); - console.log(' --emulator : Deploys and runs the project on an emulator.'); - console.log(' --target=<id> : Deploys and runs the project on the specified target.'); - console.log(' --debug : Builds project in debug mode. (Passed down to build command, if necessary)'); - console.log(' --release : Builds project in release mode. (Passed down to build command, if necessary)'); - console.log(' --nobuild : Uses pre-built package, or errors if project is not built.'); - // TODO: add support for building different archs - // console.log(" --archs : Specific chip architectures (`anycpu`, `arm`, `x86`, `x64`)."); - console.log(''); - console.log('Examples:'); - console.log(' run'); - console.log(' run --device'); - console.log(' run --emulator --target=\"iPhone-6-Plus\"'); /* eslint no-useless-escape : 0 */ - console.log(' run --device --release'); - console.log(' run --emulator --debug'); - console.log(''); - process.exit(0); -}; diff --git a/cordova/lib/spawn.js b/cordova/lib/spawn.js deleted file mode 100755 index b5a5685..0000000 --- a/cordova/lib/spawn.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var Q = require('q'); -var proc = require('child_process'); - -/** - * Run specified command with arguments - * @param {String} cmd Command - * @param {Array} args Array of arguments that should be passed to command - * @param {String} opt_cwd Working directory for command - * @param {String} opt_verbosity Verbosity level for command stdout output, "verbose" by default - * @return {Promise} Promise either fullfilled or rejected with error code - */ -module.exports = function (cmd, args, opt_cwd) { - var d = Q.defer(); - try { - var child = proc.spawn(cmd, args, {cwd: opt_cwd, stdio: 'inherit'}); - - child.on('exit', function (code) { - if (code) { - d.reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args); - } else { - d.resolve(); - } - }); - } catch (e) { - d.reject(e); - } - return d.promise; -}; diff --git a/cordova/lib/start-emulator b/cordova/lib/start-emulator deleted file mode 100755 index 624335b..0000000 --- a/cordova/lib/start-emulator +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# -# 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. -# -# Run the below to get the device targets: -# xcrun instruments -s - -set -e - - -DEFAULT_TARGET="iPhone 5s" -TARGET=${1:-$DEFAULT_TARGET} -LIB_PATH=$( cd "$( dirname "$0" )" && pwd -P) - -xcrun instruments -w "$TARGET" &> /dev/null
\ No newline at end of file diff --git a/cordova/lib/versions.js b/cordova/lib/versions.js deleted file mode 100755 index c6a41b8..0000000 --- a/cordova/lib/versions.js +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env node - -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var child_process = require('child_process'); -var Q = require('q'); - -exports.get_apple_ios_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - - return d.promise.then(function (output) { - var regex = /[0-9]*\.[0-9]*/; - var versions = []; - var regexIOS = /^iOS \d+/; - output = output.split('\n'); - for (var i = 0; i < output.length; i++) { - if (output[i].trim().match(regexIOS)) { - versions[versions.length] = parseFloat(output[i].match(regex)[0]); - } - } - versions.sort(); - console.log(versions[0]); - return Q(); - }, function (stderr) { - return Q.reject(stderr); - }); -}; - -exports.get_apple_osx_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -showsdks', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - - return d.promise.then(function (output) { - var regex = /[0-9]*\.[0-9]*/; - var versions = []; - var regexOSX = /^OS X \d+/; - output = output.split('\n'); - for (var i = 0; i < output.length; i++) { - if (output[i].trim().match(regexOSX)) { - versions[versions.length] = parseFloat(output[i].match(regex)[0]); - } - } - versions.sort(); - console.log(versions[0]); - return Q(); - }, function (stderr) { - return Q.reject(stderr); - }); -}; - -exports.get_apple_xcode_version = function () { - var d = Q.defer(); - child_process.exec('xcodebuild -version', function (error, stdout, stderr) { - var versionMatch = /Xcode (.*)/.exec(stdout); - if (error || !versionMatch) { - d.reject(stderr); - } else { - d.resolve(versionMatch[1]); - } - }); - return d.promise; -}; - -/** - * Gets ios-deploy util version - * @return {Promise} Promise that either resolved with ios-deploy version - * or rejected in case of error - */ -exports.get_ios_deploy_version = function () { - var d = Q.defer(); - child_process.exec('ios-deploy --version', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - return d.promise; -}; - -/** - * 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 - */ -exports.get_ios_sim_version = function () { - var d = Q.defer(); - child_process.exec('ios-sim --version', function (error, stdout, stderr) { - if (error) { - d.reject(stderr); - } else { - d.resolve(stdout); - } - }); - return d.promise; -}; - -/** - * Gets specific tool version - * @param {String} toolName Tool name to check. Known tools are 'xcodebuild', 'ios-sim' and 'ios-deploy' - * @return {Promise} Promise that either resolved with tool version - * or rejected in case of error - */ -exports.get_tool_version = function (toolName) { - switch (toolName) { - case 'xcodebuild': return exports.get_apple_xcode_version(); - case 'ios-sim': return exports.get_ios_sim_version(); - case 'ios-deploy': return exports.get_ios_deploy_version(); - case 'pod': return exports.get_cocoapods_version(); - default: return Q.reject(toolName + ' is not valid tool name. Valid names are: \'xcodebuild\', \'ios-sim\', \'ios-deploy\', and \'pod\''); - } -}; - -/** - * Compares two semver-notated version strings. Returns number - * that indicates equality of provided version strings. - * @param {String} version1 Version to compare - * @param {String} version2 Another version to compare - * @return {Number} Negative number if first version is lower than the second, - * positive otherwise and 0 if versions are equal. - */ -exports.compareVersions = function (version1, version2) { - function parseVer (version) { - return version.split('.').map(function (value) { - // try to convert version segment to Number - var parsed = Number(value); - // Number constructor is strict enough and will return NaN - // if conversion fails. In this case we won't be able to compare versions properly - if (isNaN(parsed)) { - throw 'Version should contain only numbers and dots'; - } - return parsed; - }); - } - var parsedVer1 = parseVer(version1); - var parsedVer2 = parseVer(version2); - - // Compare corresponding segments of each version - for (var i = 0; i < Math.max(parsedVer1.length, parsedVer2.length); i++) { - // if segment is not specified, assume that it is 0 - // E.g. 3.1 is equal to 3.1.0 - var ret = (parsedVer1[i] || 0) - (parsedVer2[i] || 0); - // if segments are not equal, we're finished - if (ret !== 0) return ret; - } - return 0; -}; |
