Skip to content

Instantly share code, notes, and snippets.

@thomasvidas
Created October 27, 2021 01:46
Show Gist options
  • Save thomasvidas/1bdc37c1220f20ab3bdc18a224af0778 to your computer and use it in GitHub Desktop.
Save thomasvidas/1bdc37c1220f20ab3bdc18a224af0778 to your computer and use it in GitHub Desktop.
Typescript wrapper for xcodebuild
import { execSync, spawn, SpawnOptions } from 'child_process'
type XCodebuildOptions = {
/**
* Build the project specified by projectname.
* Required if there are multiple project files in the same directory.
*/
project: string,
/**
* Build the target specified by targetname.
*/
target: string,
/**
* Build all the targets in the specified project.
*/
alltargets: boolean,
/**
* Build the workspace specified by workspacename.
*/
workspace: string,
/**
* Build the scheme specified by schemename.
* Required if building aworkspace.
*/
scheme: string,
/**
* Use the build configuration specified by "configurationname" when building each target.
*/
configuration: string,
/**
* Use the architecture specified by architecture when building each target.
*/
arch: string,
/**
* Build an Xcode project or workspace against the specified SDK,
* using build tools appropriate for that SDK. The argument may be an
* absolute path to an SDK, or the canonical name of an SDK.
*/
sdk: string,
/**
* Lists all available SDKs that Xcode knows about, including their
* canonical names suitable for use with -sdk. Does not initiate a build.
*/
showsdks: boolean,
/**
* Lists the targets and configurations in a project, or the schemes
* in a workspace. Does not initiate a build.
*/
list: boolean,
}
class XCodebuild {
private commands: string[]
constructor() {
this.commands = []
}
/**
* Archive a scheme from the build root (SYMROOT). This requires specifying a scheme.
*/
public archive(): XCodebuild {
this.commands.push('archive')
return this;
}
/**
* Build the target in the build root (SYMROOT). This is the default build action.
*/
public build(): XCodebuild {
this.commands.push('build')
return this;
}
/**
* Test a scheme from the build root (SYMROOT). This requires specifying a scheme.
*/
public test(): XCodebuild {
this.commands.push('test')
return this;
}
/**
* Copy the source of the project to the source root (SRCROOT).
*/
public installsrc(): XCodebuild {
this.commands.push('installsrc')
return this;
}
/**
* Build the target and install it into the target's installation directory in the distribution root
*/
public install(): XCodebuild {
this.commands.push('install')
return this;
}
/**
* Remove build products and intermediate files from the build root (SYMROOT).
*/
public clean(): XCodebuild {
this.commands.push('clean')
return this;
}
/**
* Execute the xcodebuild command. Will execute based on the order of the functions.
* @param options CLI options for xcodebuild
* @param spawnOptions Options to pass into child_process.spawn()
*/
public run(options: Partial<XCodebuildOptions>, spawnOptions: SpawnOptions): Promise<void> {
let flags = "";
(Object.keys(options) as Array<keyof XCodebuildOptions>).forEach(key => {
const value = options[key];
if (typeof options[key] === 'boolean') {
if (value) {
flags += `-${key} `
}
} else {
flags += `-${key} ${value} `
}
})
flags = flags.trim();
let action = "";
this.commands.forEach(cmd => action += `${cmd} `)
action = action.trim();
const command = `xcodebuild ${flags} ${action}`;
return new Promise((resolve, reject) => {
const p = spawn(command, spawnOptions)
p.on('close', () => resolve())
p.on('error', err => reject(err))
})
}
}
export const xcodebuild = new XCodebuild()
/**
* Silently runs a POSIX command synchronously to check if "xcodebuild" is in your path.
* @returns true if "xcodebuild" is in your path
*/
export const isXcodeAvailable = (): boolean => {
// Auto-fail if running on Windows or WSL
if(process.platform === 'win32') {
return false
}
// POSIX compatible command that checks if xcodebuild exists in path
const exists = `
#!/bin/sh
if command -v xcodebuild >/dev/null; then
echo true
else
echo false
fi
`.trim();
try {
const stdout = execSync(exists, { stdio: [] })
return JSON.parse(stdout.toString().trim())
} catch (err) {
// command failed or couldn't parse output so probably can't use xcodebuild
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment