summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-02-01 17:41:08 +1300
committerBen Bridle <ben@derelict.engineering>2025-02-01 17:41:08 +1300
commit35a4fc3c3e1871cb0b4a8bf243d5b97f0e827628 (patch)
treeef5ef9f672a5104b1225e06a98d244c3080881ee
parent480bc790bdf4c8e64bd7a3a99884a6bcc1e17055 (diff)
downloadtoaster-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.
-rw-r--r--Cargo.lock4
-rw-r--r--Cargo.toml2
-rw-r--r--src/collect_files.rs53
-rw-r--r--src/main.rs25
4 files changed, 47 insertions, 37 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b1a9231..b4c5475 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -24,8 +24,8 @@ dependencies = [
[[package]]
name = "vagabond"
-version = "1.0.3"
-source = "git+git://benbridle.com/vagabond?tag=v1.0.3#fb80ee168e1977230680115304103b80ccf7f1ac"
+version = "1.1.0"
+source = "git+git://benbridle.com/vagabond?tag=v1.1.0#6e759a3abb3bc3e5da42d69a6f20ec2c31eb33de"
[[package]]
name = "xflags"
diff --git a/Cargo.toml b/Cargo.toml
index fcda53a..4234ef9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ version = "1.7.0"
edition = "2021"
[dependencies]
-vagabond = { git = "git://benbridle.com/vagabond", tag = "v1.0.3" }
+vagabond = { git = "git://benbridle.com/vagabond", tag = "v1.1.0" }
markdown = { git = "git://benbridle.com/markdown", tag = "v3.1.0" }
recipe = { git = "git://benbridle.com/recipe", tag = "v1.4.0" }
xflags = "0.4.0-pre.1"
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 {