mntn 3.2.3

A Rust-based command-line tool for dotfiles management with profiles.
Documentation
use crate::cli::GitArgs;
use crate::commands::core::{Command, CommandExecutor};
use crate::utils::paths::get_mntn_dir;
use crate::utils::system::run_cmd;
use anyhow::Result;
use anyhow::bail;
use std::fs;
use std::path::Path;
use std::process::{Command as ProcessCommand, Stdio};

struct GitPassthroughTask {
    args: Vec<String>,
}

impl GitPassthroughTask {
    fn new(args: Vec<String>) -> Self {
        Self { args }
    }
}

impl Command for GitPassthroughTask {
    fn name(&self) -> &str {
        "Git"
    }

    fn execute(&mut self) -> Result<()> {
        let args = std::mem::take(&mut self.args);
        run_git_passthrough(args)
    }
}

pub(crate) fn run(args: GitArgs) {
    CommandExecutor::run(&mut GitPassthroughTask::new(args.args));
}

fn run_git_passthrough(args: Vec<String>) -> Result<()> {
    let mntn_dir = get_mntn_dir();
    ensure_git_repo(&mntn_dir)?;
    let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
    run_cmd_passthrough("git", &args_ref, Some(&mntn_dir))?;
    Ok(())
}

pub(crate) fn run_cmd_passthrough(cmd: &str, args: &[&str], dir: Option<&Path>) -> Result<()> {
    let mut command = ProcessCommand::new(cmd);
    command
        .args(args)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit());

    if let Some(d) = dir {
        command.current_dir(d);
    }

    let status = command.status()?;
    if !status.success() {
        bail!("{} exited with status {}", cmd, status);
    }

    Ok(())
}

pub(crate) fn ensure_git_repo(mntn_dir: &Path) -> Result<()> {
    if !mntn_dir.join(".git").exists() {
        bail!("No git repository found in ~/.mntn. Run 'mntn backup' to initialize it.");
    }

    ensure_gitignore_exists(mntn_dir)?;
    Ok(())
}

pub(crate) fn init_repo_if_missing(mntn_dir: &Path) -> Result<()> {
    if mntn_dir.join(".git").exists() {
        ensure_gitignore_exists(mntn_dir)?;
        return Ok(());
    }

    println!("Initializing git repository in {}", mntn_dir.display());
    run_cmd("git", &["init"], Some(mntn_dir))?;
    run_cmd("git", &["branch", "-M", "main"], Some(mntn_dir))?;
    println!("Git repository initialized");
    ensure_gitignore_exists(mntn_dir)?;
    Ok(())
}

fn ensure_gitignore_exists(mntn_dir: &Path) -> Result<()> {
    let gitignore_path = mntn_dir.join(".gitignore");
    if !gitignore_path.exists() {
        let default_gitignore = "# mntn
.active-profile

# log files
*.log

# temporary files
.DS_Store
Thumbs.db

# os generated files
*~
*.swp
*.swo
";
        fs::write(&gitignore_path, default_gitignore)?;
        println!("Created default .gitignore");
    }
    Ok(())
}