Skip to content

Commit 3e1b568

Browse files
ZexbeMark-Simulacrum
authored andcommitted
Make updated time unique
I split published, and updated time, and made it so duplicate updated times get different seconds.
1 parent 544037d commit 3e1b568

File tree

4 files changed

+91
-77
lines changed

4 files changed

+91
-77
lines changed

src/blogs.rs

+10
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ impl Blog {
6868
posts[i].show_year = posts[i - 1].year != posts[i].year;
6969
}
7070

71+
// Make the updated time is unique, by incrementing seconds for duplicates
72+
let mut last_matching_updated = 0;
73+
for i in 1..posts.len() {
74+
if posts[i].updated == posts[last_matching_updated].updated {
75+
posts[i].set_updated((i - last_matching_updated) as u32);
76+
} else {
77+
last_matching_updated = i;
78+
}
79+
}
80+
7181
Ok(Blog {
7282
title: manifest.title,
7383
index_title: manifest.index_title,

src/main.rs

+31-47
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod posts;
33

44
use crate::blogs::Blog;
55
use crate::posts::Post;
6-
use handlebars::{Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderError};
6+
use handlebars::{handlebars_helper, Handlebars};
77
use sass_rs::{compile_file, Options};
88
use serde_derive::Serialize;
99
use serde_json::json;
@@ -30,40 +30,21 @@ struct ReleasePost {
3030
title: String,
3131
url: String,
3232
}
33-
34-
fn hb_month_helper<'a>(
35-
h: &Helper,
36-
_b: &Handlebars,
37-
_ctx: &Context,
38-
_rc: &mut RenderContext,
39-
out: &mut dyn Output,
40-
) -> HelperResult {
41-
let num: u32 = h
42-
.param(0)
43-
.unwrap()
44-
.value()
45-
.as_str()
46-
.unwrap()
47-
.parse()
48-
.or_else(|_| Err(RenderError::new("The value is not a number")))?;
49-
let name = match num {
50-
1 => "Jan.",
51-
2 => "Feb.",
52-
3 => "Mar.",
53-
4 => "Apr.",
54-
5 => "May",
55-
6 => "June",
56-
7 => "July",
57-
8 => "Aug.",
58-
9 => "Sept.",
59-
10 => "Oct.",
60-
11 => "Nov.",
61-
12 => "Dec.",
62-
_ => "Error!",
63-
};
64-
out.write(name)?;
65-
Ok(())
66-
}
33+
handlebars_helper!(hb_month_name_helper: |month_num: u64| match month_num {
34+
1 => "Jan.",
35+
2 => "Feb.",
36+
3 => "Mar.",
37+
4 => "Apr.",
38+
5 => "May",
39+
6 => "June",
40+
7 => "July",
41+
8 => "Aug.",
42+
9 => "Sept.",
43+
10 => "Oct.",
44+
11 => "Nov.",
45+
12 => "Dec.",
46+
_ => "Error!",
47+
});
6748

6849
impl Generator {
6950
fn new(
@@ -73,7 +54,7 @@ impl Generator {
7354
let mut handlebars = Handlebars::new();
7455
handlebars.set_strict_mode(true);
7556
handlebars.register_templates_directory(".hbs", "templates")?;
76-
handlebars.register_helper("month_name", Box::new(hb_month_helper));
57+
handlebars.register_helper("month_name", Box::new(hb_month_name_helper));
7758

7859
Ok(Generator {
7960
handlebars,
@@ -131,11 +112,16 @@ impl Generator {
131112
}
132113

133114
fn render_index(&self, blog: &Blog) -> Result<(), Box<dyn Error>> {
134-
let other_blogs: Vec<_> = self.blogs.iter().filter(|b| b.index_title() != blog.index_title())
135-
.map(|other_blog| json!({
136-
"link_text": other_blog.link_text(),
137-
"url": PathBuf::from("/").join(other_blog.prefix()).join("index.html"),
138-
}))
115+
let other_blogs: Vec<_> = self
116+
.blogs
117+
.iter()
118+
.filter(|b| b.index_title() != blog.index_title())
119+
.map(|other_blog| {
120+
json!({
121+
"link_text": other_blog.link_text(),
122+
"url": PathBuf::from("/").join(other_blog.prefix()).join("index.html"),
123+
})
124+
})
139125
.collect();
140126

141127
let data = json!({
@@ -151,9 +137,9 @@ impl Generator {
151137
fn render_post(&self, blog: &Blog, post: &Post) -> Result<(), Box<dyn Error>> {
152138
let path = blog
153139
.prefix()
154-
.join(&post.year)
155-
.join(&post.month)
156-
.join(&post.day);
140+
.join(&post.year.to_string())
141+
.join(&post.month.to_string())
142+
.join(&post.day.to_string());
157143
fs::create_dir_all(self.out_directory.join(&path))?;
158144

159145
// then, we render the page in that path
@@ -202,9 +188,7 @@ impl Generator {
202188
feed_updated: time::now_utc().rfc3339().to_string(),
203189
};
204190
fs::write(
205-
self.out_directory
206-
.join(blog.prefix())
207-
.join("releases.json"),
191+
self.out_directory.join(blog.prefix()).join("releases.json"),
208192
serde_json::to_string(&data)?,
209193
)?;
210194
Ok(())

src/posts.rs

+49-29
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use regex::Regex;
44
use serde_derive::{Deserialize, Serialize};
55
use std::error::Error;
66
use std::path::{Path, PathBuf};
7+
use time::{Duration, Tm};
78

89
#[derive(Debug, PartialEq, Deserialize)]
910
struct YamlHeader {
@@ -21,13 +22,14 @@ pub(crate) struct Post {
2122
pub(crate) layout: String,
2223
pub(crate) title: String,
2324
pub(crate) author: String,
24-
pub(crate) year: String,
25+
pub(crate) year: u32,
2526
pub(crate) show_year: bool,
26-
pub(crate) month: String,
27-
pub(crate) day: String,
27+
pub(crate) month: u32,
28+
pub(crate) day: u32,
2829
pub(crate) contents: String,
2930
pub(crate) url: String,
3031
pub(crate) published: String,
32+
pub(crate) updated: String,
3133
pub(crate) release: bool,
3234
pub(crate) has_team: bool,
3335
pub(crate) team: String,
@@ -42,9 +44,10 @@ impl Post {
4244
// we need to get the metadata out of the url
4345
let mut split = filename.splitn(4, "-");
4446

45-
let year = split.next().unwrap().to_string();
46-
let month = split.next().unwrap().to_string();
47-
let day = split.next().unwrap().to_string();
47+
// we do some unwraps because these need to be valid
48+
let year = split.next().unwrap().parse::<u32>().unwrap();
49+
let month = split.next().unwrap().parse::<u32>().unwrap();
50+
let day = split.next().unwrap().parse::<u32>().unwrap();
4851
let filename = split.next().unwrap().to_string();
4952

5053
let contents = std::fs::read_to_string(path)?;
@@ -76,29 +79,16 @@ impl Post {
7679
// this is fine
7780
let url = format!("{}/{}/{}/{}", year, month, day, url.to_str().unwrap());
7881

79-
// build the published time. this is only approximate, which is fine.
80-
// we do some unwraps because these need to be valid
81-
let published = time::Tm {
82-
tm_sec: 0,
83-
tm_min: 0,
84-
tm_hour: 0,
85-
tm_mday: day.parse::<i32>().unwrap(),
86-
tm_mon: month.parse::<i32>().unwrap() - 1, // 0-11 not 1-12
87-
tm_year: year.parse::<i32>().unwrap() - 1900, // from the year 1900, not the actual year
88-
// these next two fields are wrong but we never use them to generate our times
89-
tm_wday: 1,
90-
tm_yday: 1,
91-
tm_isdst: 0,
92-
tm_utcoff: 0,
93-
tm_nsec: 0,
94-
};
95-
96-
let published = published.rfc3339().to_string();
82+
let published = build_post_time(year, month, day, 0);
83+
let updated = published.clone();
9784

9885
// validate for now that the layout is specified as "post"
9986
match &*layout {
10087
"post" => (),
101-
_ => panic!("blog post at path `{}` should have layout `post`", path.display()),
88+
_ => panic!(
89+
"blog post at path `{}` should have layout `post`",
90+
path.display()
91+
),
10292
};
10393

10494
// Enforce extra conditions
@@ -114,13 +104,18 @@ impl Post {
114104
}
115105
let captures = match R.captures(&s) {
116106
Some(c) => c,
117-
None => panic!("team from path `{}` should have format `$name <$url>`",
118-
path.display()),
107+
None => panic!(
108+
"team from path `{}` should have format `$name <$url>`",
109+
path.display()
110+
),
119111
};
120-
(Some(captures["name"].to_string()), Some(captures["url"].to_string()))
112+
(
113+
Some(captures["name"].to_string()),
114+
Some(captures["url"].to_string()),
115+
)
121116
}
122117

123-
None => (None, None)
118+
None => (None, None),
124119
};
125120

126121
Ok(Self {
@@ -134,11 +129,36 @@ impl Post {
134129
contents,
135130
url,
136131
published,
132+
updated,
137133
release,
138134
layout,
139135
has_team: team.is_some(),
140136
team: team.unwrap_or_default(),
141137
team_url: team_url.unwrap_or_default(),
142138
})
143139
}
140+
141+
pub fn set_updated(&mut self, hour: u32) {
142+
self.updated = build_post_time(self.year, self.month, self.day, hour);
143+
}
144+
}
145+
146+
fn build_post_time(year: u32, month: u32, day: u32, seconds: u32) -> String {
147+
// build the time. this is only approximate, which is fine.
148+
let mut time = Tm {
149+
tm_sec: 0,
150+
tm_min: 0,
151+
tm_hour: 0,
152+
tm_mday: day as i32,
153+
tm_mon: (month as i32) - 1, // 0-11 not 1-12
154+
tm_year: (year as i32) - 1900, // from the year 1900, not the actual year
155+
// these next two fields are wrong but we never use them to generate our times
156+
tm_wday: 1,
157+
tm_yday: 1,
158+
tm_isdst: 0,
159+
tm_utcoff: 0,
160+
tm_nsec: 0,
161+
};
162+
time = time + Duration::seconds(seconds as i64);
163+
time.rfc3339().to_string()
144164
}

templates/feed.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<title>{{title}}</title>
1818
<link rel="alternate" href="https://blog.rust-lang.org/{{../blog.prefix}}{{url}}" type="text/html" title="{{title}}" />
1919
<published>{{published}}</published>
20-
<updated>{{published}}</updated>
20+
<updated>{{updated}}</updated>
2121
<id>https://blog.rust-lang.org/{{../blog.prefix}}{{url}}</id>
2222
<content type="html" xml:base="https://blog.rust-lang.org/{{../blog.prefix}}{{url}}">{{contents}}</content>
2323

0 commit comments

Comments
 (0)