breed_planner/
main.rs

1#![allow(non_snake_case)]
2
3use std::io::prelude::*;
4use std::fs::File;
5use std::path::PathBuf;
6use std::process::Command;
7
8#[macro_use]
9mod error;
10mod breed;
11
12use error::Error;
13
14fn runDot(dot_code: &str, output_format: &str) -> Result<Vec<u8>, Error>
15{
16    let mut proc = Command::new("dot")
17        .arg("-T")
18        .arg(output_format)
19        .stdin(std::process::Stdio::piped())
20        .stdout(std::process::Stdio::piped())
21        .spawn()
22        .map_err(|e| rterr!("Failed to run dot: {}", e))?;
23    proc.stdin.take().unwrap().write_all(dot_code.as_bytes()).map_err(
24        |e| rterr!("Failed to write input to dot: {}", e))?;
25    let output = proc.wait_with_output().map_err(
26        |e| rterr!("Failed to wait for dot to finish: {}", e))?;
27    if !output.status.success()
28    {
29        return Err(rterr!("Dot command failed"));
30    }
31
32    Ok(output.stdout)
33}
34
35fn getOutputFileName(input_file: &str, output_type: &str) ->
36    Result<String, Error>
37{
38    let path = PathBuf::from(input_file);
39    let dir = if let Some(d) = path.parent()
40    {
41        d.to_owned()
42    }
43    else
44    {
45        std::env::current_dir().map_err(
46            |e| rterr!("Failed to get current dir: {}", e))?
47    };
48    let basename: &str = path.file_stem().ok_or_else(
49        || rterr!("Failed to get basename of input file"))?.to_str()
50        .ok_or_else(|| rterr!("Input file name is too weird"))?;
51    let output_basename_with_ext = format!("{}.{}", basename, output_type);
52    let mut output_path = PathBuf::new();
53    output_path.push(dir);
54    output_path.push(output_basename_with_ext);
55    Ok(output_path.to_str().ok_or_else(
56        || rterr!("Output file name is too weird"))?.to_owned())
57}
58
59fn main() -> Result<(), Error>
60{
61    let options = clap::Command::new("DWM planner").arg(
62        clap::Arg::new("FILE").required(true)
63            .help("Input breed plan file")).arg(
64        clap::Arg::new("output").short('o').long("output")
65            .value_name("FILE")
66            .help("Output file")).arg(
67        clap::Arg::new("output_type").short('t').long("output-type")
68            .value_name("TYPE").default_value("pdf")
69            .help("Output file type. E.g. 'pdf', 'svg', etc. \
70                   This argument is passed to the dot -T option."))
71        .get_matches();
72
73    let filename = options.get_one::<String>("FILE").unwrap();
74
75    let f = std::fs::File::open(filename).map_err(|e| rterr!("{}", e))?;
76    let output_file = if let Some(output) = options.get_one::<String>("output")
77    {
78        String::from(output)
79    }
80    else
81    {
82        getOutputFileName(
83            filename, options.get_one::<String>("output_type").unwrap())?
84    };
85
86    let plan = breed::BreedPlan::fromStream(&mut std::io::BufReader::new(f))?;
87    let output = runDot(
88        &plan.toDot(), options.get_one::<String>("output_type").unwrap())?;
89    let mut f = File::create(output_file).map_err(
90        |e| rterr!("Failed to open output file: {}", e))?;
91    f.write_all(&output).map_err(
92        |e| rterr!("Failed to write output file: {}", e))?;
93
94    Ok(())
95}