magg 0.4.4

Opinionated tools for Rust devs
Documentation
use crate::errors::{
    MaggError, Result, err_execute_command, err_obtain_output, err_read_file, err_spawn_command,
};
use std::io::{self, Write};
use std::path::Path;

/// Name of this crate.
pub const CREATE_NAME: &str = env!("CARGO_PKG_NAME");

/// Version of this crate.
pub const CREATE_VERSION: &str = env!("CARGO_PKG_VERSION");

/// Separator line.
pub const SEPARATOR_LINE: &str =
    "────────────────────────────────────────────────────────────────────────────────";

pub fn read_file(file_name: impl AsRef<Path>) -> Result<String> {
    let path = file_name.as_ref();
    std::fs::read_to_string(path).map_err(|e| err_read_file(path, e))
}

pub fn write_file(file_name: impl AsRef<Path>, contents: &str) -> Result<()> {
    let file_path = file_name.as_ref();
    let parent = file_path.parent().ok_or_else(|| {
        MaggError::new(format!(
            "failed to retrieve path for: {}",
            file_path.display()
        ))
    })?;
    std::fs::create_dir_all(parent).map_err(|e| {
        MaggError::new(format!(
            "failed to create paths for: {}, reason: {}",
            file_path.display(),
            e
        ))
    })?;
    std::fs::write(file_path, contents).map_err(|e| {
        MaggError::new(format!(
            "failed to write file {}, reason: {}",
            file_path.display(),
            e
        ))
    })
}

pub fn parse_toml(file_name: impl AsRef<Path>) -> Result<toml::Value> {
    toml::from_str(&read_file(file_name)?).map_err(|e| MaggError::new(e.to_string()))
}

pub fn get_package_name(parsed: &toml::Value) -> &str {
    parsed["package"]["name"]
        .as_str()
        .expect("package.name not found in Cargo.toml")
}
pub fn get_repository(parsed: &toml::Value) -> &str {
    parsed["package"]["repository"]
        .as_str()
        .expect("package.repository not found in Cargo.toml")
}

pub fn step_progress() {
    print!("·");
    io::stdout().flush().unwrap();
}

/// Executes a command with arguments and returns the content od stdout.
pub fn execute_command(verbose: bool, program: &str, args: &[&str], dir: &str) -> Result<String> {
    if verbose {
        println!("{} {}", program, args.join(" "));
    } else {
        step_progress();
    }
    let mut command = std::process::Command::new(program);
    let child = command
        .args(args)
        .current_dir(dir)
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()
        .map_err(|e| err_spawn_command(program, e.to_string()))?;
    let output = child
        .wait_with_output()
        .map_err(|e| err_obtain_output(e.to_string()))?;
    let stdout = String::from_utf8_lossy(&output.stdout).to_string();
    let stderr = String::from_utf8_lossy(&output.stderr).to_string();
    let status = output.status;
    if status.success() {
        Ok(stdout)
    } else {
        Err(err_execute_command(status, stdout, stderr))
    }
}

pub fn parse_columns(input: &str, col_count: usize) -> Result<Vec<Vec<String>>> {
    let mut rows = vec![];
    for mut line in input.lines().map(str::trim) {
        if line.starts_with('\"') {
            line = line.strip_prefix("\"").unwrap();
        }
        if line.starts_with('\'') {
            line = line.strip_prefix("'").unwrap();
        }
        if line.ends_with('\"') {
            line = line.strip_suffix("\"").unwrap();
        }
        if line.ends_with('\'') {
            line = line.strip_suffix("'").unwrap();
        }
        line = line.trim();
        if !line.is_empty() {
            let columns = line
                .split(" ||| ")
                .map(ToString::to_string)
                .collect::<Vec<String>>();
            if columns.len() != col_count {
                return Err(MaggError::new(format!(
                    "invalid number of columns, expected: {col_count}, actual: {}",
                    columns.len()
                )));
            }
            rows.push(columns);
        }
    }
    Ok(rows)
}