import { execute, type ExecuteOptions } from './index.js';
import type { XcodebuildResult, XcodebuildListOutput } from '../types/xcodebuild.js';
import { XCODEBUILD_TIMEOUTS } from '../types/xcodebuild.js';
import {
generateResultBundlePath,
cleanupResultBundle,
parseResultBundle,
} from '../utils/result-bundle-parser.js';
export interface XcodebuildOptions extends ExecuteOptions {
/**
* Path for the result bundle. If not specified, a temporary path is generated.
* Temporary bundles are auto-cleaned after parsing.
*/
resultBundlePath?: string;
/**
* If true, keep the result bundle after parsing (only applies to auto-generated paths).
*/
keepResultBundle?: boolean;
}
/**
* Execute an xcodebuild command.
*/
export function xcodebuild(
args: string[],
options: XcodebuildOptions = {}
): XcodebuildResult {
const result = execute('xcodebuild', args, {
cwd: options.cwd,
env: options.env,
timeout: options.timeout ?? XCODEBUILD_TIMEOUTS.build,
});
return {
...result,
};
}
/**
* Execute an xcodebuild action that produces a result bundle (build, test).
* The result bundle is parsed and included in the result.
*/
export function xcodebuildWithResultBundle(
action: 'build' | 'test' | 'build-for-testing' | 'test-without-building',
args: string[],
options: XcodebuildOptions = {}
): XcodebuildResult {
const isTemporary = !options.resultBundlePath;
const bundlePath = options.resultBundlePath ?? generateResultBundlePath();
// Insert -resultBundlePath after the action
const fullArgs = [action, '-resultBundlePath', bundlePath, ...args];
const result = execute('xcodebuild', fullArgs, {
cwd: options.cwd,
env: options.env,
timeout: options.timeout ?? (action.includes('test') ? XCODEBUILD_TIMEOUTS.test : XCODEBUILD_TIMEOUTS.build),
});
// Parse the result bundle
const resultBundle = parseResultBundle(bundlePath);
// Clean up temporary bundle
if (isTemporary && !options.keepResultBundle) {
cleanupResultBundle(bundlePath);
}
return {
...result,
resultBundle,
};
}
/**
* Execute xcodebuild -list to get schemes, targets, and configurations.
*/
export function xcodebuildList(
args: string[],
options: ExecuteOptions = {}
): XcodebuildListOutput {
const result = execute('xcodebuild', ['-list', '-json', ...args], {
cwd: options.cwd,
env: options.env,
timeout: options.timeout ?? XCODEBUILD_TIMEOUTS.list,
});
if (result.exitCode !== 0) {
throw new Error(`xcodebuild -list failed: ${result.stderr || result.stdout}`);
}
try {
return JSON.parse(result.stdout) as XcodebuildListOutput;
} catch {
throw new Error(`Failed to parse xcodebuild -list JSON output: ${result.stdout}`);
}
}
/**
* Execute xcodebuild -showBuildSettings.
* Returns the raw output as a string (key-value format).
*/
export function xcodebuildShowBuildSettings(
args: string[],
options: ExecuteOptions = {}
): string {
const result = execute('xcodebuild', ['-showBuildSettings', ...args], {
cwd: options.cwd,
env: options.env,
timeout: options.timeout ?? XCODEBUILD_TIMEOUTS.showBuildSettings,
});
if (result.exitCode !== 0) {
throw new Error(`xcodebuild -showBuildSettings failed: ${result.stderr || result.stdout}`);
}
return result.stdout;
}
/**
* Execute xcodebuild clean.
*/
export function xcodebuildClean(
args: string[],
options: ExecuteOptions = {}
): XcodebuildResult {
const result = execute('xcodebuild', ['clean', ...args], {
cwd: options.cwd,
env: options.env,
timeout: options.timeout ?? XCODEBUILD_TIMEOUTS.clean,
});
return result;
}