loveletter 0.2.0

🐟 ← 💌 ← 📎 ← 💌 ← ðŸĶĒ
Documentation
use std::fs;
use std::path::{Path, PathBuf};
use log::debug;

use anyhow::Result;
use xshell::{cmd, Shell};
use email_address::EmailAddress;

pub struct Repo {
    prefix: PathBuf,
    sh: Shell,
}

impl Repo {
    pub fn init<P: AsRef<Path>>(prefix: P) -> Result<Repo> {
        let prefix = prefix.as_ref().to_path_buf();
        let sh = Shell::new()?;
        sh.change_dir(&prefix);
        cmd!(sh, "git init").run()?;
        Ok(Repo { prefix, sh })
    }

    pub fn load<P: AsRef<Path>>(prefix: P) -> Result<Repo> {
        debug!("loading git repository from {}...", prefix.as_ref().display());
        let sh = Shell::new()?;
        sh.change_dir(&prefix);
        debug!("git repository {} loaded", fs::canonicalize(&prefix)?.display());
        Ok(Repo { 
            prefix: prefix.as_ref().to_path_buf(),
            sh,
        })
    }

    pub fn add<P: AsRef<Path>>(&self, spec: P) -> Result<()> {
        let spec = spec.as_ref();
        let spec = match spec.starts_with(&self.prefix) {
            true => spec.strip_prefix(&self.prefix)?.to_path_buf(),
            false => spec.to_path_buf(),
        };

        let spec = spec
            .into_os_string()
            .into_string()
            .unwrap();
        cmd!(self.sh, "git add {spec}").run()?;
        Ok(())
    }

    pub fn commit(&self, msg: &str, author: Option<EmailAddress>) -> Result<()> {
        match author {
            Some(author) => {
                let author = author.to_string();
                cmd!(self.sh, "git commit --message {msg} --author {author}").run()?;
            },
            None => cmd!(self.sh, "git commit --message {msg}").run()?,
        }
        
        Ok(())
    }

    pub fn push(&self) -> Result<()> {
        cmd!(self.sh, "git push").run()?;
        Ok(())
    }

    pub fn is_clean(&self) -> Result<bool> {
        let stdout = cmd!(self.sh, "git status --short").read()?;
        Ok(stdout.is_empty())
    }
}