From 7c0b7f51023c3608825774f7a4921fd6a249273e Mon Sep 17 00:00:00 2001 From: Lia Lenckowski Date: Thu, 7 Sep 2023 23:26:25 +0200 Subject: copy and symlink output modes --- Cargo.lock | 45 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/main.rs | 48 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 571f48d..0737d92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,8 +288,10 @@ dependencies = [ "clap", "image", "indicatif", + "pathdiff", "priority-queue", "rayon", + "reflink-copy", "serde", "serde_json", "sha2", @@ -495,6 +497,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ioctl-sys" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c" + [[package]] name = "itoa" version = "1.0.9" @@ -658,6 +666,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pin-project" version = "1.1.3" @@ -765,6 +779,18 @@ dependencies = [ "bitflags", ] +[[package]] +name = "reflink-copy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b9fdc4b74744920661b70bc8daa091791c1f6940d7f9a90338754532237c29" +dependencies = [ + "cfg-if", + "ioctl-sys", + "libc", + "windows", +] + [[package]] name = "ryu" version = "1.0.15" @@ -1035,6 +1061,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 7335a70..f066eae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,5 @@ serde = "1" serde_json = "1" sha2 = "0" anyhow = "1" +pathdiff = "0" +reflink-copy = "0" diff --git a/src/main.rs b/src/main.rs index 1872e31..6337b14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ -#![feature(iterator_try_collect)] +#![feature(iterator_try_collect, absolute_path)] use anyhow::Result; use clap::Parser; use priority_queue::PriorityQueue; use sha2::{Sha512_256, Digest}; -use std::{cmp::Ordering, collections::HashMap, fs, io, io::Write, path::PathBuf}; +use std::{cmp::Ordering, collections::HashMap, fs, io, io::Write, path, path::PathBuf}; use embedders::*; use pure_embedders::*; @@ -28,11 +28,11 @@ struct Args { embedder: Embedder, /// Symlink the sorted images into this directory - #[arg(short = 'o', long)] + #[arg(short = 's', long)] symlink_dir: Option, - /// Copy the sorted images into this directory. TODO uses COW when available - #[arg(short = 's', long)] + /// Copy the sorted images into this directory. Uses COW when available + #[arg(short = 'o', long)] copy_dir: Option, /// Write sorted paths into stdout, one per line @@ -186,8 +186,36 @@ fn process_embedder(mut e: E, args: &Args, cfg: &Config) -> Result Result<()> {todo!()} -fn copy_into(tsp: &[PathBuf], target: &PathBuf) -> Result<()> {todo!()} +fn symlink_into(tsp: &[PathBuf], target: &PathBuf) -> Result<()> { + fs::create_dir_all(target)?; + + let pad_len = (tsp.len() as f64).log10().ceil() as usize; + for (i, p) in tsp.iter().enumerate() { + let ext: String = match p.extension() { + None => "".to_string(), + Some(e) => format!(".{}", e.to_str().unwrap()), + }; + let tp = target.join(format!("{:0pl$}{ext}", i, pl = pad_len, ext = ext)); + let rel_path = pathdiff::diff_paths(path::absolute(p)?, + path::absolute(target)?).unwrap(); + std::os::unix::fs::symlink(rel_path, tp); + } + Ok(()) +} +fn copy_into(tsp: &[PathBuf], target: &PathBuf) -> Result<()> { + fs::create_dir_all(target)?; + + let pad_len = (tsp.len() as f64).log10().ceil() as usize; + for (i, p) in tsp.iter().enumerate() { + let ext: String = match p.extension() { + None => "".to_string(), + Some(e) => format!(".{}", e.to_str().unwrap()), + }; + let tp = target.join(format!("{:0pl$}{ext}", i, pl = pad_len, ext = ext)); + reflink_copy::reflink_or_copy(p, tp)?; + } + Ok(()) +} fn main() -> Result<()> { let cfg = get_config()?; @@ -200,11 +228,11 @@ fn main() -> Result<()> { Embedder::Content => process_embedder(ContentEmbedder::new(&cfg), &args, &cfg), }?; - args.symlink_dir.into_iter().try_for_each(|p| symlink_into(&tsp_path, &p))?; - args.copy_dir .into_iter().try_for_each(|p| copy_into(&tsp_path, &p))?; + if let Some(p) = args.symlink_dir { symlink_into(&tsp_path, &p)? } + if let Some(p) = args.copy_dir { copy_into(&tsp_path, &p)? } let path_delim = if args.stdout0 { Some(0) } - else if args.stdout { Some(10) } + else if args.stdout { Some(b'\n') } else { None }; path_delim.into_iter().try_for_each(|delim| { -- cgit v1.2.3-70-g09d2