Merge b10698aa15
into a7517106e8
This commit is contained in:
commit
5d9fc679fc
|
@ -131,7 +131,7 @@ checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
|||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -160,6 +160,18 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.28"
|
||||
|
@ -407,6 +419,7 @@ name = "obsidian-export"
|
|||
version = "23.12.0"
|
||||
dependencies = [
|
||||
"eyre",
|
||||
"filetime",
|
||||
"gumdrop",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
|
@ -618,7 +631,7 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -754,7 +767,7 @@ dependencies = [
|
|||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -915,7 +928,16 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -924,13 +946,28 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -939,42 +976,84 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
|
|
|
@ -40,6 +40,7 @@ serde_yaml = "0.9.27"
|
|||
slug = "0.1.5"
|
||||
snafu = "0.7.5"
|
||||
unicode-normalization = "0.1.22"
|
||||
filetime = "0.2.23"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
|
|
49
src/lib.rs
49
src/lib.rs
|
@ -14,6 +14,7 @@ pub use context::Context;
|
|||
pub use frontmatter::{Frontmatter, FrontmatterStrategy};
|
||||
pub use walker::{vault_contents, WalkOptions};
|
||||
|
||||
use filetime::set_file_mtime;
|
||||
use frontmatter::{frontmatter_from_str, frontmatter_to_str};
|
||||
use pathdiff::diff_paths;
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
|
@ -165,6 +166,20 @@ pub enum ExportError {
|
|||
source: ignore::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to read the mtime of '{}'", path.display()))]
|
||||
/// This occurs when a file's modified time cannot be read
|
||||
ModTimeReadError {
|
||||
path: PathBuf,
|
||||
source: std::io::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("Failed to set the mtime of '{}'", path.display()))]
|
||||
/// This occurs when a file's modified time cannot be set
|
||||
ModTimeSetError {
|
||||
path: PathBuf,
|
||||
source: std::io::Error,
|
||||
},
|
||||
|
||||
#[snafu(display("No such file or directory: {}", path.display()))]
|
||||
/// This occurs when an operation is requested on a file or directory which does not exist.
|
||||
PathDoesNotExist { path: PathBuf },
|
||||
|
@ -231,6 +246,7 @@ pub struct Exporter<'a> {
|
|||
vault_contents: Option<Vec<PathBuf>>,
|
||||
walk_options: WalkOptions<'a>,
|
||||
process_embeds_recursively: bool,
|
||||
preserve_mtime: bool,
|
||||
postprocessors: Vec<&'a Postprocessor<'a>>,
|
||||
embed_postprocessors: Vec<&'a Postprocessor<'a>>,
|
||||
}
|
||||
|
@ -247,6 +263,7 @@ impl<'a> fmt::Debug for Exporter<'a> {
|
|||
"process_embeds_recursively",
|
||||
&self.process_embeds_recursively,
|
||||
)
|
||||
.field("preserve_mtime", &self.preserve_mtime)
|
||||
.field(
|
||||
"postprocessors",
|
||||
&format!("<{} postprocessors active>", self.postprocessors.len()),
|
||||
|
@ -273,6 +290,7 @@ impl<'a> Exporter<'a> {
|
|||
frontmatter_strategy: FrontmatterStrategy::Auto,
|
||||
walk_options: WalkOptions::default(),
|
||||
process_embeds_recursively: true,
|
||||
preserve_mtime: false,
|
||||
vault_contents: None,
|
||||
postprocessors: vec![],
|
||||
embed_postprocessors: vec![],
|
||||
|
@ -313,6 +331,15 @@ impl<'a> Exporter<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set whether the modified time of exported files should be preserved.
|
||||
///
|
||||
/// When `preserve` is true, the modified time of exported files will be set to the modified
|
||||
/// time of the source file.
|
||||
pub fn preserve_mtime(&mut self, preserve: bool) -> &mut Exporter<'a> {
|
||||
self.preserve_mtime = preserve;
|
||||
self
|
||||
}
|
||||
|
||||
/// Append a function to the chain of [postprocessors][Postprocessor] to run on exported Obsidian Markdown notes.
|
||||
pub fn add_postprocessor(&mut self, processor: &'a Postprocessor) -> &mut Exporter<'a> {
|
||||
self.postprocessors.push(processor);
|
||||
|
@ -388,11 +415,19 @@ impl<'a> Exporter<'a> {
|
|||
}
|
||||
|
||||
fn export_note(&self, src: &Path, dest: &Path) -> Result<()> {
|
||||
match is_markdown_file(src) {
|
||||
let result = match is_markdown_file(src) {
|
||||
true => self.parse_and_export_obsidian_note(src, dest),
|
||||
false => copy_file(src, dest),
|
||||
}
|
||||
.context(FileExportSnafu { path: src })
|
||||
.context(FileExportSnafu { path: src });
|
||||
|
||||
if self.preserve_mtime {
|
||||
if let Ok(()) = result {
|
||||
copy_mtime(src, dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_and_export_obsidian_note(&self, src: &Path, dest: &Path) -> Result<()> {
|
||||
|
@ -762,6 +797,16 @@ fn create_file(dest: &Path) -> Result<File> {
|
|||
Ok(file)
|
||||
}
|
||||
|
||||
fn copy_mtime(src: &Path, dest: &Path) -> Result<()> {
|
||||
let metadata = fs::metadata(src).context(ModTimeReadSnafu { path: src })?;
|
||||
let modified_time = metadata
|
||||
.modified()
|
||||
.context(ModTimeReadSnafu { path: src })?;
|
||||
|
||||
set_file_mtime(dest, modified_time.into()).context(ModTimeSetSnafu { path: dest })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn copy_file(src: &Path, dest: &Path) -> Result<()> {
|
||||
std::fs::copy(src, dest)
|
||||
.or_else(|err| {
|
||||
|
|
|
@ -54,6 +54,13 @@ struct Opts {
|
|||
#[options(no_short, help = "Don't process embeds recursively", default = "false")]
|
||||
no_recursive_embeds: bool,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Preserve the mtime of exported files",
|
||||
default = "false"
|
||||
)]
|
||||
preserve_mtime: bool,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Convert soft line breaks to hard line breaks. This mimics Obsidian's 'Strict line breaks' setting",
|
||||
|
@ -94,6 +101,7 @@ fn main() {
|
|||
let mut exporter = Exporter::new(root, destination);
|
||||
exporter.frontmatter_strategy(args.frontmatter_strategy);
|
||||
exporter.process_embeds_recursively(!args.no_recursive_embeds);
|
||||
exporter.preserve_mtime(args.preserve_mtime);
|
||||
exporter.walk_options(walk_options);
|
||||
|
||||
if args.hard_linebreaks {
|
||||
|
|
|
@ -358,6 +358,44 @@ fn test_no_recursive_embeds() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preserve_mtime() {
|
||||
let tmp_dir = TempDir::new().expect("failed to make tempdir");
|
||||
|
||||
let mut exporter = Exporter::new(
|
||||
PathBuf::from("tests/testdata/input/main-samples/"),
|
||||
tmp_dir.path().to_path_buf(),
|
||||
);
|
||||
exporter.preserve_mtime(true);
|
||||
exporter.run().expect("exporter returned error");
|
||||
|
||||
let src = "tests/testdata/input/main-samples/obsidian-wikilinks.md";
|
||||
let dest = tmp_dir.path().join(PathBuf::from("obsidian-wikilinks.md"));
|
||||
let src_meta = std::fs::metadata(src).unwrap();
|
||||
let dest_meta = std::fs::metadata(dest).unwrap();
|
||||
|
||||
assert_eq!(src_meta.modified().unwrap(), dest_meta.modified().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_no_preserve_mtime() {
|
||||
let tmp_dir = TempDir::new().expect("failed to make tempdir");
|
||||
|
||||
let mut exporter = Exporter::new(
|
||||
PathBuf::from("tests/testdata/input/main-samples/"),
|
||||
tmp_dir.path().to_path_buf(),
|
||||
);
|
||||
exporter.preserve_mtime(false);
|
||||
exporter.run().expect("exporter returned error");
|
||||
|
||||
let src = "tests/testdata/input/main-samples/obsidian-wikilinks.md";
|
||||
let dest = tmp_dir.path().join(PathBuf::from("obsidian-wikilinks.md"));
|
||||
let src_meta = std::fs::metadata(src).unwrap();
|
||||
let dest_meta = std::fs::metadata(dest).unwrap();
|
||||
|
||||
assert_ne!(src_meta.modified().unwrap(), dest_meta.modified().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_ascii_filenames() {
|
||||
let tmp_dir = TempDir::new().expect("failed to make tempdir");
|
||||
|
|
Loading…
Reference in New Issue