Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use promise-based result for Cordova #66

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 124 additions & 119 deletions src/add-swift-support.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,146 +23,151 @@ const semver = require('semver');
const glob = require('glob');

module.exports = context => {
const projectRoot = context.opts.projectRoot;

// This script has to be executed depending on the command line arguments, not
// on the hook execution cycle.
if ((context.hook === 'after_platform_add' && context.cmdLine.includes('platform add')) ||
(context.hook === 'after_prepare' && context.cmdLine.includes('prepare')) ||
(context.hook === 'after_plugin_add' && context.cmdLine.includes('plugin add'))) {
getPlatformVersionsFromFileSystem(context, projectRoot).then(platformVersions => {
const IOS_MIN_DEPLOYMENT_TARGET = '7.0';
const platformPath = path.join(projectRoot, 'platforms', 'ios');
const config = getConfigParser(context, path.join(projectRoot, 'config.xml'));

let bridgingHeaderPath;
let bridgingHeaderContent;
let projectName;
let projectPath;
let pluginsPath;
let iosPlatformVersion;
let pbxprojPath;
let xcodeProject;

const COMMENT_KEY = /_comment$/;
let buildConfigs;
let buildConfig;
let configName;

platformVersions.forEach((platformVersion) => {
if (platformVersion.platform === 'ios') {
iosPlatformVersion = platformVersion.version;
}
});

if (!iosPlatformVersion) {
return;
}

projectName = config.name();
projectPath = path.join(platformPath, projectName);
pbxprojPath = path.join(platformPath, projectName + '.xcodeproj', 'project.pbxproj');
xcodeProject = xcode.project(pbxprojPath);
pluginsPath = path.join(projectPath, 'Plugins');

xcodeProject.parseSync();

bridgingHeaderPath = getBridgingHeaderPath(projectPath, iosPlatformVersion);

try {
fs.statSync(bridgingHeaderPath);
} catch (err) {
// If the bridging header doesn't exist, we create it with the minimum
// Cordova/CDV.h import.
bridgingHeaderContent = ['//',
'// Use this file to import your target\'s public headers that you would like to expose to Swift.',
'//',
'#import <Cordova/CDV.h>'];
fs.writeFileSync(bridgingHeaderPath, bridgingHeaderContent.join('\n'), { encoding: 'utf-8', flag: 'w' });
xcodeProject.addHeaderFile('Bridging-Header.h');
}

buildConfigs = xcodeProject.pbxXCBuildConfigurationSection();

const bridgingHeaderProperty = '"$(PROJECT_DIR)/$(PROJECT_NAME)' + bridgingHeaderPath.split(projectPath)[1] + '"';

for (configName in buildConfigs) {
if (!COMMENT_KEY.test(configName)) {
buildConfig = buildConfigs[configName];
if (xcodeProject.getBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', buildConfig.name) !== bridgingHeaderProperty) {
xcodeProject.updateBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', bridgingHeaderProperty, buildConfig.name);
console.log('Update IOS build setting SWIFT_OBJC_BRIDGING_HEADER to:', bridgingHeaderProperty, 'for build configuration', buildConfig.name);
return new Promise(resolve => {
const projectRoot = context.opts.projectRoot;

// This script has to be executed depending on the command line arguments, not
// on the hook execution cycle.
if ((context.hook === 'after_platform_add' && context.cmdLine.includes('platform add')) ||
(context.hook === 'after_prepare' && context.cmdLine.includes('prepare')) ||
(context.hook === 'after_plugin_add' && context.cmdLine.includes('plugin add'))) {
getPlatformVersionsFromFileSystem(context, projectRoot).then(platformVersions => {
const IOS_MIN_DEPLOYMENT_TARGET = '7.0';
const platformPath = path.join(projectRoot, 'platforms', 'ios');
const config = getConfigParser(context, path.join(projectRoot, 'config.xml'));

let bridgingHeaderPath;
let bridgingHeaderContent;
let projectName;
let projectPath;
let pluginsPath;
let iosPlatformVersion;
let pbxprojPath;
let xcodeProject;

const COMMENT_KEY = /_comment$/;
let buildConfigs;
let buildConfig;
let configName;

platformVersions.forEach((platformVersion) => {
if (platformVersion.platform === 'ios') {
iosPlatformVersion = platformVersion.version;
}
}
}
});

// Look for any bridging header defined in the plugin
glob('**/*Bridging-Header*.h', { cwd: pluginsPath }, (error, files) => {
const bridgingHeader = path.basename(bridgingHeaderPath);
const headers = files.map((filePath) => path.basename(filePath));
if (!iosPlatformVersion) {
return;
}

// if other bridging headers are found, they are imported in the
// one already configured in the project.
let content = fs.readFileSync(bridgingHeaderPath, 'utf-8');
projectName = config.name();
projectPath = path.join(platformPath, projectName);
pbxprojPath = path.join(platformPath, projectName + '.xcodeproj', 'project.pbxproj');
xcodeProject = xcode.project(pbxprojPath);
pluginsPath = path.join(projectPath, 'Plugins');

xcodeProject.parseSync();

bridgingHeaderPath = getBridgingHeaderPath(projectPath, iosPlatformVersion);

try {
fs.statSync(bridgingHeaderPath);
} catch (err) {
// If the bridging header doesn't exist, we create it with the minimum
// Cordova/CDV.h import.
bridgingHeaderContent = ['//',
'// Use this file to import your target\'s public headers that you would like to expose to Swift.',
'//',
'#import <Cordova/CDV.h>'];
fs.writeFileSync(bridgingHeaderPath, bridgingHeaderContent.join('\n'), { encoding: 'utf-8', flag: 'w' });
xcodeProject.addHeaderFile('Bridging-Header.h');
}

if (error) throw new Error(error);
buildConfigs = xcodeProject.pbxXCBuildConfigurationSection();

headers.forEach((header) => {
if (header !== bridgingHeader && !~content.indexOf(header)) {
if (content.charAt(content.length - 1) !== '\n') {
content += '\n';
}
content += '#import "' + header + '"\n';
console.log('Importing', header, 'into', bridgingHeaderPath);
}
});
fs.writeFileSync(bridgingHeaderPath, content, 'utf-8');
const bridgingHeaderProperty = '"$(PROJECT_DIR)/$(PROJECT_NAME)' + bridgingHeaderPath.split(projectPath)[1] + '"';

for (configName in buildConfigs) {
if (!COMMENT_KEY.test(configName)) {
buildConfig = buildConfigs[configName];
if (parseFloat(xcodeProject.getBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', buildConfig.name)) < parseFloat(IOS_MIN_DEPLOYMENT_TARGET)) {
xcodeProject.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', IOS_MIN_DEPLOYMENT_TARGET, buildConfig.name);
console.log('Update IOS project deployment target to:', IOS_MIN_DEPLOYMENT_TARGET, 'for build configuration', buildConfig.name);
if (xcodeProject.getBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', buildConfig.name) !== bridgingHeaderProperty) {
xcodeProject.updateBuildProperty('SWIFT_OBJC_BRIDGING_HEADER', bridgingHeaderProperty, buildConfig.name);
console.log('Update IOS build setting SWIFT_OBJC_BRIDGING_HEADER to:', bridgingHeaderProperty, 'for build configuration', buildConfig.name);
}
}
}

if (xcodeProject.getBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', buildConfig.name) !== 'YES') {
xcodeProject.updateBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES', buildConfig.name);
console.log('Update IOS build setting ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to: YES', 'for build configuration', buildConfig.name);
}
// Look for any bridging header defined in the plugin
glob('**/*Bridging-Header*.h', { cwd: pluginsPath }, (error, files) => {
const bridgingHeader = path.basename(bridgingHeaderPath);
const headers = files.map((filePath) => path.basename(filePath));

if (xcodeProject.getBuildProperty('LD_RUNPATH_SEARCH_PATHS', buildConfig.name) !== '"@executable_path/Frameworks"') {
xcodeProject.updateBuildProperty('LD_RUNPATH_SEARCH_PATHS', '"@executable_path/Frameworks"', buildConfig.name);
console.log('Update IOS build setting LD_RUNPATH_SEARCH_PATHS to: @executable_path/Frameworks', 'for build configuration', buildConfig.name);
}
// if other bridging headers are found, they are imported in the
// one already configured in the project.
let content = fs.readFileSync(bridgingHeaderPath, 'utf-8');

if (error) throw new Error(error);

if (typeof xcodeProject.getBuildProperty('SWIFT_VERSION', buildConfig.name) === 'undefined') {
if (config.getPreference('UseLegacySwiftLanguageVersion', 'ios')) {
xcodeProject.updateBuildProperty('SWIFT_VERSION', '2.3', buildConfig.name);
console.log('Use legacy Swift language version', buildConfig.name);
} else if (config.getPreference('UseSwiftLanguageVersion', 'ios')) {
const swiftVersion = config.getPreference('UseSwiftLanguageVersion', 'ios');
xcodeProject.updateBuildProperty('SWIFT_VERSION', swiftVersion, buildConfig.name);
console.log('Use Swift language version', swiftVersion);
} else {
xcodeProject.updateBuildProperty('SWIFT_VERSION', '4.0', buildConfig.name);
console.log('Update SWIFT version to 4.0', buildConfig.name);
headers.forEach((header) => {
if (header !== bridgingHeader && !~content.indexOf(header)) {
if (content.charAt(content.length - 1) !== '\n') {
content += '\n';
}
content += '#import "' + header + '"\n';
console.log('Importing', header, 'into', bridgingHeaderPath);
}
});
fs.writeFileSync(bridgingHeaderPath, content, 'utf-8');

for (configName in buildConfigs) {
if (!COMMENT_KEY.test(configName)) {
buildConfig = buildConfigs[configName];
if (parseFloat(xcodeProject.getBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', buildConfig.name)) < parseFloat(IOS_MIN_DEPLOYMENT_TARGET)) {
xcodeProject.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', IOS_MIN_DEPLOYMENT_TARGET, buildConfig.name);
console.log('Update IOS project deployment target to:', IOS_MIN_DEPLOYMENT_TARGET, 'for build configuration', buildConfig.name);
}

if (xcodeProject.getBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', buildConfig.name) !== 'YES') {
xcodeProject.updateBuildProperty('ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES', 'YES', buildConfig.name);
console.log('Update IOS build setting ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to: YES', 'for build configuration', buildConfig.name);
}

if (xcodeProject.getBuildProperty('LD_RUNPATH_SEARCH_PATHS', buildConfig.name) !== '"@executable_path/Frameworks"') {
xcodeProject.updateBuildProperty('LD_RUNPATH_SEARCH_PATHS', '"@executable_path/Frameworks"', buildConfig.name);
console.log('Update IOS build setting LD_RUNPATH_SEARCH_PATHS to: @executable_path/Frameworks', 'for build configuration', buildConfig.name);
}

if (buildConfig.name === 'Debug') {
if (xcodeProject.getBuildProperty('SWIFT_OPTIMIZATION_LEVEL', buildConfig.name) !== '"-Onone"') {
xcodeProject.updateBuildProperty('SWIFT_OPTIMIZATION_LEVEL', '"-Onone"', buildConfig.name);
console.log('Update IOS build setting SWIFT_OPTIMIZATION_LEVEL to: -Onone', 'for build configuration', buildConfig.name);
if (typeof xcodeProject.getBuildProperty('SWIFT_VERSION', buildConfig.name) === 'undefined') {
if (config.getPreference('UseLegacySwiftLanguageVersion', 'ios')) {
xcodeProject.updateBuildProperty('SWIFT_VERSION', '2.3', buildConfig.name);
console.log('Use legacy Swift language version', buildConfig.name);
} else if (config.getPreference('UseSwiftLanguageVersion', 'ios')) {
const swiftVersion = config.getPreference('UseSwiftLanguageVersion', 'ios');
xcodeProject.updateBuildProperty('SWIFT_VERSION', swiftVersion, buildConfig.name);
console.log('Use Swift language version', swiftVersion);
} else {
xcodeProject.updateBuildProperty('SWIFT_VERSION', '4.0', buildConfig.name);
console.log('Update SWIFT version to 4.0', buildConfig.name);
}
}

if (buildConfig.name === 'Debug') {
if (xcodeProject.getBuildProperty('SWIFT_OPTIMIZATION_LEVEL', buildConfig.name) !== '"-Onone"') {
xcodeProject.updateBuildProperty('SWIFT_OPTIMIZATION_LEVEL', '"-Onone"', buildConfig.name);
console.log('Update IOS build setting SWIFT_OPTIMIZATION_LEVEL to: -Onone', 'for build configuration', buildConfig.name);
}
}
}
}
}

fs.writeFileSync(pbxprojPath, xcodeProject.writeSync());
fs.writeFileSync(pbxprojPath, xcodeProject.writeSync());
resolve();
});
});
});
}
} else {
resolve();
}
});
};

const getConfigParser = (context, configPath) => {
Expand Down