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
extern crate nom;
use std::path::Path;
use std::env;
use std::fs;
use std::io;
use parser::Message;
use std::path::PathBuf;
pub mod generator;
pub mod parser;
pub fn process_current_dir() -> io::Result<()> {
process_dir(&env::current_dir()?)
}
fn convert_error<T>(r: Result<T, String>) -> Result<T, io::Error> {
r.map_err(|s| io::Error::new(io::ErrorKind::Other, s))
}
fn get_out_dir() -> io::Result<PathBuf> {
match env::var_os("OUT_DIR") {
Some(var) => Ok(PathBuf::from(&var)),
None => return convert_error(Err("missing OUT_DIR variable".to_string())),
}
}
pub fn process_dir(path: &Path) -> io::Result<()> {
let out_dir = get_out_dir()?;
let name = path.components().last().expect("not a valid path");
let out_file = out_dir.join(Path::new(&name)).with_extension("rs");
process_dir_to(path, &out_file, None)
}
pub fn process_dir_to(path: &Path, out_file: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
fs::create_dir_all(out_file.parent().expect("No parent for out file"))?;
let messages = parse_dir_int(path)?;
process(messages, &out_file, post_process)?;
Ok(())
}
pub fn process_file(path: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
let messages = parse_file(&path)?;
let out_dir = get_out_dir()?;
let name = path.components().last().expect("not a valid path");
let out_file = out_dir.join(Path::new(&name)).with_extension("rs");
process(messages, &out_file, post_process)
}
fn parse_dir_int(path: &Path) -> io::Result<Vec<Message>> {
println!("process dir {}", path.to_string_lossy());
let mut messages = vec![];
for entry in fs::read_dir(path)? {
let entry = entry?;
if entry.file_type()?.is_dir() {
messages.extend(parse_dir_int(&entry.path())?);
} else if entry.path().extension().iter().any(|ext| *ext == "protogen") {
messages.extend(parse_file(&entry.path())?);
}
};
Ok(messages)
}
fn parse_file(path: &Path) -> io::Result<Vec<Message>> {
let data = fs::read(path)?;
match parser::source_file(&data) {
Ok((rest, messages)) => {
let rest = String::from_utf8_lossy(&rest);
if rest.trim().is_empty() {
return Ok(messages);
} else {
return Err(io::Error::new(io::ErrorKind::Other,
format!("Parse error at {}", rest)));
}
}
Err(e) => {
return Err(io::Error::new(io::ErrorKind::Other,
format!("Parse error {:?}", e)));
}
}
}
fn process(messages: Vec<Message>, out_path: &Path, post_process: Option<&Fn(&str) -> String>) -> io::Result<()> {
let mut generated = convert_error(generator::Generator::from_messages(messages))?.to_string();
if let Some(process_fn) = post_process {
generated = process_fn(&generated);
}
fs::write(&out_path, generated)?;
Ok(())
}