bawa 0.1.0

A TUI game save organizer
Documentation
use anyhow::{bail, Result};
use std::{
    fs,
    io::Write,
    path::{Path, PathBuf},
};

const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");

pub fn get_state_dir() -> Result<PathBuf> {
    #[cfg(target_os = "linux")]
    let state_dir = dirs::state_dir().or_else(dirs::data_dir);

    #[cfg(not(target_os = "linux"))]
    let state_dir = dirs::data_dir();

    let path = match state_dir {
        Some(path) => path.join(PACKAGE_NAME),
        None => bail!("Couldn't find state directory"),
    };

    if !path.exists() {
        std::fs::create_dir_all(&path)?;
    }

    Ok(path)
}

pub fn get_config_dir() -> Result<PathBuf> {
    let path = match dirs::config_dir() {
        Some(path) => path.join(PACKAGE_NAME),
        None => bail!("Couldn't find config directory"),
    };

    Ok(path)
}

pub fn validate_name(path: &mut PathBuf) {
    while path.exists() {
        path.set_file_name(format!(
            "{} (dup){}",
            path.file_stem().unwrap().to_string_lossy(),
            path.extension()
                .map_or(String::new(), |ext| format!(".{}", ext.to_string_lossy()))
        ));
    }
}

pub fn check_for_dup(path: &Path) -> Result<()> {
    if path.exists() {
        Err(anyhow::anyhow!(
            "A {} with the name {:?} already exists.",
            if path.is_dir() { "directory" } else { "file" },
            path.file_name().unwrap()
        ))
    } else {
        Ok(())
    }
}

pub fn rename(from: &Path, to: &Path) -> Result<()> {
    check_for_dup(to)?;
    Ok(fs::rename(from, to)?)
}

pub fn get_relative_path(base: &Path, path: &Path) -> Result<PathBuf> {
    Ok(path.strip_prefix(base)?.to_owned())
}

pub fn write_atomic(path: &Path, content: &[u8]) -> Result<()> {
    let mut tmp = tempfile::Builder::new()
        .prefix(path.file_name().unwrap())
        .tempfile_in(get_state_dir()?)?;
    tmp.write_all(content)?;

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        if let Ok(meta) = path.metadata() {
            let mode = meta.permissions().mode();
            tmp.as_file()
                .set_permissions(fs::Permissions::from_mode(mode))?;
        }
    }

    tmp.persist(path)?;
    Ok(())
}