commit a10b02ce31440618574a3ca4b9049ad3b03d9476
parent c9357fc4f409a65f6f029104ac4001d53e11942d
Author: lash <dev@holbrook.no>
Date:   Sun, 25 Sep 2022 20:25:38 +0000
Prepare enable define multiple digest types for apply
Diffstat:
4 files changed, 95 insertions(+), 43 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -51,7 +51,12 @@ version = "0.7.1"
 version = "0.2.3"
 optional = true
 
+[dependencies.md5]
+version = "0.7.0"
+optional = true
+
 [features]
 #rdf = ["rio_turtle", "rio_api"]
 #dump_bibtex = ["biblatex"]
 magic = ["tree_magic"]
+digest_md5 = ["md5"]
diff --git a/src/digest.rs b/src/digest.rs
@@ -1,4 +1,5 @@
 use std::marker::Copy;
+use std::fmt;
 
 use crate::error::ParseError;
 
@@ -10,6 +11,12 @@ use sha2::{
 
 use log::error;
 
+pub enum DigestType {
+    Sha512,
+    #[cfg(feature="digest_md5")]
+    MD5,
+}
+
 /// Encapsulations of supported digests for digest data.
 pub enum RecordDigest {
     Sha512(Vec<u8>),
@@ -61,8 +68,36 @@ impl RecordDigest {
             },
         }
     }
+
+    /// Returns the digest value of the media as a hex-encoded string.
+    ///
+    /// TODO: implememt in fmt for digest instead
+    pub fn urn(&self) -> String {
+        match self {
+            RecordDigest::Empty => {
+                return String::new();
+            },
+            RecordDigest::Sha512(v) => {
+                return String::from("sha512:") + hex::encode(&v).as_str();
+            },
+            RecordDigest::Sha256(v) => {
+                return String::from("sha256:") + hex::encode(&v).as_str();
+            },
+            RecordDigest::MD5(v) => {
+                return String::from("md5:") + hex::encode(&v).as_str();
+            },
+            RecordDigest::SwarmHash(v) => {
+                return hex::encode(&v);
+            },
+        }
+    }
 }
 
+impl fmt::Debug for RecordDigest {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.urn())
+    }
+}
 
 /// Create a [RecordDigest::Sha512](RecordDigest::Sha512) instance from the raw digest data.
 ///
diff --git a/src/main.rs b/src/main.rs
@@ -38,10 +38,11 @@ use kitab::biblatex::{
 };
 use kitab::meta::{
     MetaData,
-    digest_from_path,
+    digests_from_path,
 };
 use kitab::digest::from_urn;
 use kitab::digest::RecordDigest;
+use kitab::digest::DigestType;
 
 
 fn args_setup() -> ArgMatches<'static> {
@@ -235,27 +236,30 @@ fn exec_import_biblatex(f: &Path, index_path: &Path, digests: &Vec<RecordDigest>
     true
 }
 
