diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-02-01 17:41:08 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-02-01 17:41:08 +1300 |
commit | 35a4fc3c3e1871cb0b4a8bf243d5b97f0e827628 (patch) | |
tree | ef5ef9f672a5104b1225e06a98d244c3080881ee /src | |
parent | 480bc790bdf4c8e64bd7a3a99884a6bcc1e17055 (diff) | |
download | toaster-35a4fc3c3e1871cb0b4a8bf243d5b97f0e827628.zip |
Set last-modified time of generated files same as source file
When generating a file from a source file, the last-modified time
of the generated file will be set to be the same as the last-modified
time of the source file. This is so that when copying the generated
website to a server with rsync, only modified files will be copied
over, saving considerable time.
This commit also updates vagabond to the latest version which includes
a change where files are only copied if they have been modified or if
they haven't yet been copied. This saves considerable time when
generating the website, if the website contains large static files.
Diffstat (limited to 'src')
-rw-r--r-- | src/collect_files.rs | 53 | ||||
-rw-r--r-- | src/main.rs | 25 |
2 files changed, 44 insertions, 34 deletions
diff --git a/src/collect_files.rs b/src/collect_files.rs index de577cf..4eee1dc 100644 --- a/src/collect_files.rs +++ b/src/collect_files.rs @@ -10,19 +10,20 @@ pub struct Website { pub config: HashMap<String, String>, pub pages: Vec<Page>, pub redirects: Vec<Redirect>, - pub static_files: Vec<StaticItem>, - pub static_dirs: Vec<StaticItem>, + pub static_files: Vec<StaticItem>, // Redirects, !-prefixed-dir contents + pub static_dirs: Vec<StaticItem>, // Only !-prefixed static dirs } pub struct Page { - pub name: String, // Display name of this page - pub name_url: String, // URL name for this page, no extension - pub full_url: String, // Full URL for this page, no extension - pub parents: Vec<String>, // Parent directory components, unsafe - pub parent_url: String, // Base URL for links in this page - pub source_path: PathBuf, // Absolute path to source file - pub document: MarkdownDocument, // File content parsed as markdown - pub headings: Vec<Heading>, // Ordered list of all headings in page + pub name: String, // Display name of this page + pub name_url: String, // URL name for this page, no extension + pub full_url: String, // Full URL for this page, no extension + pub parents: Vec<String>, // Parent directory components, unsafe + pub parent_url: String, // Base URL for links in this page + pub source_path: PathBuf, // Absolute path to source file + pub document: MarkdownDocument, // File content parsed as markdown + pub headings: Vec<Heading>, // Ordered list of all headings in page + pub last_modified: Option<SystemTime>, // last-modified time of source file } pub struct Heading { @@ -32,16 +33,18 @@ pub struct Heading { } pub struct StaticItem { - pub full_url: String, // Safe full URL, with extension - pub source_path: PathBuf, // Absolute path to source file + pub full_url: String, // Safe full URL, with extension + pub source_path: PathBuf, // Absolute path to source file + pub last_modified: Option<SystemTime>, // last-modified time of source file } pub struct Redirect { - pub name: String, // Display name of this redirect - pub full_url: String, // Safe full URL, no extension - pub parents: Vec<String>, // Parent directory components, unsafe - pub parent_url: String, // Base URL for relative redirects - pub redirect: String, // Page to redirect to, as an internal link + pub name: String, // Display name of this redirect + pub full_url: String, // Safe full URL, no extension + pub parents: Vec<String>, // Parent directory components, unsafe + pub parent_url: String, // Base URL for relative redirects + pub redirect: String, // Page to redirect to, as an internal link + pub last_modified: Option<SystemTime>, // last-modified time of source file } pub trait LinkFrom { @@ -110,6 +113,8 @@ impl Website { } } let name_url = make_url_safe(&name); + // Get last-modified time. + let last_modified = entry.last_modified; // Generate parent URL, used only for files. let source_path = entry.original_path.clone(); let relative_path = source_path.strip_prefix(prefix).unwrap_or_else( @@ -128,10 +133,10 @@ impl Website { |_| error!("Path doesn't start with {prefix:?}: {source_path:?}")) .as_os_str().to_string_lossy().to_string(); let full_url = format!("{stripped}/{relative_path}"); - self.static_files.push(StaticItem { full_url, source_path }) + self.static_files.push(StaticItem { full_url, source_path, last_modified }) } let full_url = make_url_safe(stripped); - self.static_dirs.push(StaticItem { full_url, source_path }); + self.static_dirs.push(StaticItem { full_url, source_path, last_modified }); } else { for child in list_directory(entry.original_path).unwrap() { self.collect_entry(&child.original_path, prefix); @@ -191,6 +196,7 @@ impl Website { source_path, document, headings, + last_modified, }); } else { // This is an index file for a directory. @@ -213,6 +219,7 @@ impl Website { source_path, document, headings, + last_modified, }); } } else { @@ -229,6 +236,7 @@ impl Website { parents, parent_url, source_path, document, headings, + last_modified, }); } }, @@ -242,7 +250,10 @@ impl Website { full_url.push_str(&name_url); let redirect = std::fs::read_to_string(&source_path) .unwrap().trim().to_string(); - self.redirects.push(Redirect { name, full_url, parents, parent_url, redirect }); + self.redirects.push(Redirect { + name, full_url, parents, parent_url, + redirect, last_modified, + }); } _ => { let mut parent_url = String::new(); @@ -251,7 +262,7 @@ impl Website { parent_url.push('/'); } let full_url = format!("{parent_url}{name_url}.{extension}"); - self.static_files.push(StaticItem { full_url, source_path }); + self.static_files.push(StaticItem { full_url, source_path, last_modified }); }, } } diff --git a/src/main.rs b/src/main.rs index 2920917..25d1528 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use markdown::*; use vagabond::*; use std::collections::HashSet; +use std::time::SystemTime; const NORMAL: &str = "\x1b[0m"; @@ -95,7 +96,7 @@ fn main() { // Convert document to different formats. if args.html { let html = generate_html(&page.document, page, &website); - write_file(&html, &destination, "html"); + write_file(&html, &destination, "html", page.last_modified); } // Copy original markdown file. destination.add_extension("md"); @@ -115,15 +116,7 @@ fn main() { static_file.source_path, destination)); } - for static_dir in &website.static_dirs { - let mut destination = destination.clone(); - destination.push(&static_dir.full_url); - verbose!("Copying static directory to {destination:?}"); - make_parent_directory(&destination).unwrap(); - copy(&static_dir.source_path, &destination).unwrap_or_else(|_| - error!("Failed to copy static directory {:?} to {:?}", - static_dir.source_path, destination)); - } + // NOTE: Static dir contents are copied as part of all static files. for redirect in &website.redirects { let mut destination = destination.clone(); @@ -132,12 +125,12 @@ fn main() { if args.html { if !path.contains("://") { if let Some(path) = website.has_page(redirect, &path, "html") { - write_file(&generate_html_redirect(&path), &destination, "html"); + write_file(&generate_html_redirect(&path), &destination, "html", redirect.last_modified); } else { warn!("Redirect {:?} links to nonexistent page {path:?}", redirect.name); } } else { - write_file(&generate_html_redirect(&path), &destination, "html"); + write_file(&generate_html_redirect(&path), &destination, "html", redirect.last_modified); } } } @@ -145,7 +138,7 @@ fn main() { -pub fn write_file(text: &str, destination: &PathBuf, ext: &str) { +pub fn write_file(text: &str, destination: &PathBuf, ext: &str, last_modified: Option<SystemTime>) { let mut destination = destination.clone(); destination.add_extension(ext); verbose!("Generating {destination:?}"); @@ -153,6 +146,12 @@ pub fn write_file(text: &str, destination: &PathBuf, ext: &str) { error!("Failed to create parent directories for {destination:?}")); write_to_file(&destination, text).unwrap_or_else(|_| error!("Failed to write generated {ext} file to {destination:?}")); + // Set the last-modified time of the new file to the time provided. + if let Some(time) = last_modified { + if let Ok(dest) = std::fs::File::open(&destination) { + let _ = dest.set_modified(time); + } + } } pub fn make_url_safe(text: &str) -> String { |