-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.rs
120 lines (115 loc) · 3.71 KB
/
build.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use anyhow::Result;
use chrono::{DateTime, FixedOffset, Local, TimeZone};
use pulldown_cmark::{Event, Parser};
use std::collections::HashMap;
use std::fs::{read_dir, File};
use std::io::{BufReader, BufWriter, Read};
use std::path::Path;
fn find_first_commit(p: &Path) -> Result<DateTime<Local>> {
let history = std::process::Command::new("git")
.args(["log", "--format=%at", "--follow", &p.to_string_lossy()])
.output()?;
let history = unsafe { String::from_utf8_unchecked(history.stdout) };
if let Some(last_line) = history.split('\n').filter(|s| !s.is_empty()).last() {
Ok(Local.timestamp_opt(last_line.parse()?, 0).unwrap())
} else {
Ok(Local::now())
}
}
fn open_titles() -> Result<HashMap<String, String>> {
let mut titles = File::open("blogdata/titles.txt")?;
let titles = {
let mut str = String::new();
titles.read_to_string(&mut str)?;
str
};
Ok(titles
.split('\n')
.filter(|s| !s.is_empty())
.map(|s| {
let mut pair = s.split('\t').take(2);
let key = pair.next().unwrap();
let value = pair.next().unwrap();
(key.to_owned(), value.to_owned())
})
.collect())
}
fn main() -> Result<()> {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=blogdata/*");
let mut ch = {
let rss_file = File::open("blogdata/feed.xml")?;
let rss_file = BufReader::new(rss_file);
rss::Channel::read_from(rss_file)?
};
let old_ch = ch.clone();
let now = Local::now();
ch.last_build_date = Some(
now.with_timezone(&FixedOffset::east_opt(8 * 3600).unwrap())
.to_rfc2822(),
);
ch.items.clear();
let mut files = vec![];
for f in read_dir("blogdata")? {
let f = f?;
if f.file_type()?.is_file() {
let p = f.path();
if p.extension().and_then(|s| s.to_str()) == Some("md") {
let pub_time = find_first_commit(&p)?;
files.push((p, pub_time));
}
}
}
files.sort_by_key(|(_, t)| *t);
let titles = open_titles()?;
for (p, pub_date) in files {
let description = {
let mut blog_file = File::open(&p)?;
let mut text = String::new();
blog_file.read_to_string(&mut text)?;
let mut parser = Parser::new(&text);
parser
.find_map(|e| {
if let Event::Text(text) = e {
Some(text.to_string())
} else {
None
}
})
.unwrap_or_default()
};
let filename = p
.with_extension("")
.file_name()
.map(|s| s.to_string_lossy())
.unwrap_or_default()
.into_owned();
ch.items.push(
rss::ItemBuilder::default()
.title(Some(titles[&filename].clone()))
.link(Some(format!("{}{}", ch.link, filename)))
.description(Some(description))
.guid(Some(
rss::GuidBuilder::default()
.permalink(false)
.value(filename)
.build(),
))
.pub_date(Some(pub_date.to_rfc2822()))
.build(),
);
}
if ch.items == old_ch.items {
return Ok(());
}
{
let rss_file = File::options()
.write(true)
.create(true)
.truncate(true)
.open("blogdata/feed.xml")?;
let rss_file = BufWriter::new(rss_file);
ch.pretty_write_to(rss_file, b' ', 2)?;
}
Ok(())
}