-fn exec_apply(p: &Path, index_path: &Path) -> bool {
+fn exec_apply(p: &Path, index_path: &Path, mut extra_digest_types: Vec<DigestType>) -> bool {
+    let mut digest_types: Vec<DigestType> = vec!(DigestType::Sha512);
+    digest_types.append(&mut extra_digest_types);
     for entry in WalkDir::new(&p)
         .into_iter()
         .filter_map(Result::ok)
         .filter(|e| !e.file_type().is_dir()) {
             let ep = entry.path();
-            let z = digest_from_path(ep);
-            let z_hex = hex::encode(z);
-
-            let fp = index_path.join(&z_hex);
-            match fp.canonicalize() {
-                Ok(v) => {
-                    let f = File::open(&v).unwrap();
-                    let m = rdf_read(f);
-                    info!("apply {:?} -> {:?} for {:?}", entry, &m, z_hex);
-                    m.to_xattr(&ep);
-                },
-                Err(e) => {
-                    debug!("metadata not found for {:?} -> {:?}", entry, z_hex);
-                },
-            };
+            for digest in digests_from_path(ep, &digest_types) {
+                let z_hex = hex::encode(digest.fingerprint());
+
+                let fp = index_path.join(&z_hex);
+                match fp.canonicalize() {
+                    Ok(v) => {
+                        let f = File::open(&v).unwrap();
+                        let m = rdf_read(f);
+                        info!("apply {:?} -> {:?} for {:?}", entry, &m, &digest);
+                        m.to_xattr(&ep);
+                    },
+                    Err(e) => {
+                        debug!("metadata not found for {:?} -> {:?}", entry, z_hex);
+                    },
+                };
+            }
     }
     true
 }
@@ -339,7 +343,7 @@ fn main() {
         Some(v) => {
             let p = str_to_path(v);
             info!("apply from path {:?}", &p);
-            if !exec_apply(p.as_path(), index_dir.as_path()) {
+            if !exec_apply(p.as_path(), index_dir.as_path(), vec!()) {
                 r = false; 
             }
         },
diff --git a/src/meta.rs b/src/meta.rs
@@ -25,6 +25,9 @@ use std::os::linux::fs::MetadataExt;
 
 use biblatex::EntryType;
 
+#[cfg(feature = "md5")]
+use md5::Context;
+
 #[cfg(feature = "magic")]
 use tree_magic;
 
@@ -65,13 +68,36 @@ pub struct MetaData {
     publish_date: PublishDate,
 }
 
+pub fn digests_from_path(filepath: &path::Path, digest_types: &Vec<digest::DigestType>) -> Vec<digest::RecordDigest> {
+    let mut r: Vec<digest::RecordDigest> = vec!();
+    for v in digest_types {
+        match v {
+            digest::DigestType::Sha512 => {
+                let digest = digest_sha512_from_path(filepath);
+                r.push(digest);
+            },
+            #[cfg(feature = "md5")]
+            digest::DigestType::MD5 => {
+                let digest = digest_md5_from_path(filepath);
+                r.push(digest);
+            },
+        };
+    }
+    r
+}
+
+#[cfg(feature = "md5")]
+pub fn digest_md5_from_path(filepath: &path::Path) -> digest::RecordDigest {
+    let ctx = md5::Context::new();
+    digest::RecordDigest::MD5(vec!())
+}
 
 /// Generates the native `sha512` digest of a file.
 ///
 /// # Arguments
 ///
 /// * `filepath` - Absolute path to file to calculate digest for.
-pub fn digest_from_path(filepath: &path::Path) -> Vec<u8> {
+pub fn digest_sha512_from_path(filepath: &path::Path) -> digest::RecordDigest {
     let mut h = Sha512::new();
     let st = metadata(filepath).unwrap();
     let bs: u64 = st.st_blksize();
@@ -84,7 +110,8 @@ pub fn digest_from_path(filepath: &path::Path) -> Vec<u8> {
         h.update(&b[..c]);
         i += c;
     }
-    h.finalize().to_vec()
+    let r = h.finalize().to_vec();
+    digest::RecordDigest::Sha512(r)
 }
 
 impl MetaData {
@@ -209,30 +236,11 @@ impl MetaData {
         self.dc.language.clone()
     }
 
-    /// Returns the digest value of the media as a hex-encoded string.
     ///
-    /// TODO: implememt in fmt for digest instead
     pub fn urn(&self) -> String {
-        match &self.digest {
-            digest::RecordDigest::Empty => {
-                return String::new();
-            },
-            digest::RecordDigest::Sha512(v) => {
-                return String::from("sha512:") + hex::encode(&v).as_str();
-            },
-            digest::RecordDigest::Sha256(v) => {
-                return String::from("sha256:") + hex::encode(&v).as_str();
-            },
-            digest::RecordDigest::MD5(v) => {
-                return String::from("md5:") + hex::encode(&v).as_str();
-            },
-            digest::RecordDigest::SwarmHash(v) => {
-                return hex::encode(&v);
-            },
-        }
+        self.digest.urn()
     }
 
-
     ///
     pub fn fingerprint(&self) -> String {
         let digest_fingerprint = self.digest.fingerprint();
@@ -248,8 +256,8 @@ impl MetaData {
         let filename: FileName; 
 
         debug!("Calculate digest for file {:?}",  &filepath);
-        let digest = digest_from_path(filepath);
-        debug!("Calculated digest {} for file {:?}", hex::encode(&digest), &filepath);
+        let digest = digest_sha512_from_path(filepath);
+        debug!("Calculated digest {} for file {:?}", hex::encode(digest.fingerprint()), &filepath);
 
         filename = filepath.file_name()
             .unwrap()
@@ -292,7 +300,7 @@ impl MetaData {
             None => {},
         }
 
-        let mut metadata = MetaData::new(title.as_str(), author.as_str(), typ, digest::RecordDigest::Sha512(digest), Some(filename));
+        let mut metadata = MetaData::new(title.as_str(), author.as_str(), typ, digest, Some(filename));
         if !metadata.validate() {
             return Err(ParseError::new("invalid input"));
         }