solverforge-cli 2.2.2

CLI for scaffolding and managing SolverForge constraint solver projects
use std::path::Path;
use std::process::Command;

use crate::app_spec;
use crate::error::{CliError, CliResult};
use crate::output;

pub fn run(port: u16, debug: bool) -> CliResult {
    if is_cli_shell()? {
        return Err(CliError::with_hint(
            "`solverforge server` is not available for CLI-shell projects",
            "run the generated command-line app with `cargo run -- demo-data`",
        ));
    }

    let mode = if debug { "debug" } else { "release" };

    output::print_status("start", &format!("SolverForge server ({})", mode));

    if debug {
        output::print_dim("  Compiling in debug mode... (this may take a moment on first run)");
    } else {
        output::print_dim("  Compiling in release mode... (this may take a minute on first run)");
    }

    let mut args = vec!["run"];
    if !debug {
        args.push("--release");
    }

    // Set PORT env var for the server to pick up
    let status = Command::new("cargo")
        .args(&args)
        .env("PORT", port.to_string())
        .status()
        .map_err(|e| CliError::IoError {
            context: "failed to run cargo".to_string(),
            source: e,
        })?;

    if status.success() {
        Ok(())
    } else {
        Err(CliError::SubprocessFailed {
            command: format!("cargo run --{}", mode),
        })
    }
}

fn is_cli_shell() -> CliResult<bool> {
    if !Path::new("solverforge.app.toml").exists() {
        return Ok(false);
    }
    let spec = app_spec::load()?;
    Ok(spec.app.shell == "cli")
}