~asayers/flin

bc142bb93fd47db96d9738adb9e5a9e9009f2b89 — Alex Sayers 5 years ago 425ab86 master
Improve error handling
3 files changed, 39 insertions(+), 20 deletions(-)

M INSTALLING
M TODO
M src/main.rs
M INSTALLING => INSTALLING +1 -1
@@ 1,4 1,4 @@
Flin is a simple (50-line, no deps) rust program.  You can install it with
Flin is a very simple rust program.  You can install it with

    cargo install --path=.


M TODO => TODO +0 -1
@@ 1,3 1,2 @@
* Escaping, probably with "{{" and "}}"
* Better error messages
* Reduce buffering to per-line

M src/main.rs => src/main.rs +38 -18
@@ 3,6 3,7 @@ use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Write};

fn main() {
    let mut ret = 0;
    let args = env::args().collect::<Vec<_>>();
    let stdin = stdin();
    let template = BufReader::new(stdin.lock());


@@ 16,30 17,49 @@ fn main() {
            .unwrap();
        for segment in segments {
            let mut var_rem = segment.splitn(2, '}');
            let variable = var_rem.next().unwrap();
            if let Ok(idx) = variable.parse::<usize>() {
                // it's a CLI arg
                let file = File::open(&args[idx + 1]).unwrap();
                let mut file_lines = BufReader::new(file).lines();
                stdout.write_all(file_lines.next().unwrap().unwrap().as_bytes()).unwrap();
                for line in file_lines {
                    stdout.write_all(b"\n").unwrap();
                    stdout.write_all(line.unwrap().as_bytes()).unwrap();
            let var = var_rem.next().unwrap();
            match handle(var, &args, &mut stdout) {
                Ok(()) => (),
                Err(e) => {
                    ret = 1;
                    eprintln!("{}", e);
                    // Just print the original placeholder
                    stdout.write_all(format!("{{{}}}", var).as_bytes()).unwrap();
                }
            } else {
                stdout
                    .write_all(
                        env::var(variable)
                            .expect("Couldn't find variable")
                            .as_bytes(),
                    )
                    .unwrap();
            }
            stdout
                .write_all(var_rem.next().expect("Unclose open brace").as_bytes())
                .write_all(var_rem.next().expect("Unclosed open brace").as_bytes())
                .unwrap();
        }
        stdout.write_all(b"\n").unwrap();
    }
    stdout.flush().unwrap();
    std::process::exit(ret);
}

fn handle(var: &str, args: &[String], mut stdout: impl Write) -> Result<(), String> {
    if let Ok(idx) = var.parse::<usize>() {
        // It's a file.  Get the path from the arg list
        let path = args.get(idx + 1).ok_or_else(|| {
            format!(
                "Not enough args: required {}, receieved {}",
                idx + 1,
                args.len() - 1,
            )
        })?;
        let file = File::open(path).map_err(|e| format!("Couldn't open file {}: {}", path, e))?;
        let mut file_lines = BufReader::new(file).lines();
        stdout
            .write_all(file_lines.next().unwrap().unwrap().as_bytes())
            .unwrap();
        for line in file_lines {
            stdout.write_all(b"\n").unwrap();
            stdout.write_all(line.unwrap().as_bytes()).unwrap();
        }
    } else {
        // It's an environment variable
        let val = env::var(var).map_err(|_| format!("Couldn't find variable {}", var))?;
        stdout.write_all(val.as_bytes()).unwrap();
    }
    Ok(())
}