tracel-xtask 4.16.0

Reusable and Extensible xtask commands to manage repositories.
Documentation
use std::process::Command as StdCommand;

use crate::prelude::{Context, Environment, run_process};

#[tracel_xtask_macros::declare_command_args(None, DockerComposeSubCommand)]
pub struct DockerComposeCmdArgs {}

pub fn handle_command(
    args: DockerComposeCmdArgs,
    env: Environment,
    _ctx: Context,
) -> anyhow::Result<()> {
    match args.get_command() {
        DockerComposeSubCommand::Up => {
            up_docker_compose(&env, &args.project, args.build, args.services)
        }
        DockerComposeSubCommand::Down => down_docker_compose(&env, &args.project),
    }
}

fn get_config_filename(config: &str) -> String {
    format!("docker-compose.{config}.yml")
}

pub fn up_docker_compose(
    env: &Environment,
    project: &str,
    build: bool,
    services: Vec<String>,
) -> anyhow::Result<()> {
    let env_name = env.to_string();
    let project = format!("{project}-{env_name}");
    let config = get_config_filename(&env_name);
    let env_files = env.get_env_files();
    let mut args = vec!["compose", "-f", &config, "-p", &project];
    env_files.iter().for_each(|f| {
        let path = std::path::Path::new(f);
        if path.exists() {
            args.extend(vec!["--env-file", f]);
        }
    });
    args.extend(vec!["up", "-d"]);
    if build {
        args.extend(vec!["--build"]);
    }
    args.extend(services.iter().map(String::as_str));
    let result = run_process(
        "docker",
        &args,
        None,
        None,
        "Failed to execute 'docker compose' to start the container!",
    );
    if result.is_err() {
        run_process(
            "docker-compose",
            &args[1..],
            None,
            None,
            "Failed to execute 'docker compose' to start the container!",
        )
    } else {
        result
    }
}

pub fn down_docker_compose(env: &Environment, project: &str) -> anyhow::Result<()> {
    let env_name = env.to_string();
    let project = format!("{project}-{env_name}");
    let config = get_config_filename(&env_name);
    let env_files = env.get_env_files();
    let mut args = vec!["compose", "-f", &config, "-p", &project];
    env_files.iter().for_each(|f| {
        let path = std::path::Path::new(f);
        if path.exists() {
            args.extend(vec!["--env-file", f]);
        }
    });
    args.extend(vec!["down"]);
    let result = run_process(
        "docker",
        &args,
        None,
        None,
        "Failed to execute 'docker compose' to stop the container!",
    );
    if result.is_err() {
        run_process(
            "docker-compose",
            &args[1..],
            None,
            None,
            "Failed to execute 'docker compose' to stop the container!",
        )
    } else {
        result
    }
}

pub fn tail_container_command(container_name: &str) -> StdCommand {
    let mut command = StdCommand::new("docker");
    command.args(["logs", "-f", container_name]);
    command
}