summaryrefslogtreecommitdiff
path: root/src/bin/subplot.rs
blob: 38e129e559c3676729869cae3e749087b1385e9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Subplot top level binary
//!

use anyhow::Result;

use structopt::StructOpt;
use subplot::{resource, DataFile, Style};

use std::fs::write;
use std::path::PathBuf;
use std::process;

mod cli;

#[derive(Debug, StructOpt)]
struct Toplevel {
    #[structopt(flatten)]
    resources: resource::ResourceOpts,

    #[structopt(flatten)]
    command: Cmd,
}

impl Toplevel {
    fn run(&self) -> Result<()> {
        self.command.run()
    }
}

#[derive(Debug, StructOpt)]
enum Cmd {
    Extract(Extract),
}

impl Cmd {
    fn run(&self) -> Result<()> {
        match self {
            Cmd::Extract(e) => e.run(),
        }
    }
}

#[derive(Debug, StructOpt)]
/// Extract embedded files from a subplot document
///
/// If no embedded filenames are provided, this will
/// extract all embedded files.  if the output directory
/// is not specified then this will extract to the current directory.
struct Extract {
    /// Directory to write extracted files to
    #[structopt(
        name = "DIR",
        long = "directory",
        short = "d",
        parse(from_os_str),
        default_value = "."
    )]
    directory: PathBuf,

    /// Don't actually write the files out
    #[structopt(long)]
    dry_run: bool,

    /// Input subplot document filename
    #[structopt(parse(from_os_str))]
    filename: PathBuf,

    /// Names of embedded files to be extracted.
    embedded: Vec<String>,
}

impl Extract {
    fn run(&self) -> Result<()> {
        let doc = cli::load_document(&self.filename, Style::default())?;

        let files: Vec<&DataFile> = if self.embedded.is_empty() {
            doc.files()
                .iter()
                .map(Result::Ok)
                .collect::<Result<Vec<_>>>()
        } else {
            self.embedded
                .iter()
                .map(|filename| cli::extract_file(&doc, filename))
                .collect::<Result<Vec<_>>>()
        }?;

        for f in files {
            let outfile = self.directory.join(f.filename());
            if self.dry_run {
                println!("Would write out {}", outfile.display());
            } else {
                write(outfile, f.contents())?
            }
        }

        Ok(())
    }
}

fn main() {
    let args = Toplevel::from_args();
    args.resources.handle();
    match args.run() {
        Ok(_) => {}
        Err(e) => {
            eprintln!("Failure: {:?}", e);
            process::exit(1);
        }
    }
}