candentia 0.2.0

A cli tool for managing CT-Scan data to study evolutionary biology
use std::fs;
use std::path::{Path, PathBuf};

use regex::Regex;

const VOUCHER_NAME: &str = r"^\D+(_\d{3,10})";

pub struct Organizer<'a> {
    pub scans: &'a [PathBuf],
    pub output: &'a Path,
}

impl<'a> Organizer<'a> {
    pub fn new(scans: &'a [PathBuf], output: &'a Path) -> Self {
        Self { scans, output }
    }

    pub fn organize(&self) {
        log::info!("{:18}: {}", "File counts", self.scans.len());
        self.scans.iter().for_each(|scan| {
            let scan_name = scan
                .file_name()
                .expect("Scan has no name")
                .to_string_lossy()
                .to_string();
            let voucher_name = match self.capture_voucher_name(&scan_name) {
                Some(name) => name,
                None => {
                    eprintln!("Could not capture voucher name from {}", scan_name);
                    return;
                }
            };

            let voucher_path = self.output.join(voucher_name);
            fs::create_dir_all(&voucher_path).expect("Could not create voucher directory");
            fs::rename(scan, voucher_path.join(&scan_name)).expect("Could not move scan");
        });
        log::info!("Done");
    }

    fn capture_voucher_name(&self, name: &str) -> Option<String> {
        let re = Regex::new(VOUCHER_NAME).expect("Invalid regex");
        re.captures(name).map(|cap| cap[0].to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_capture_voucher_name() {
        let organizer = Organizer::new(&[], &Path::new(""));
        let name = "Uromys_spce_MUSEUM_12345_2080_1066_960_2027_0.0119013mm_16be_un.raw";
        let voucher_name = organizer.capture_voucher_name(name);
        assert_eq!(voucher_name, Some("Uromys_spce_MUSEUM_12345".to_string()));
    }
}