cargo-xcodebuild 0.1.0

Helps cargo build and run apps for iOS
use anyhow::Context;

mod cargo;
mod devices;
mod source;
mod teams;
mod toml;
mod xcodebuild;
mod xcodegen;

fn print_help() {
    println!(
        r#"cargo-xcodebuild
Helps cargo build and run apps for iOS

USAGE:
    cargo xcodebuild [SUBCOMMAND]

SUBCOMMAND:
    check, c     Checks that the current package builds without creating xcodeproject
    build, b     Compiles the current package and create xcodeproject
    run, r       Run a project on device or simulator
    generate, g  Generate xcodeproject without building it
    open, o      Open generated project with Xcode
    devices, d   List of booted simulator and connected devices
    teams, t     List of signing teams
    boot [id]    Boot a simulator with specific device id
"#
    );
}

#[cfg(not(target_os = "macos"))]
fn main() {
    compile_error!("Unfortunately, only MacOS is supported.");
}

#[cfg(target_os = "macos")]
fn main() -> anyhow::Result<()> {
    env_logger::try_init().with_context(|| "Failed to init env_logger".to_string())?;

    let args = std::env::args();
    let cmd = cargo_subcommand::Subcommand::new(args, "xcodebuild", |_, _| Ok(false));
    if cmd.is_err() {
        print_help();
        std::process::exit(0);
    }
    let cmd = cmd?;
    let mut xcode_build = xcodebuild::Xcodebuild::new(cmd.manifest(), cmd.target_dir())?;
    let build_type = match *cmd.profile() {
        cargo_subcommand::Profile::Dev => crate::xcodebuild::BuildType::Debug,
        cargo_subcommand::Profile::Release => crate::xcodebuild::BuildType::Release,
        cargo_subcommand::Profile::Custom(ref str) => {
            log::warn!("Custrom Profile: `{}`. Return debug build type", str);
            crate::xcodebuild::BuildType::Debug
        }
    };

    match cmd.cmd() {
        "check" | "c" => {
            xcode_build.check(cmd.args())?;
        }
        "build" | "b" => {
            xcode_build.build(cmd.args(), build_type)?;
        }
        "run" | "r" => {
            xcode_build.build(cmd.args(), build_type)?;
            xcode_build.run(build_type)?;
        }
        "generate" | "g" => {
            xcode_build.generate_project()?;
        }
        "devices" | "d" => {
            let simulators = xcodebuild::Xcodebuild::get_simulator_device_list()?;
            println!("Booted simulators: ");
            for device in simulators {
                if device.state == crate::devices::DeviceState::Booted {
                    println!("{:?}", device);
                }
            }

            let devices = md::get_device_list();
            println!("Connected devices: {}", devices.len());
            for device in devices {
                println!("{:?}", device);
            }
        }
        "teams" | "t" => {
            println!("Signing teams:");
            let teams = teams::find_development_teams();
            for t in teams {
                println!("{:?}", t);
            }
        }
        "boot" => {
            if let Some(arg) = cmd.args().get(0) {
                xcode_build.boot_simulator(arg)?;
            } else {
                println!("Simulator device id is required. List of avaliable devices:");
                let devices = xcodebuild::Xcodebuild::get_simulator_device_list()?;
                for d in devices {
                    println!("{:?}", d)
                }
                std::process::exit(1);
            }
        }
        "open" | "o" => xcode_build.open_xcode()?,
        "--help" => {
            if let Some(arg) = cmd.args().get(0) {
                match &**arg {
                    "build" | "b" | "check" | "c" | "run" | "r" | "test" | "t" | "doc" => {
                        cargo::run_cargo_subcommand(&cmd)?;
                    }
                    _ => print_help(),
                }
            } else {
                print_help();
            }
        }
        _ => print_help(),
    }

    Ok(())
}