Created
December 5, 2023 02:33
-
-
Save Gankra/348d080d6d5e609074a326ad73fdd96a to your computer and use it in GitHub Desktop.
rustblog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"articles": | |
[ | |
{ | |
"path": "oops-that-was-important", | |
"toc": false, | |
"title": "Compiler Optimizations Are Hard Because They Forget", | |
"date": "Sat, 24 Sep 2022 06:06:58 +0000" | |
}, | |
{ | |
"path": "defaults-affect-inference", | |
"toc": true, | |
"title": "Defaults Affect Inference in Rust: Expressions Instead Of Types", | |
"date": "Sun, 10 Apr 2022 23:00:13 +0000" | |
}, | |
{ | |
"path": "tower-of-weakenings", | |
"toc": true, | |
"title": "The Tower of Weakenings: Memory Models For Everyone", | |
"date": "Tue, 05 Apr 2022 20:07:14 +0000" | |
}, | |
{ | |
"path": "dsts-are-polymorphic-generics", | |
"toc": false, | |
"title": "DSTs Are Just Polymorphically Compiled Generics", | |
"date": "Tue, 30 Mar 2022 22:13:17 +0000" | |
}, | |
{ | |
"path": "fix-rust-pointers", | |
"toc": true, | |
"title": "Rust's Unsafe Pointer Types Need An Overhaul", | |
"date": "Sat, 19 Mar 2022 22:13:17 +0000" | |
}, | |
{ | |
"path": "c-isnt-a-language", | |
"toc": false, | |
"title": "C Isn't A Programming Language Anymore", | |
"date": "Wed, 16 Mar 2022 21:24:08 +0000" | |
}, | |
{ | |
"path": "faultlore", | |
"toc": false, | |
"title": "Faultlore: Learning Through Errors", | |
"date": "Sun, 27 Feb 2022 18:18:56 +0000" | |
}, | |
{ | |
"path": "deinitialize-me-maybe", | |
"toc": true, | |
"title": "Destroy All Values: Designing Deinitialization in Programming Languages", | |
"date": "Sun, 23 Jan 2022 00:00:00 +0000" | |
}, | |
{ | |
"path": "compact-unwinding", | |
"toc": true, | |
"title": "The Apple Compact Unwinding Format: Documented and Explained", | |
"date": "Wed, 09 Jun 2021 00:00:00 +0000" | |
}, | |
{ | |
"path": "swift-abi", | |
"toc": true, | |
"title": "How Swift Achieved Dynamic Linking Where Rust Couldn't", | |
"date": "Thu, 07 Nov 2019 00:00:00 +0000" | |
}, | |
{ | |
"path": "text-hates-you", | |
"toc": true, | |
"title": "Text Rendering Hates You", | |
"date": "Sat, 28 Sep 2019 00:00:00 +0000" | |
}, | |
{ | |
"path": "hashbrown-tldr", | |
"toc": false, | |
"title": "Swisstable, a Quick and Dirty Description", | |
"date": "Sat, 27 Jul 2019 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.35.0" | |
}, | |
{ | |
"path": "initialize-me-maybe", | |
"toc": false, | |
"title": "Here's My Type, So Initialize Me Maybe", | |
"date": "Tue, 21 May 2019 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.36.0" | |
}, | |
{ | |
"path": "hashbrown-insert", | |
"toc": false, | |
"title": "Why Hashbrown Does A Double-Lookup", | |
"date": "Wed, 20 Mar 2019 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.36.0" | |
}, | |
{ | |
"path": "impl-defined", | |
"toc": false, | |
"title": "The Kinds of Implementation-Defined?", | |
"date": "Tue, 13 Nov 2018 00:00:00 +0000" | |
}, | |
{ | |
"path": "rust-layouts-and-abis", | |
"toc": true, | |
"title": "Notes on Type Layouts and ABIs in Rust", | |
"date": "Tue, 09 Oct 2018 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.30.0" | |
}, | |
{ | |
"path": "only-in-rust", | |
"toc": false, | |
"title": "Bugs You'll Probably Only Have In Rust", | |
"date": "Wed, 14 Jun 2017 00:00:00 +0000" | |
}, | |
{ | |
"path": "linear-rust", | |
"toc": true, | |
"title": "The Pain Of Linear Types In Rust", | |
"date": "Mon, 08 May 2017 00:00:00 +0000" | |
}, | |
{ | |
"path": "robinhood-part-1", | |
"toc": false, | |
"title": "A HashMap in Rust - What's a HashMap?", | |
"date": "Thu, 15 Jan 2015 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.0.0" | |
}, | |
{ | |
"path": "rust-btree-case", | |
"toc": false, | |
"title": "Rust Collections Case Study: BTreeMap", | |
"date": "Fri, 05 Jun 2015 00:00:00 +0000", | |
"aux_date": "Rust Nightly 1.0.0" | |
}, | |
{ | |
"path": "rust-generics-and-collections", | |
"toc": false, | |
"title": "Rust, Generics, and Collections", | |
"date": "Wed, 03 Jun 2015 00:00:00 +0000", | |
"aux_date": "Rust Nightly 0.12.0" | |
}, | |
{ | |
"path": "everyone-poops", | |
"toc": false, | |
"title": "Pre-Pooping Your Pants With Rust", | |
"date": "Mon, 27 Apr 2015 00:00:00 +0000", | |
"aux_date": "Rust Nightly 0.12.0" | |
}, | |
{ | |
"path": "rust-lifetimes-and-collections", | |
"toc": false, | |
"title": "Rust, Lifetimes, and Collections", | |
"date": "Sun, 09 Nov 2014 00:00:00 +0000", | |
"aux_date": "Rust Nightly 0.12.0" | |
}, | |
{ | |
"path": "homestuck-memories", | |
"toc": false, | |
"title": "Memories of Working on Homestuck", | |
"date": "Wed, 06 May 2020 00:00:00 +0000" | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "rustblog" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
serde_json = "1.0" | |
serde = { version = "1.0", features = ["derive"] } | |
linked-hash-map = "0.5.4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Assumes a bunch of random css/js files exist in parent dirs | |
use serde::Deserialize; | |
use std::error::Error; | |
use std::fs::{self, File}; | |
use std::io::BufReader; | |
use std::io::prelude::*; | |
use std::env; | |
use std::process::Command; | |
use std::time::Duration; | |
#[derive(Deserialize)] | |
struct Manifest { | |
articles: Vec<Article>, | |
} | |
#[allow(dead_code)] | |
#[derive(Deserialize)] | |
struct Article { | |
path: String, | |
toc: bool, | |
title: String, | |
date: String, | |
aux_date: Option<String>, | |
} | |
fn main() -> Result<(), Box<dyn Error>> { | |
env::set_current_dir("../../")?; | |
let file = File::open("articles.json")?; | |
let reader = BufReader::new(file); | |
let manifest: Manifest = serde_json::from_reader(reader)?; | |
let rss_base = r#" | |
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> | |
<channel> | |
<title>Faultlore</title> | |
<link>https://gankra.github.io/blah/</link> | |
<atom:link href="http://gankra.github.io/rss.xml" rel="self" type="application/rss+xml"/> | |
<description>Aria's Feverdreams</description> | |
<language>en-us</language> | |
<image> | |
<url>https://gankra.github.io/blah/img/error-base.png</url> | |
<title>Faultlore</title> | |
<link>https://gankra.github.io/blah/</link> | |
</image> | |
"#; | |
let rss_end = r#" | |
</channel> | |
</rss> | |
"#; | |
let mut rss = String::new(); | |
rss.push_str(rss_base); | |
for article in &manifest.articles { | |
print!("processing {}...", article.path); | |
assert!(!article.title.contains("\"")); | |
assert!(!article.path.contains("\"")); | |
assert!(!article.title.contains("<")); | |
assert!(!article.path.contains("<")); | |
assert!(!article.title.contains(">")); | |
assert!(!article.path.contains(">")); | |
assert!(!article.title.contains("\\")); | |
assert!(!article.path.contains("\\")); | |
let true_title = format!("{} - Faultlore", article.title); | |
let true_link = format!("https://gankra.github.io/blah/{}", article.path); | |
let true_desc = format!("{}", article.title); | |
env::set_current_dir(&article.path)?; | |
fs::create_dir_all("doc")?; | |
fs::copy("../rustblog/head.html", "./head.html")?; | |
{ | |
// Add new meta headers for robots | |
let title_meta = format!("\n<meta property=\"og:title\" content=\"{}\">", &true_title); | |
let url_meta = format!("\n<meta property=\"og:url\" content=\"{}\">", &true_link); | |
let mut header = File::options() | |
.read(true) | |
.append(true) | |
.open("./head.html")?; | |
header.write_all(title_meta.as_bytes())?; | |
header.write_all(url_meta.as_bytes())?; | |
header.sync_all()?; | |
} | |
std::thread::sleep(Duration::from_millis(75)); | |
let mut command = Command::new("rustdoc"); | |
if article.toc { | |
// Do nothing | |
} else { | |
command.arg("--markdown-no-toc"); | |
} | |
command | |
.arg("--html-in-header") | |
.arg("./head.html") | |
.arg("--html-before-content") | |
.arg("../rustblog/before.html") | |
.arg("--html-after-content") | |
.arg("../rustblog/after.html") | |
.arg("index.md") | |
.status()?; | |
std::thread::sleep(Duration::from_millis(75)); | |
fs::rename("doc/index.html", "./index.html")?; | |
fs::remove_file("./head.html")?; | |
fs::remove_dir_all("doc")?; | |
std::thread::sleep(Duration::from_millis(75)); | |
{ | |
let html = fs::read_to_string("./index.html")?; | |
let suffix = &*html; | |
// Replace the title | |
let title_start = suffix.find("<title>").expect("could not find title"); | |
let (part0, suffix) = suffix.split_at(title_start); | |
let title_end = suffix.find("</title>").expect("could not find title"); | |
let (_title, suffix) = suffix.split_at(title_end); | |
let new_title = format!("<title>{}</title>", &true_title); | |
let new_html = if article.toc { | |
// rustdoc puts the TOC before our author/date header, so we need to hackily | |
// pull the header out and put it back before the header. | |
let article_start = suffix.find("<article").expect("could not find article"); | |
let (part1, suffix) = suffix.split_at(article_start); | |
let nav_start = suffix.find("<nav").expect("could not find nav"); | |
let (part2, suffix) = suffix.split_at(nav_start); | |
let hdr_start = suffix.find("<header>").expect("could not find standard author header"); | |
let (nav, suffix) = suffix.split_at(hdr_start); | |
let hdr_end = suffix.find("</header>").expect("could not find header end"); | |
let (hdr, suffix) = suffix.split_at(hdr_end); | |
format!("{}{}{}{}{}{}{}", part0, new_title, part1, part2, hdr, nav, suffix) | |
} else { | |
format!("{}{}{}", part0, new_title, suffix) | |
}; | |
let mut html_file = File::create("./index.html")?; | |
html_file.write_all(new_html.as_bytes())?; | |
} | |
let rss_item = format!(r#" | |
<item> | |
<title>{}</title> | |
<link>{}</link> | |
<description>{}</description> | |
<pubDate>{}</pubDate> | |
</item> | |
"#, | |
true_title, | |
true_link, | |
true_desc, | |
article.date); | |
rss.push_str(&rss_item); | |
env::set_current_dir("../")?; | |
println!(" done!"); | |
} | |
{ | |
// Finalize the RSS feed | |
rss.push_str(rss_end); | |
let mut rss_file = File::create("./rss.xml")?; | |
rss_file.write_all(rss.as_bytes())?; | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment