-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathgenpest.rs
88 lines (77 loc) · 2.25 KB
/
genpest.rs
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
//! `pest_derive` crate has large dependency tree, and, as a build dependency,
//! it imposes these deps onto our consumers.
//!
//! To avoid that, let's just dump generated code to string into this
//! repository, and add a test that checks that the code is fresh.
use std::{
fs,
io::Write,
process::{Command, Stdio},
time::Instant,
};
#[test]
fn generated_code_is_fresh() {
let t = Instant::now();
let token_stream = {
let grammar = include_str!("../src/semver.pest");
let input = format!(
r###"
#[derive(Parser)]
#[grammar_inline = r#"{}"#]
struct SemverParser;
"###,
grammar
)
.parse::<proc_macro2::TokenStream>()
.unwrap();
let ts = pest_generator::derive_parser(input.into(), true);
eprintln!("Generated code in {:02?}", t.elapsed());
ts
};
let code = {
eprintln!("Reformatting (this will take couple of minutes)");
let t = Instant::now();
let code = format!(
"\
/// This is @generated code, do not edit by hand.
/// See `semver.pest` and `genpest.rs`.
use super::SemverParser;
{}
",
token_stream
);
let code = reformat(&code);
eprintln!("Reformatted in {:02?}", t.elapsed());
normalize_newlines(&code)
};
let current = {
let current = fs::read("./src/generated.rs").unwrap_or_default();
let current = String::from_utf8(current).unwrap();
normalize_newlines(¤t)
};
if current == code {
eprintln!("Generated code is up to date, hurray!")
} else {
fs::write("./src/generated.rs", code).unwrap();
panic!("Generated code in the repository is outdated, updating...");
}
}
fn reformat(code: &str) -> String {
let mut cmd = Command::new("rustfmt")
.args(&["--config", "tab_spaces=2"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
cmd.stdin
.take()
.unwrap()
.write_all(code.as_bytes())
.unwrap();
let output = cmd.wait_with_output().unwrap();
assert!(output.status.success());
String::from_utf8(output.stdout).unwrap()
}
fn normalize_newlines(code: &str) -> String {
code.replace("\r\n", "\n")
}