bijux-cli 0.3.6

Command-line runtime for automation, plugin-driven tools, and interactive workflows with structured output.
Documentation
//! Product install command handler.

use std::env;
use std::io::IsTerminal;
use std::process::Command;

use anyhow::Result;
use serde_json::{json, Value};

use crate::contracts::{ColorMode, LogLevel, OutputFormat, PrettyMode};
use crate::features::install::{install_target_aliases, resolve_install_target, Ecosystem};
use crate::interface::cli::dispatch::AppRunResult;
use crate::interface::cli::parser::ParsedGlobalFlags;
use crate::shared::argv::{command_has_flag, command_positionals};
use crate::shared::output::{render_value, EmitterConfig};

fn default_output_format() -> OutputFormat {
    if std::io::stdout().is_terminal() {
        OutputFormat::Text
    } else {
        OutputFormat::Json
    }
}

fn emitter_config(flags: &ParsedGlobalFlags) -> EmitterConfig {
    EmitterConfig {
        format: flags.output_format.unwrap_or_else(default_output_format),
        pretty: !matches!(flags.pretty_mode, Some(PrettyMode::Compact)),
        color: flags.color_mode.unwrap_or(ColorMode::Auto),
        log_level: flags.log_level.unwrap_or(LogLevel::Info),
        quiet: flags.quiet,
        no_color: env::var_os("NO_COLOR").is_some(),
    }
}

fn with_trailing_newline(mut content: String) -> String {
    if !content.ends_with('\n') {
        content.push('\n');
    }
    content
}

fn render_machine_result(
    payload: &Value,
    cfg: EmitterConfig,
    exit_code: i32,
    quiet_success: bool,
) -> Result<AppRunResult> {
    if quiet_success && exit_code == 0 {
        return Ok(AppRunResult { exit_code, stdout: String::new(), stderr: String::new() });
    }
    let rendered = with_trailing_newline(render_value(payload, cfg)?);
    Ok(if exit_code == 0 {
        AppRunResult { exit_code, stdout: rendered, stderr: String::new() }
    } else {
        AppRunResult { exit_code, stdout: String::new(), stderr: rendered }
    })
}

fn install_command_for(package_name: &str, quiet: bool) -> Vec<String> {
    let mut command = vec!["cargo".to_string(), "install".to_string(), "--locked".to_string()];
    if quiet {
        command.push("--quiet".to_string());
    }
    command.push(package_name.to_string());
    command
}

struct SuccessPayload<'a> {
    requested_target: &'a str,
    canonical_target: &'a str,
    package_name: &'a str,
    executable_name: &'a str,
    dry_run: bool,
    command: &'a [String],
    stdout: &'a str,
    stderr: &'a str,
}

fn success_payload(args: SuccessPayload<'_>) -> Value {
    json!({
        "status": "ok",
        "requested_target": args.requested_target,
        "target": args.canonical_target,
        "installer": "cargo",
        "ecosystem": "cargo",
        "package": args.package_name,
        "executable": args.executable_name,
        "dry_run": args.dry_run,
        "command": args.command,
        "stdout": args.stdout,
        "stderr": args.stderr,
    })
}

fn error_payload(
    requested_target: &str,
    message: &str,
    exit_code: i32,
    command: Option<&[String]>,
    stdout: &str,
    stderr: &str,
) -> Value {
    json!({
        "status": "error",
        "code": exit_code,
        "requested_target": requested_target,
        "message": message,
        "installer": "cargo",
        "command": command,
        "stdout": stdout,
        "stderr": stderr,
        "supported_targets": install_target_aliases(),
    })
}

pub(crate) fn try_run(
    normalized_path: &[String],
    argv: &[String],
    global_flags: &ParsedGlobalFlags,
) -> Result<Option<AppRunResult>> {
    if !matches!(normalized_path, [command] if command == "install") {
        return Ok(None);
    }

    let cfg = emitter_config(global_flags);
    let requested_target =
        command_positionals(argv, &["install"]).first().cloned().unwrap_or_default();
    if requested_target.trim().is_empty() {
        let payload =
            error_payload("", "Missing argument: install target is required", 2, None, "", "");
        return Ok(Some(render_machine_result(&payload, cfg, 2, false)?));
    }

    let Some(target) = resolve_install_target(&requested_target) else {
        let payload = error_payload(
            &requested_target,
            &format!("Unknown install target: {requested_target}"),
            2,
            None,
            "",
            "",
        );
        return Ok(Some(render_machine_result(&payload, cfg, 2, false)?));
    };

    let command = install_command_for(&target.strategy.package_name, global_flags.quiet);
    let dry_run = command_has_flag(argv, "--dry-run");

    if dry_run {
        let payload = success_payload(SuccessPayload {
            requested_target: &requested_target,
            canonical_target: &target.target_name,
            package_name: &target.strategy.package_name,
            executable_name: &target.strategy.executable_name,
            dry_run: true,
            command: &command,
            stdout: "",
            stderr: "",
        });
        if cfg.format == OutputFormat::Text {
            return Ok(Some(AppRunResult {
                exit_code: 0,
                stdout: if global_flags.quiet {
                    String::new()
                } else {
                    with_trailing_newline(command.join(" "))
                },
                stderr: String::new(),
            }));
        }
        return Ok(Some(render_machine_result(&payload, cfg, 0, global_flags.quiet)?));
    }

    let output = match target.strategy.ecosystem {
        Ecosystem::Cargo => Command::new(&command[0]).args(&command[1..]).output(),
        Ecosystem::Pip => unreachable!("cargo-only install targets are supported"),
    };

    match output {
        Ok(output) => {
            let exit_code = output.status.code().unwrap_or(1);
            let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
            let stderr = String::from_utf8_lossy(&output.stderr).into_owned();

            if cfg.format == OutputFormat::Text {
                let text_stdout = if stdout.is_empty() && exit_code == 0 && stderr.is_empty() {
                    with_trailing_newline(format!(
                        "Installed `{}` with `cargo install --locked {}`.",
                        target.strategy.executable_name, target.strategy.package_name
                    ))
                } else {
                    stdout
                };
                return Ok(Some(AppRunResult {
                    exit_code,
                    stdout: if global_flags.quiet && exit_code == 0 {
                        String::new()
                    } else {
                        text_stdout
                    },
                    stderr,
                }));
            }

            let payload = if exit_code == 0 {
                success_payload(SuccessPayload {
                    requested_target: &requested_target,
                    canonical_target: &target.target_name,
                    package_name: &target.strategy.package_name,
                    executable_name: &target.strategy.executable_name,
                    dry_run: false,
                    command: &command,
                    stdout: &stdout,
                    stderr: &stderr,
                })
            } else {
                error_payload(
                    &requested_target,
                    &format!("cargo install failed for {}", target.strategy.package_name),
                    exit_code,
                    Some(&command),
                    &stdout,
                    &stderr,
                )
            };
            Ok(Some(render_machine_result(&payload, cfg, exit_code, global_flags.quiet)?))
        }
        Err(error) => {
            if cfg.format == OutputFormat::Text {
                return Ok(Some(AppRunResult {
                    exit_code: 1,
                    stdout: String::new(),
                    stderr: with_trailing_newline(format!(
                        "failed to start `cargo install --locked {}`: {error}",
                        target.strategy.package_name
                    )),
                }));
            }

            let payload = error_payload(
                &requested_target,
                &format!(
                    "failed to start cargo install for {}: {error}",
                    target.strategy.package_name
                ),
                1,
                Some(&command),
                "",
                "",
            );
            Ok(Some(render_machine_result(&payload, cfg, 1, false)?))
        }
    }
}