summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/cordova/lib/build.js
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2016-11-08 11:46:59 -0500
committerJules Laplace <jules@okfoc.us>2016-11-08 11:46:59 -0500
commit5fa81da81260d65113f57a293b6256d334fe8e2d (patch)
tree01d3dd7ab7a1febccd20de1756d0801a64ae64e9 /StoneIsland/platforms/ios/cordova/lib/build.js
parente5652e9cd560ccda249819857c207643820b075f (diff)
parent7773d1d0686de69504e9b820efdb3e94d72eff04 (diff)
le build
Diffstat (limited to 'StoneIsland/platforms/ios/cordova/lib/build.js')
-rwxr-xr-xStoneIsland/platforms/ios/cordova/lib/build.js304
1 files changed, 225 insertions, 79 deletions
diff --git a/StoneIsland/platforms/ios/cordova/lib/build.js b/StoneIsland/platforms/ios/cordova/lib/build.js
index 2213ef8c..a26f1983 100755
--- a/StoneIsland/platforms/ios/cordova/lib/build.js
+++ b/StoneIsland/platforms/ios/cordova/lib/build.js
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,98 +20,170 @@
/*jshint node: true*/
var Q = require('q'),
- nopt = require('nopt'),
path = require('path'),
shell = require('shelljs'),
spawn = require('./spawn'),
- check_reqs = require('./check_reqs'),
- fs = require('fs');
+ fs = require('fs'),
+ plist = require('plist'),
+ util = require('util');
+
+var check_reqs;
+try {
+ check_reqs = require('./check_reqs');
+} catch (err) {
+ // For unit tests, check_reqs.js is not a sibling to build.js
+ check_reqs = require('../../../../lib/check_reqs');
+}
+
+var events = require('cordova-common').events;
var projectPath = path.join(__dirname, '..', '..');
var projectName = null;
-module.exports.run = function (argv) {
+// These are regular expressions to detect if the user is changing any of the built-in xcodebuildArgs
+var buildFlagMatchers = {
+ 'xcconfig' : /^\-xcconfig\s*(.*)$/,
+ 'workspace' : /^\-workspace\s*(.*)/,
+ 'scheme' : /^\-scheme\s*(.*)/,
+ 'configuration' : /^\-configuration\s*(.*)/,
+ 'sdk' : /^\-sdk\s*(.*)/,
+ 'destination' : /^\-destination\s*(.*)/,
+ 'archivePath' : /^\-archivePath\s*(.*)/,
+ 'configuration_build_dir' : /^(CONFIGURATION_BUILD_DIR=.*)/,
+ 'shared_precomps_dir' : /^(SHARED_PRECOMPS_DIR=.*)/
+};
- var args = nopt({
- // "archs": String, // TODO: add support for building different archs
- 'debug': Boolean,
- 'release': Boolean,
- 'device': Boolean,
- 'emulator': Boolean,
- 'codeSignIdentity': String,
- 'codeSignResourceRules': String,
- 'provisioningProfile': String,
- 'buildConfig' : String
- }, {'-r': '--release'}, argv);
+module.exports.run = function (buildOpts) {
- if (args.debug && args.release) {
- return Q.reject('Only one of "debug"/"release" options should be specified');
+ buildOpts = buildOpts || {};
+
+ if (buildOpts.debug && buildOpts.release) {
+ return Q.reject('Cannot specify "debug" and "release" options together.');
}
- if (args.device && args.emulator) {
- return Q.reject('Only one of "device"/"emulator" options should be specified');
+ if (buildOpts.device && buildOpts.emulator) {
+ return Q.reject('Cannot specify "device" and "emulator" options together.');
}
- if(args.buildConfig) {
- if(!fs.existsSync(args.buildConfig)) {
- return Q.reject('Build config file does not exist:' + args.buildConfig);
+ if(buildOpts.buildConfig) {
+ if(!fs.existsSync(buildOpts.buildConfig)) {
+ return Q.reject('Build config file does not exist:' + buildOpts.buildConfig);
}
- console.log('Reading build config file:', path.resolve(args.buildConfig));
- var buildConfig = JSON.parse(fs.readFileSync(args.buildConfig, 'utf-8'));
+ events.emit('log','Reading build config file:', path.resolve(buildOpts.buildConfig));
+ var contents = fs.readFileSync(buildOpts.buildConfig, 'utf-8');
+ var buildConfig = JSON.parse(contents.replace(/^\ufeff/, '')); // Remove BOM
if(buildConfig.ios) {
- var buildType = args.release ? 'release' : 'debug';
+ var buildType = buildOpts.release ? 'release' : 'debug';
var config = buildConfig.ios[buildType];
if(config) {
- ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile'].forEach(
+ ['codeSignIdentity', 'codeSignResourceRules', 'provisioningProfile', 'developmentTeam', 'packageType'].forEach(
function(key) {
- args[key] = args[key] || config[key];
+ buildOpts[key] = buildOpts[key] || config[key];
});
}
}
}
-
+
return check_reqs.run().then(function () {
return findXCodeProjectIn(projectPath);
}).then(function (name) {
projectName = name;
var extraConfig = '';
- if (args.codeSignIdentity) {
- extraConfig += 'CODE_SIGN_IDENTITY = ' + args.codeSignIdentity + '\n';
- extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + args.codeSignIdentity + '\n';
+ if (buildOpts.codeSignIdentity) {
+ extraConfig += 'CODE_SIGN_IDENTITY = ' + buildOpts.codeSignIdentity + '\n';
+ extraConfig += 'CODE_SIGN_IDENTITY[sdk=iphoneos*] = ' + buildOpts.codeSignIdentity + '\n';
}
- if (args.codeSignResourceRules) {
- extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + args.codeSignResourceRules + '\n';
+ if (buildOpts.codeSignResourceRules) {
+ extraConfig += 'CODE_SIGN_RESOURCE_RULES_PATH = ' + buildOpts.codeSignResourceRules + '\n';
}
- if (args.provisioningProfile) {
- extraConfig += 'PROVISIONING_PROFILE = ' + args.provisioningProfile + '\n';
+ if (buildOpts.provisioningProfile) {
+ extraConfig += 'PROVISIONING_PROFILE = ' + buildOpts.provisioningProfile + '\n';
+ }
+ if (buildOpts.developmentTeam) {
+ extraConfig += 'DEVELOPMENT_TEAM = ' + buildOpts.developmentTeam + '\n';
}
return Q.nfcall(fs.writeFile, path.join(__dirname, '..', 'build-extras.xcconfig'), extraConfig, 'utf-8');
}).then(function () {
- var configuration = args.release ? 'Release' : 'Debug';
+ var configuration = buildOpts.release ? 'Release' : 'Debug';
+
+ events.emit('log','Building project: ' + path.join(projectPath, projectName + '.xcworkspace'));
+ events.emit('log','\tConfiguration: ' + configuration);
+ events.emit('log','\tPlatform: ' + (buildOpts.device ? 'device' : 'emulator'));
+
+ var buildOutputDir = path.join(projectPath, 'build', 'device');
- console.log('Building project : ' + path.join(projectPath, projectName + '.xcodeproj'));
- console.log('\tConfiguration : ' + configuration);
- console.log('\tPlatform : ' + (args.device ? 'device' : 'emulator'));
+ // remove the build/device folder before building
+ return spawn('rm', [ '-rf', buildOutputDir ], projectPath)
+ .then(function() {
+ var xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, buildOpts.device, buildOpts.buildFlag);
+ return spawn('xcodebuild', xcodebuildArgs, projectPath);
+ });
- var xcodebuildArgs = getXcodeArgs(projectName, projectPath, configuration, args.device);
- return spawn('xcodebuild', xcodebuildArgs, projectPath);
}).then(function () {
- if (!args.device) {
+ if (!buildOpts.device || buildOpts.noSign) {
return;
}
+
+ var exportOptions = {'compileBitcode': false, 'method': 'development'};
+
+ if (buildOpts.packageType) {
+ exportOptions.method = buildOpts.packageType;
+ }
+
+ if (buildOpts.developmentTeam) {
+ exportOptions.teamID = buildOpts.developmentTeam;
+ }
+
+ var exportOptionsPlist = plist.build(exportOptions);
+ var exportOptionsPath = path.join(projectPath, 'exportOptions.plist');
+
var buildOutputDir = path.join(projectPath, 'build', 'device');
- var pathToApp = path.join(buildOutputDir, projectName + '.app');
- var pathToIpa = path.join(buildOutputDir, projectName + '.ipa');
- var xcRunArgs = ['-sdk', 'iphoneos', 'PackageApplication',
- '-v', pathToApp,
- '-o', pathToIpa];
- if (args.codeSignIdentity) {
- xcRunArgs.concat('--sign', args.codeSignIdentity);
+
+
+ function checkSystemRuby() {
+ var ruby_cmd = shell.which('ruby');
+
+ if (ruby_cmd != '/usr/bin/ruby') {
+ events.emit('warn', 'Non-system Ruby in use. This may cause packaging to fail.\n' +
+ 'If you use RVM, please run `rvm use system`.\n' +
+ 'If you use chruby, please run `chruby system`.');
+ }
+ }
+
+ function packageArchive() {
+ var xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath);
+ return spawn('xcodebuild', xcodearchiveArgs, projectPath);
+ }
+
+ function unpackIPA() {
+ var ipafile = path.join(buildOutputDir, projectName + '.ipa');
+
+ // unpack the existing platform/ios/build/device/appname.ipa (zipfile), will create a Payload folder
+ return spawn('unzip', [ '-o', '-qq', ipafile ], buildOutputDir);
}
- if (args.provisioningProfile) {
- xcRunArgs.concat('--embed', args.provisioningProfile);
+
+ function moveApp() {
+ var appFileInflated = path.join(buildOutputDir, 'Payload', projectName + '.app');
+ var appFile = path.join(buildOutputDir, projectName + '.app');
+ var payloadFolder = path.join(buildOutputDir, 'Payload');
+
+ // delete the existing platform/ios/build/device/appname.app
+ return spawn('rm', [ '-rf', appFile ], buildOutputDir)
+ .then(function() {
+ // move the platform/ios/build/device/Payload/appname.app to parent
+ return spawn('mv', [ '-f', appFileInflated, buildOutputDir ], buildOutputDir);
+ })
+ .then(function() {
+ // delete the platform/ios/build/device/Payload folder
+ return spawn('rm', [ '-rf', payloadFolder ], buildOutputDir);
+ });
}
- return spawn('xcrun', xcRunArgs, projectPath);
+
+ return Q.nfcall(fs.writeFile, exportOptionsPath, exportOptionsPlist, 'utf-8')
+ .then(checkSystemRuby)
+ .then(packageArchive)
+ .then(unpackIPA)
+ .then(moveApp);
});
};
@@ -125,12 +197,12 @@ function findXCodeProjectIn(projectPath) {
var xcodeProjFiles = shell.ls(projectPath).filter(function (name) {
return path.extname(name) === '.xcodeproj';
});
-
+
if (xcodeProjFiles.length === 0) {
return Q.reject('No Xcode project found in ' + projectPath);
}
if (xcodeProjFiles.length > 1) {
- console.warn('Found multiple .xcodeproj directories in \n' +
+ events.emit('warn','Found multiple .xcodeproj directories in \n' +
projectPath + '\nUsing first one');
}
@@ -148,38 +220,111 @@ module.exports.findXCodeProjectIn = findXCodeProjectIn;
* @param {Boolean} isDevice Flag that specify target for package (device/emulator)
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
-function getXcodeArgs(projectName, projectPath, configuration, isDevice) {
+function getXcodeBuildArgs(projectName, projectPath, configuration, isDevice, buildFlags) {
var xcodebuildArgs;
+ var options;
+ var buildActions;
+ var settings;
+ var customArgs = {};
+ customArgs.otherFlags = [];
+
+ if (buildFlags) {
+ if (typeof buildFlags === 'string' || buildFlags instanceof String) {
+ parseBuildFlag(buildFlags, customArgs);
+ } else { // buildFlags is an Array of strings
+ buildFlags.forEach( function(flag) {
+ parseBuildFlag(flag, customArgs);
+ });
+ }
+ }
+
if (isDevice) {
- xcodebuildArgs = [
- '-xcconfig', path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-project', projectName + '.xcodeproj',
- 'ARCHS=armv7 armv7s arm64',
- '-target', projectName,
- '-configuration', configuration,
- '-sdk', 'iphoneos',
- 'build',
- 'VALID_ARCHS=armv7 armv7s arm64',
- 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'device'),
- 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ options = [
+ '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
+ '-workspace', customArgs.workspace || projectName + '.xcworkspace',
+ '-scheme', customArgs.scheme || projectName,
+ '-configuration', customArgs.configuration || configuration,
+ '-destination', customArgs.destination || 'generic/platform=iOS',
+ '-archivePath', customArgs.archivePath || projectName + '.xcarchive'
+ ];
+ buildActions = [ 'archive' ];
+ settings = [
+ customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'device'),
+ customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
];
+ // Add other matched flags to otherFlags to let xcodebuild present an appropriate error.
+ // This is preferable to just ignoring the flags that the user has passed in.
+ if (customArgs.sdk) {
+ customArgs.otherFlags = customArgs.otherFlags.concat(['-sdk', customArgs.sdk]);
+ }
} else { // emulator
- xcodebuildArgs = [
- '-xcconfig', path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
- '-project', projectName + '.xcodeproj',
- 'ARCHS=i386',
- '-target', projectName ,
- '-configuration', configuration,
- '-sdk', 'iphonesimulator',
- 'build',
- 'VALID_ARCHS=i386',
- 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'emulator'),
- 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
+ options = [
+ '-xcconfig', customArgs.xcconfig || path.join(__dirname, '..', 'build-' + configuration.toLowerCase() + '.xcconfig'),
+ '-workspace', customArgs.project || projectName + '.xcworkspace',
+ '-scheme', customArgs.scheme || projectName,
+ '-configuration', customArgs.configuration || configuration,
+ '-sdk', customArgs.sdk || 'iphonesimulator',
+ '-destination', customArgs.destination || 'platform=iOS Simulator,name=iPhone 5s'
+ ];
+ buildActions = [ 'build' ];
+ settings = [
+ customArgs.configuration_build_dir || 'CONFIGURATION_BUILD_DIR=' + path.join(projectPath, 'build', 'emulator'),
+ customArgs.shared_precomps_dir || 'SHARED_PRECOMPS_DIR=' + path.join(projectPath, 'build', 'sharedpch')
];
+ // Add other matched flags to otherFlags to let xcodebuild present an appropriate error.
+ // This is preferable to just ignoring the flags that the user has passed in.
+ if (customArgs.archivePath) {
+ customArgs.otherFlags = customArgs.otherFlags.concat(['-archivePath', customArgs.archivePath]);
+ }
}
+ xcodebuildArgs = options.concat(buildActions).concat(settings).concat(customArgs.otherFlags);
return xcodebuildArgs;
}
+
+/**
+ * Returns array of arguments for xcodebuild
+ * @param {String} projectName Name of xcode project
+ * @param {String} projectPath Path to project file. Will be used to set CWD for xcodebuild
+ * @param {String} outputPath Output directory to contain the IPA
+ * @param {String} exportOptionsPath Path to the exportOptions.plist file
+ * @return {Array} Array of arguments that could be passed directly to spawn method
+ */
+function getXcodeArchiveArgs(projectName, projectPath, outputPath, exportOptionsPath) {
+ return [
+ '-exportArchive',
+ '-archivePath', projectName + '.xcarchive',
+ '-exportOptionsPlist', exportOptionsPath,
+ '-exportPath', outputPath
+ ];
+}
+
+function parseBuildFlag(buildFlag, args) {
+ var matched;
+ for (var key in buildFlagMatchers) {
+ var found = buildFlag.match(buildFlagMatchers[key]);
+ if (found) {
+ matched = true;
+ // found[0] is the whole match, found[1] is the first match in parentheses.
+ args[key] = found[1];
+ events.emit('warn', util.format('Overriding xcodebuildArg: %s', buildFlag));
+ }
+ }
+
+ if (!matched) {
+ // If the flag starts with a '-' then it is an xcodebuild built-in option or a
+ // user-defined setting. The regex makes sure that we don't split a user-defined
+ // setting that is wrapped in quotes.
+ if (buildFlag[0] === '-' && !buildFlag.match(/^.*=(\".*\")|(\'.*\')$/)) {
+ args.otherFlags = args.otherFlags.concat(buildFlag.split(' '));
+ events.emit('warn', util.format('Adding xcodebuildArg: %s', buildFlag.split(' ')));
+ } else {
+ args.otherFlags.push(buildFlag);
+ events.emit('warn', util.format('Adding xcodebuildArg: %s', buildFlag));
+ }
+ }
+}
+
// help/usage function
module.exports.help = function help() {
console.log('');
@@ -198,6 +343,7 @@ module.exports.help = function help() {
console.log(' --codeSignIdentity : Type of signing identity used for code signing.');
console.log(' --codeSignResourceRules : Path to ResourceRules.plist.');
console.log(' --provisioningProfile : UUID of the profile.');
+ console.log(' --device --noSign : Builds project without application signing.');
console.log('');
console.log('examples:');
console.log(' build ');