Skip to content

Commit

Permalink
Merge pull request #8966 from cb1kenobi/timob-24565_6_1_X
Browse files Browse the repository at this point in the history
[TIMOB-24565] App Store build .ipa export backport
  • Loading branch information
cb1kenobi committed Apr 14, 2017
2 parents 437ee5a + edb20bc commit 5ba12ba
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 94 deletions.
2 changes: 1 addition & 1 deletion iphone/cli/commands/_build.js
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ iOSBuilder.prototype.configOptionOutputDir = function configOptionOutputDir(orde

return {
abbr: 'O',
desc: __('the output directory when using %s', 'dist-adhoc'.cyan),
desc: __('the output directory when using %s or %s', 'dist-appstore'.cyan, 'dist-adhoc'.cyan),
hint: 'dir',
order: order,
prompt: function (callback) {
Expand Down
215 changes: 122 additions & 93 deletions iphone/cli/hooks/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ exports.init = function (logger, config, cli) {
}
});

// if output-dir don't move the archive, instead export it into an IPA
if (cli.argv['output-dir']) {
exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
return;
}

var month = now.getMonth() + 1;
var day = now.getDate();
var hours = now.getHours();
Expand All @@ -129,112 +135,135 @@ exports.init = function (logger, config, cli) {
logger: logger.debug
});

// open xcode + organizer after packaging
logger.info(__('Launching Xcode: %s', builder.xcodeEnv.xcodeapp.cyan));
exec('open -a "' + builder.xcodeEnv.xcodeapp + '"', function (err, stdout, stderr) {
process.env.TI_ENV_NAME = process.env.STUDIO_NAME || 'Terminal.app';
exec('osascript "' + path.join(builder.platformPath, 'xcode_organizer.scpt') + '"', { env: process.env }, function (err, stdout, stderr) {
logger.info(__('Packaging complete'));
finished();
// if not build-only open xcode + organizer after packaging, otherwise finish
if (!cli.argv['build-only']) {
logger.info(__('Launching Xcode: %s', builder.xcodeEnv.xcodeapp.cyan));
exec('open -a "' + builder.xcodeEnv.xcodeapp + '"', function (err, stdout, stderr) {
process.env.TI_ENV_NAME = process.env.STUDIO_NAME || 'Terminal.app';
exec('osascript "' + path.join(builder.platformPath, 'xcode_organizer.scpt') + '"', { env: process.env }, function (err, stdout, stderr) {
logger.info(__('Packaging complete'));
finished();
});
});
});
} else {
logger.info(__('Packaging complete'));
finished();
}
return;

case 'dist-adhoc':
var outputDir = cli.argv['output-dir'] && afs.resolvePath(cli.argv['output-dir']);
if (!outputDir) {
logger.warn(__('Invalid %s, skipping packaging', '--output-dir'.cyan));
return finished();
}
logger.info(__('Packaging for Ad Hoc distribution'));
exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
return;
}

finished();
}
});

