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

refactor!: Consistent app template/Xcode project name #1485

Merged
merged 8 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
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
33 changes: 7 additions & 26 deletions lib/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,39 +81,20 @@ class Api {

setupEvents(events);

let xcodeProjDir;
let xcodeCordovaProj;

try {
const xcodeProjDir_array = fs.readdirSync(this.root).filter(e => e.match(/\.xcodeproj$/i));
if (xcodeProjDir_array.length > 1) {
for (let x = 0; x < xcodeProjDir_array.length; x++) {
if (xcodeProjDir_array[x].substring(0, 2) === '._') {
xcodeProjDir_array.splice(x, 1);
}
}
}
xcodeProjDir = xcodeProjDir_array[0];

if (!xcodeProjDir) {
throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`);
}

const cordovaProjName = xcodeProjDir.substring(xcodeProjDir.lastIndexOf(path.sep) + 1, xcodeProjDir.indexOf('.xcodeproj'));
xcodeCordovaProj = path.join(this.root, cordovaProjName);
} catch (e) {
throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`);
const xcodeProjDir = path.join(this.root, 'App.xcodeproj');
if (!fs.existsSync(xcodeProjDir)) {
throw new CordovaError(`The provided path "${this.root}" is not an up-to-date Cordova iOS project.`);
}

this.locations = {
root: this.root,
www: path.join(this.root, 'www'),
platformWww: path.join(this.root, 'platform_www'),
configXml: path.join(xcodeCordovaProj, 'config.xml'),
configXml: path.join(this.root, 'App', 'config.xml'),
defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
pbxproj: path.join(this.root, xcodeProjDir, 'project.pbxproj'),
xcodeProjDir: path.join(this.root, xcodeProjDir),
xcodeCordovaProj
pbxproj: path.join(xcodeProjDir, 'project.pbxproj'),
xcodeProjDir,
xcodeCordovaProj: path.join(this.root, 'App')
};
}

Expand Down
18 changes: 6 additions & 12 deletions lib/Podfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ function Podfile (podFilePath, projectName, minDeploymentTarget) {
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');
Expand Down Expand Up @@ -168,18 +164,16 @@ Podfile.prototype.escapeSingleQuotes = function (string) {
};

Podfile.prototype.getTemplate = function () {
// Escaping possible ' in the project name
const projectName = this.escapeSingleQuotes(this.projectName);
return util.format(
'# DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
'%s\n' +
'platform :ios, \'%s\'\n' +
'%s\n' +
'target \'%s\' do\n' +
'\tproject \'%s.xcodeproj\'\n' +
'target \'App\' do\n' +
'\tproject \'App.xcodeproj\'\n' +
'%s\n' +
'end\n',
this.sourceToken, this.minDeploymentTarget, this.declarationToken, projectName, projectName, this.podToken);
this.sourceToken, this.minDeploymentTarget, this.declarationToken, this.podToken);
};

Podfile.prototype.addSpec = function (name, spec) {
Expand Down Expand Up @@ -361,10 +355,10 @@ Podfile.prototype.before_install = function (toolOptions) {
// Template tokens in order: project name, project name, debug | release
const template =
'// DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
'#include "Pods/Target Support Files/Pods-%s/Pods-%s.%s.xcconfig"';
'#include "Pods/Target Support Files/Pods-App/Pods-App.%s.xcconfig"';

const debugContents = util.format(template, this.projectName, this.projectName, 'debug');
const releaseContents = util.format(template, this.projectName, this.projectName, 'release');
const debugContents = util.format(template, 'debug');
const releaseContents = util.format(template, 'release');

const debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig');
const releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig');
Expand Down
75 changes: 30 additions & 45 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,11 @@ const buildFlagMatchers = {
* a project path and name
*
* @param {*} projectPath
* @param {*} projectName
*/
function createProjectObject (projectPath, projectName) {
function createProjectObject (projectPath) {
const locations = {
root: projectPath,
pbxproj: path.join(projectPath, `${projectName}.xcodeproj`, 'project.pbxproj')
pbxproj: path.join(projectPath, 'App.xcodeproj', 'project.pbxproj')
};

return projectFile.parse(locations);
Expand Down Expand Up @@ -103,7 +102,6 @@ function getDefaultSimulatorTarget () {
module.exports.run = function (buildOpts) {
const projectPath = this.root;
let emulatorTarget = 'iOS Device';
let projectName = '';

buildOpts = buildOpts || {};

Expand Down Expand Up @@ -180,9 +178,7 @@ module.exports.run = function (buildOpts) {
}
})
.then(() => check_reqs.run())
.then(() => findXCodeProjectIn(projectPath))
.then(name => {
projectName = name;
.then(() => {
let extraConfig = '';
if (buildOpts.codeSignIdentity) {
extraConfig += `CODE_SIGN_IDENTITY = ${buildOpts.codeSignIdentity}\n`;
Expand All @@ -201,7 +197,7 @@ module.exports.run = function (buildOpts) {
}

function writeCodeSignStyle (value) {
const project = createProjectObject(projectPath, projectName);
const project = createProjectObject(projectPath);

events.emit('verbose', `Set CODE_SIGN_STYLE Build Property to ${value}.`);
project.xcode.updateBuildProperty('CODE_SIGN_STYLE', value);
Expand All @@ -223,7 +219,7 @@ module.exports.run = function (buildOpts) {
}).then(() => {
const configuration = buildOpts.release ? 'Release' : 'Debug';

events.emit('log', `Building project: ${path.join(projectPath, `${projectName}.xcworkspace`)}`);
events.emit('log', `Building project: ${path.join(projectPath, 'App.xcworkspace')}`);
events.emit('log', `\tConfiguration: ${configuration}`);
events.emit('log', `\tPlatform: ${buildOpts.device ? 'device' : 'emulator'}`);
events.emit('log', `\tTarget: ${emulatorTarget}`);
Expand All @@ -233,14 +229,14 @@ module.exports.run = function (buildOpts) {
// remove the build output folder before building
fs.rmSync(buildOutputDir, { recursive: true, force: true });

const xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, emulatorTarget, buildOpts);
const xcodebuildArgs = getXcodeBuildArgs(projectPath, configuration, emulatorTarget, buildOpts);
return execa('xcodebuild', xcodebuildArgs, { cwd: projectPath, stdio: 'inherit' });
}).then(() => {
if (!buildOpts.device || buildOpts.catalyst || buildOpts.noSign) {
return;
}

const project = createProjectObject(projectPath, projectName);
const project = createProjectObject(projectPath);
const bundleIdentifier = project.getPackageName();
const exportOptions = { ...buildOpts.exportOptions, compileBitcode: false, method: 'development' };

Expand Down Expand Up @@ -287,7 +283,7 @@ module.exports.run = function (buildOpts) {
}

function packageArchive () {
const xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath, buildOpts);
const xcodearchiveArgs = getXcodeArchiveArgs(projectPath, buildOutputDir, exportOptionsPath, buildOpts);
return execa('xcodebuild', xcodearchiveArgs, { cwd: projectPath, stdio: 'inherit' });
}

Expand All @@ -298,38 +294,15 @@ module.exports.run = function (buildOpts) {
.then(() => {}); // resolve to undefined
};

/**
* 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);
const xcodeProjFiles = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');

if (xcodeProjFiles.length === 0) {
return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
}
if (xcodeProjFiles.length > 1) {
events.emit('warn', `Found multiple .xcodeproj directories in \n${projectPath}\nUsing first one`);
}

const projectName = path.basename(xcodeProjFiles[0], '.xcodeproj');
return Promise.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 {String} emulatorTarget Target for emulator (rather than default)
* @param {Object} buildConfig The build configuration options
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTarget, buildConfig = {}) {
function getXcodeBuildArgs (projectPath, configuration, emulatorTarget, buildConfig = {}) {
let options;
let buildActions;
let settings;
Expand All @@ -349,11 +322,11 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar

if (buildConfig.device && !buildConfig.catalyst) {
options = [
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
'-workspace', customArgs.workspace || 'App.xcworkspace',
'-scheme', customArgs.scheme || 'App',
'-configuration', customArgs.configuration || configuration,
'-destination', customArgs.destination || 'generic/platform=iOS',
'-archivePath', customArgs.archivePath || `${projectName}.xcarchive`
'-archivePath', customArgs.archivePath || 'App.xcarchive'
];
buildActions = ['archive'];
settings = [];
Expand Down Expand Up @@ -386,8 +359,8 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
}
} else { // emulator
options = [
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
'-workspace', customArgs.workspace || 'App.xcworkspace',
'-scheme', customArgs.scheme || 'App',
'-configuration', customArgs.configuration || configuration
];

Expand Down Expand Up @@ -425,15 +398,27 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar

/**
* 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 {Object} buildConfig Build configuration options
* @return {Array} Array of arguments that could be passed directly to spawn method
*/
function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath, buildConfig = {}) {
function getXcodeArchiveArgs (projectPath, outputPath, exportOptionsPath, buildConfig = {}) {
const options = [];
const buildFlags = buildConfig.buildFlag;
const customArgs = {};
customArgs.otherFlags = [];

if (buildFlags) {
if (typeof buildFlags === 'string' || buildFlags instanceof String) {
parseBuildFlag(buildFlags, customArgs);
} else { // buildFlags is an Array of strings
buildFlags.forEach(flag => {
parseBuildFlag(flag, customArgs);
});
}
}

if (buildConfig.automaticProvisioning) {
options.push('-allowProvisioningUpdates');
Expand All @@ -450,10 +435,10 @@ function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOption

return [
'-exportArchive',
'-archivePath', `${projectName}.xcarchive`,
'-archivePath', customArgs.archivePath || 'App.xcarchive',
'-exportOptionsPlist', exportOptionsPath,
'-exportPath', outputPath
].concat(options);
].concat(options).concat(customArgs.otherFlags);
}

function parseBuildFlag (buildFlag, args) {
Expand Down
10 changes: 2 additions & 8 deletions lib/clean.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,15 @@
const path = require('node:path');
const fs = require('node:fs');
const execa = require('execa');
const { CordovaError } = require('cordova-common');

module.exports.run = function () {
const projectPath = this.root;
const projectName = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');

if (!projectName) {
return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
}

const xcodebuildClean = configName => {
return execa(
'xcodebuild',
['-project', projectName, '-configuration', configName, '-alltargets', 'clean'],
{ cwd: projectPath, stdio: 'inherit' }
['-project', 'App.xcodeproj', '-configuration', configName, '-alltargets', 'clean'],
{ cwd: this.root, stdio: 'inherit' }
);
};

Expand Down
Loading