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
|
use chrono::{Local, TimeZone};
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::time::UNIX_EPOCH;
use structopt::StructOpt;
use anyhow::Result;
use subplot::{get_basedir_from, resource, Document, Style};
// Define the command line arguments.
#[derive(Debug, StructOpt)]
#[structopt(name = "docgen", about = "Subplot document generator.")]
struct Opt {
// One or more input filename.
#[structopt(parse(from_os_str))]
filenames: Vec<PathBuf>,
// Set output file name.
#[structopt(name = "FILE", long = "--output", short = "-o", parse(from_os_str))]
output: PathBuf,
// Set date.
#[structopt(name = "DATE", long = "--date")]
date: Option<String>,
#[structopt(flatten)]
resources: resource::ResourceOpts,
}
fn main() -> Result<()> {
let opt = Opt::from_args();
opt.resources.handle();
let mut pandoc = pandoc::new();
let first_file = &opt.filenames[0];
let mut style = Style::default();
if opt.output.extension() == Some(&OsString::from("pdf")) {
style.typeset_links_as_notes();
}
let basedir = get_basedir_from(first_file)?;
let mut doc = Document::from_file(&basedir, &first_file, style)?;
doc.lint()?;
if !doc.check_named_files_exist()? {
eprintln!("Continuing despite warnings");
}
// Metadata date from command line or file mtime. However, we
// can't set it directly, since we don't want to override the date
// in the actual document, if given, so we only set
// user-provided-date. Our parsing code will use that if date is
// not document metadata.
let date = if let Some(date) = opt.date {
date
} else if let Some(date) = doc.meta().date() {
date.to_string()
} else {
mtime_formatted(mtime(first_file)?)
};
pandoc.add_option(pandoc::PandocOption::Meta("date".to_string(), Some(date)));
pandoc.add_option(pandoc::PandocOption::TableOfContents);
pandoc.add_option(pandoc::PandocOption::Standalone);
pandoc.add_option(pandoc::PandocOption::NumberSections);
if need_output(&mut doc, &opt.output) {
doc.typeset();
pandoc.set_input_format(pandoc::InputFormat::Json, vec![]);
pandoc.set_input(pandoc::InputKind::Pipe(doc.ast()?));
pandoc.set_output(pandoc::OutputKind::File(opt.output.clone()));
pandoc.execute()?;
}
Ok(())
}
fn mtime(filename: &Path) -> Result<(u64, u32)> {
let mtime = fs::metadata(filename)?.modified()?;
let mtime = mtime.duration_since(UNIX_EPOCH)?;
Ok((mtime.as_secs(), mtime.subsec_nanos()))
}
fn mtime_formatted(mtime: (u64, u32)) -> String {
let secs: i64 = format!("{}", mtime.0).parse().unwrap_or(0);
let dt = Local.timestamp(secs, mtime.1);
dt.format("%Y-%m-%d %H:%M").to_string()
}
fn need_output(doc: &mut subplot::Document, output: &Path) -> bool {
let output = match mtime(output) {
Err(_) => return true,
Ok(ts) => ts,
};
for filename in doc.sources() {
let source = match mtime(&filename) {
Err(_) => return true,
Ok(ts) => ts,
};
if source >= output {
return true;
}
}
false
}
|