/**
* Centralized function to export build into an IPA
*/
function exportIPA(builder, target, stagingArchiveDir, outputDirArg, callback) {
logger.debug(__('Packaging IPA for target %s', target.cyan));

var outputDir = outputDirArg && afs.resolvePath(outputDirArg);
if (!outputDir) {
logger.warn(__('Invalid output directory %s, skipping packaging', '--output-dir'.cyan));
return callback();
}

// make sure the output directory is good to go
fs.existsSync(outputDir) || wrench.mkdirSyncRecursive(outputDir);
var ipaFile = path.join(outputDir, builder.tiapp.name + '.ipa');
fs.existsSync(ipaFile) && fs.unlinkSync(ipaFile);

var exportsOptionsPlistFile = path.join(builder.buildDir, 'export_options.plist');
var exportsOptions = new appc.plist();

// Build the options plist file
if (target === 'dist-appstore') {
exportsOptions.method = 'app-store';
} else {
exportsOptions.method = 'ad-hoc';

var pp = null;
builder.iosInfo.provisioning.adhoc.some(function (p) {
if (p.uuid === builder.provisioningProfileUUID) {
pp = p;
return true;
}
});
if (!pp) {
builder.iosInfo.provisioning.enterprise.some(function (p) {
if (p.uuid === builder.provisioningProfileUUID) {
pp = p;
exportsOptions.method = 'enterprise';
return true;
}
});
}
if (pp && pp.team && pp.team.length) {
exportsOptions.teamId = pp.team[0];
}
}

// make sure the output directory is good to go
fs.existsSync(outputDir) || wrench.mkdirSyncRecursive(outputDir);
var ipaFile = path.join(outputDir, builder.tiapp.name + '.ipa');
fs.existsSync(ipaFile) && fs.unlinkSync(ipaFile);
fs.writeFileSync(exportsOptionsPlistFile, exportsOptions.toString('xml'));

// write the export options plist file
var exportsOptionsPlistFile = path.join(builder.buildDir, 'export_options.plist');
var exportsOptions = new appc.plist();
exportsOptions.method = 'ad-hoc';
// construct the command
var cmd = [
builder.xcodeEnv.executables.xcodebuild,
'-exportArchive',
'-archivePath', '"' + stagingArchiveDir + '"',
'-exportPath', '"' + outputDir + '"',
'-exportOptionsPlist', '"' + exportsOptionsPlistFile + '"'
].join(' ');

var pp = null;
builder.iosInfo.provisioning.adhoc.some(function (p) {
// execute!
logger.debug(__('Running: %s', cmd.cyan));
exec(cmd, function (err, stdout, stderr) {
if (err) {
var output = stderr.trim();
output.split('\n').forEach(logger.trace);
logger.error(__('Failed to export archive to ipa'));

var pp = null;
var ppType = null;

function findPP(type) {
builder.iosInfo.provisioning[type].some(function (p) {
if (p.uuid === builder.provisioningProfileUUID) {
pp = p;
return true;
ppType = type;
}
});
if (!pp) {
builder.iosInfo.provisioning.enterprise.some(function (p) {
if (p.uuid === builder.provisioningProfileUUID) {
pp = p;
exportsOptions.method = 'enterprise';
return true;
}
});
}
if (pp && pp.team && pp.team.length) {
exportsOptions.teamId = pp.team[0];
}
}

fs.writeFileSync(exportsOptionsPlistFile, exportsOptions.toString('xml'));

// construct the command
var cmd = [
builder.xcodeEnv.executables.xcodebuild,
'-exportArchive',
'-archivePath', '"' + stagingArchiveDir + '"',
'-exportPath', '"' + outputDir + '"',
'-exportOptionsPlist', '"' + exportsOptionsPlistFile + '"'
].join(' ');

// execute!
logger.debug(__('Running: %s', cmd.cyan));
exec(cmd, function (err, stdout, stderr) {
if (err) {
var output = stderr.trim();
output.split('\n').forEach(logger.trace);
logger.error(__('Failed to export archive to ipa'));

var pp = null;
var ppType = null;

function findPP(type) {
builder.iosInfo.provisioning[type].some(function (p) {
if (p.uuid === builder.provisioningProfileUUID) {
pp = p;
ppType = type;
}
});
}

findPP('distribution');
if (!pp) {
findPP('adhoc');
}

if (pp) {
if (ppType === 'distribution') {
logger.error(__('The selected provisioning profile "%s (%s)" appears to be a Distribution provisioning profile and not an Ad Hoc provisioning profile.', pp.name, pp.uuid));
} else {
logger.error(__('The selected provisioning profile "%s (%s)" is most likely not a valid Ad Hoc provisioning profile.', pp.name, pp.uuid));
}
} else {
logger.error(__('The selected provisioning profile doesn\'t appear to be a Ad Hoc provisioning profile or match the signing identity.'));
}
logger.error(__('Please ensure you are using a valid Ad Hoc provisioning that is linked to the signing identity, then try again.'));
} else {
logger.info(__('Packaging complete'));
logger.info(__('Package location: %s', ipaFile.cyan));
}
finished();
});
return;
}
findPP('distribution');
if (!pp) {
findPP('adhoc');
}

finished();
}
});
var targetName = target === 'dist-appstore' ? 'Distribution' : 'Ad Hoc';

if (pp) {
if (ppType === 'distribution' && target === 'dist-adhoc') {
logger.error(__('The selected provisioning profile "%s (%s)" appears to be a Distribution provisioning profile and not an Ad Hoc provisioning profile.', pp.name, pp.uuid));
} else if (ppType === 'adhoc' && target === 'dist-appstore') {
logger.error(__('The selected provisioning profile "%s (%s)" appears to be an Ad Hoc provisioning profile and not a Distribution provisioning profile.', pp.name, pp.uuid));
}
else {
logger.error(__('The selected provisioning profile "%s (%s)" is most likely not a valid %s provisioning profile.', pp.name, pp.uuid, targetName));
}
} else {
logger.error(__('The selected provisioning profile doesn\'t appear to be a %s provisioning profile or match the signing identity.', targetName));
}
logger.error(__('Please ensure you are using a valid %s provisioning that is linked to the signing identity, then try again.', targetName));
} else {
logger.info(__('Packaging complete'));
logger.info(__('Package location: %s', ipaFile.cyan));
}
callback();
});
}
};

0 comments on commit 5ba12ba

Please sign in to comment.