about summary refs log tree commit diff
path: root/src/atom/mod.rs
blob: 2020163b0a9d9ea570e659009beb493778c5c214 (plain)
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
mod urn;

use std::str::FromStr;

use bempline::{variables, Document, Options};
use camino::{Utf8Path, Utf8PathBuf};
use confindent::{let_get, Confindent, Entry, Node};
use time::{format_description::well_known, OffsetDateTime};
use urn::Urn;

use crate::{markup, templated::Templated, timeparse};

pub fn main() -> ! {
	let awake_conf = Confindent::from_file(std::env::args().nth(2).unwrap()).unwrap();

	let root: Utf8PathBuf = awake_conf.child_parse("Webroot").unwrap();

	// Grab the atom config and then grab the atom template
	let atom_conf_path = std::env::args().nth(3).unwrap_or(String::from("atom.conf"));
	let mut atom_conf = Confindent::from_file(&atom_conf_path).unwrap();
	let atom = Document::from_file(
		root.clone()
			.join(atom_conf.child_value("Template").unwrap())
			.canonicalize_utf8()
			.unwrap(),
		Options::default(),
	)
	.unwrap();

	let mut changed = false;
	// Go through every feed and create the entries
	let feeds = atom_conf.children_mut("Feed");
	for feed in feeds {
		make_feed(feed, &mut changed, &root, atom.clone())
	}

	// If the atom has changed, probably because we created an ID
	// write it to disk.
	if changed {
		std::fs::write(atom_conf_path, atom_conf.to_string());
	}

	std::process::exit(0);
}

pub struct AtomFeed {
	/// Where is the atom located in the webroot. (relative to webroot)
	relpath: Utf8PathBuf,
	/// What unique ID does this Feed have?
	id: String,

	title: String,
	subtitle: String,
	updated: OffsetDateTime,
	author_name: String,
	author_email: String,

	entries: Vec<AtomEntry>,
}

pub struct AtomEntry {
	/// What file does this entry direct to? This file will be opened to inspect
	/// the frontmatter for information to fill out the entry with. It will also
	/// be used to create the link to the entry.
	relpath: Utf8PathBuf,
	/// What unique ID does this Entry have?
	id: String,

	title: String,
	published: OffsetDateTime,
	updated: OffsetDateTime,
}

/// Parses all the options of a feed and generates the build job
pub fn make_feed(feed: &mut Entry, changed: &mut bool, root: &Utf8Path, mut atom: Document) {
	let_get!(
		feed,
		relpath: Utf8PathBuf = "Output",
		clone id = "Id",
		clone title = "Title",
		clone subtitle = "Subtitle",
		clone updated = "Updated",
	);

	//FIXME: gen- We need to backresolve the feed URL
	let feed_link = "";
	let author_name = feed.get("Author/Name").unwrap().to_owned();
	let author_email = feed.get("Author/Email").unwrap().to_owned();

	let mut atomfeed = AtomFeed {
		relpath,
		id,
		title,
		subtitle,
		updated: timeparse::parse(&updated).unwrap(),
		author_name,
		author_email,
		entries: vec![],
	};

	let entries = feed.children_mut("Entry");
	for entry in entries {
		if !entry.has_child("Id") {
			//TODO: gen- Read NID from conf?
			let id = Urn::new_random("dreamy");
			entry.push_entry(("Id", id));
			*changed = true;
		}

		atomfeed.entries.push(make_entry(entry, &root));
	}
}

fn make_entry<P: AsRef<Utf8Path>>(entry: &Entry, webroot: P) -> AtomEntry {
	let relpath: Utf8PathBuf = entry.parse().unwrap();
	let path = webroot.as_ref().join(&relpath);

	let entry_content = match std::fs::read_to_string(&path) {
		Ok(ok) => ok,
		Err(e) => {
			panic!("failed to get file at {path}: {e}");
		}
	};
	let entry_templated = Templated::from_str(&entry_content).unwrap();

	let conf_or_frontmatter = |conf_key: &str, front_key: &str| -> &str {
		entry
			.child_value(conf_key)
			.unwrap_or_else(|| entry_templated.frontmatter.get(front_key).unwrap())
	};

	let title = conf_or_frontmatter("Title", "title").to_owned();
	let id = entry.child_value("Id").unwrap().to_owned();

	let entry_published_raw = conf_or_frontmatter("Published", "published");

	let updated = timeparse::parse(entry.child_value("Updated").unwrap_or_else(|| {
		entry_templated
			.frontmatter
			.get("updated")
			.unwrap_or(entry_published_raw)
	}))
	.unwrap();

	let published = timeparse::parse(entry_published_raw).unwrap();

	AtomEntry {
		relpath,
		id,
		title,
		published,
		updated,
	}
}