-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbuild.rs
More file actions
88 lines (80 loc) · 3.24 KB
/
Copy pathbuild.rs
File metadata and controls
88 lines (80 loc) · 3.24 KB
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
//! Build script for shields crate.
//!
//! 1. Minifies the SVG templates next to their sources (skipped when already up to date, so
//! building from a read-only packaged source tree keeps working).
//! 2. Converts the JSON font width tables into static Rust arrays in OUT_DIR, so the library
//! performs no JSON parsing at runtime.
use std::env;
use std::fmt::Write as _;
use std::fs;
use std::io;
use std::path::Path;
const TEMPLATE_FILES: [&str; 5] = [
"templates/flat_badge_template.svg",
"templates/flat_square_badge_template.svg",
"templates/plastic_badge_template.svg",
"templates/social_badge_template.svg",
"templates/for_the_badge_template.svg",
];
const FONT_TABLES: [(&str, &str); 4] = [
("VERDANA_11_NORMAL", "assets/fonts/verdana-11px-normal.json"),
("HELVETICA_11_BOLD", "assets/fonts/helvetica-11px-bold.json"),
("VERDANA_10_NORMAL", "assets/fonts/verdana-10px-normal.json"),
("VERDANA_10_BOLD", "assets/fonts/verdana-10px-bold.json"),
];
fn main() -> io::Result<()> {
println!("cargo:rerun-if-changed=build.rs");
minify_templates()?;
generate_font_tables()?;
Ok(())
}
fn minify_templates() -> io::Result<()> {
for file in &TEMPLATE_FILES {
println!("cargo:rerun-if-changed={file}");
let path = Path::new(file);
let dest = path.with_extension("min.svg");
let content = fs::read_to_string(path)?;
let min_content = minify_svg(&content);
// Skip the write when up to date: the packaged crate ships correct .min.svg files,
// and its source tree may be read-only (docs.rs, Nix, shared registry caches).
if fs::read_to_string(&dest).is_ok_and(|existing| existing == min_content) {
continue;
}
fs::write(dest, min_content)?;
}
Ok(())
}
// Minify SVG content by trimming lines, joining whitespace, and removing unnecessary spaces
fn minify_svg(content: &str) -> String {
let min_content = content.lines().map(str::trim).collect::<String>();
let min_content = min_content.split_whitespace().collect::<Vec<_>>().join(" ");
min_content.replace(" />", "/>").replace("> <", "><")
}
fn generate_font_tables() -> io::Result<()> {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR is set by cargo");
let mut code = String::from(
"// Generated by build.rs from assets/fonts/*.json. Do not edit.\n\
// Sorted, non-overlapping (lower, upper, width) code point ranges.\n",
);
for (name, path) in &FONT_TABLES {
println!("cargo:rerun-if-changed={path}");
let json = fs::read_to_string(path)?;
let ranges: Vec<(u32, u32, f64)> = serde_json::from_str(&json)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?;
assert!(
ranges.windows(2).all(|w| w[0].1 < w[1].0),
"{path}: font ranges must be sorted and non-overlapping"
);
writeln!(
code,
"pub static {name}: [(u32, u32, f64); {}] = [",
ranges.len()
)
.unwrap();
for (lower, upper, width) in ranges {
writeln!(code, " ({lower}, {upper}, {width:?}),").unwrap();
}
code.push_str("];\n");
}
fs::write(Path::new(&out_dir).join("font_tables.rs"), code)
}