aors 0.1.3

Useful rs tools for Advent of Code
Documentation
use std::ffi::OsStr;
use std::io::{ErrorKind, Write};
use std::{error::Error, process::Command};
use std::{fs, io};

const GITIGNORE: &str = "
# Eric Wastl wishes for users not to share their puzzle input
/inputs/*
/input_examples/*

# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk
";

pub fn init() -> Result<(), Box<dyn Error>> {
    cmd("cargo", &["init"]);
    cmd("cargo", &["add", "aors"]);
    fs::remove_file("src/main.rs")?;
    fs::remove_file(".gitignore")?;

    mkdir("inputs");
    mkdir("input_examples");
    mkdir("answers");
    mkdir("src/bin/helpers");

    touch(
        "src/bin/helpers/mod.rs",
        "",
        "failed to create helpers module",
    );

    touch(".gitignore", GITIGNORE, "failed to create .gitignore");

    Ok(())
}

fn cmd<I, S>(cmd: &str, args: I)
where
    I: IntoIterator<Item = S>,
    S: AsRef<OsStr>,
{
    let cmd = Command::new(cmd)
        .args(args)
        .output()
        .expect("failed to run command");
    io::stdout().write_all(&cmd.stdout).unwrap();
    io::stderr().write_all(&cmd.stderr).unwrap();
}

fn mkdir(path: &str) {
    if let Err(a) = fs::create_dir_all(path) {
        if a.kind() != ErrorKind::AlreadyExists {
            eprintln!("\x1b[31m{}\x1b[0m", a);
        }
    }
}

fn touch(path: &str, contents: &str, error_msg: &str) {
    if let Err(_) = fs::File::open(path) {
        fs::write(path, contents).expect(error_msg);
    }
}