diff options
author | Bryan Newbold <bnewbold@robocracy.org> | 2017-11-24 18:45:37 -0800 |
---|---|---|
committer | Bryan Newbold <bnewbold@robocracy.org> | 2017-11-24 18:45:37 -0800 |
commit | 9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0 (patch) | |
tree | 8ab695c63102700402eb7984d0099457cfd5a407 /src | |
parent | 23a1fa44e8f69dedf23ea1e713a02b5112f9413a (diff) | |
download | geniza-9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0.tar.gz geniza-9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0.zip |
import/export drive directories
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/geniza-drive.rs | 31 | ||||
-rw-r--r-- | src/drive.rs | 85 |
2 files changed, 116 insertions, 0 deletions
diff --git a/src/bin/geniza-drive.rs b/src/bin/geniza-drive.rs index d402539..42e06e2 100644 --- a/src/bin/geniza-drive.rs +++ b/src/bin/geniza-drive.rs @@ -52,6 +52,18 @@ fn run() -> Result<()> { .arg_from_usage("--target <path> 'path to save the file to (if not same name)'") ) .subcommand( + SubCommand::with_name("import-dir") + .about("Adds a directory (recursively) to the dat") + .arg_from_usage("<DIR> 'directory to add'") + .arg_from_usage("--target <path> 'path to import the file to (if not top level)'") + ) + .subcommand( + SubCommand::with_name("export-dir") + .about("Copies a directory (recursively) from dat archive to local disk") + .arg_from_usage("<DIR> 'directory to export'") + .arg_from_usage("--target <path> 'path to save the directory to (if not same name)'") + ) + .subcommand( SubCommand::with_name("log") .about("History of additions/deletions from this dat") ) @@ -122,6 +134,25 @@ fn run() -> Result<()> { }; drive.export_file(&path, &fpath)?; } + ("import-dir", Some(subm)) => { + let path = Path::new(subm.value_of("DIR").unwrap()); + let mut drive = DatDrive::open(dir, true)?; + let fpath = match subm.value_of("target") { + None => Path::new("/").join(path.file_name().unwrap()), + Some(p) => Path::new("/").join(p) + }; + drive.import_dir(&path, &fpath)?; + + } + ("export-dir", Some(subm)) => { + let path = Path::new(subm.value_of("DIR").unwrap()); + let mut drive = DatDrive::open(dir, true)?; + let fpath = match subm.value_of("target") { + None => Path::new("/").join(path.file_name().unwrap()), + Some(p) => Path::new("/").join(p) + }; + drive.export_dir(&path, &fpath)?; + } ("log", Some(_subm)) => { let mut drive = DatDrive::open(dir, false)?; for entry in drive.history(0) { diff --git a/src/drive.rs b/src/drive.rs index a4e6cf9..360555b 100644 --- a/src/drive.rs +++ b/src/drive.rs @@ -464,6 +464,56 @@ impl<'a> DatDrive { Ok(()) } + /// Copies Stat metadata and all content from a directory (recursively) from the "real" + /// filesystem into the DatDrive. + /// On success, returns version number including all the added files. + pub fn import_dir<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<u64> { + let source = source.as_ref(); + let dest = dest.as_ref(); + // TODO: check that dest doesn't exist (or is directory) + let nearest = self.get_nearest(dest)?; + if let Some(nearest) = nearest { + if nearest.path == dest { + bail!("destination already exists (as a file)"); + } + } + let mut ret = self.entry_count()?; + if source.is_dir() { + for entry in read_dir(source)? { + let entry = entry?; + let path = entry.path(); + let fname = path.file_name().unwrap().to_owned(); + if fname.to_str() == Some(".dat") { + // Don't import yourself! + continue + } + if path.is_dir() { + ret = self.import_dir(path, dest.join(fname))?; + } else { + ret = self.import_file(path, dest.join(fname))?; + } + } + } else { + bail!("Source path wasn't a directory"); + } + Ok(ret) + } + + /// Copies a file from the drive to the "real" filesystem, preserving Stat metadata. + pub fn export_dir<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> { + let source = source.as_ref(); + let dest = dest.as_ref(); + // TODO: this collect() is inefficient; read doesn't mutate, so shouldn't really need a + // mutable borrow + let path_list: Vec<Result<DriveEntry>> = self.read_dir_recursive(source).collect(); + for entry in path_list { + let path = entry?.path.to_owned(); + let out_path = dest.join(path.strip_prefix(source).unwrap()); + self.export_file(path, out_path)?; + } + Ok(()) + } + pub fn read_file_bytes<P: AsRef<Path>>(&mut self, path: P) -> Result<Vec<u8>> { let de = self.get_file_entry(path.as_ref())?; if let Some(entry) = de { @@ -703,6 +753,41 @@ fn test_dd_export_file() { } #[test] +fn test_dd_import_dir() { + + use tempdir::TempDir; + use env_logger; + env_logger::init().unwrap(); + let tmp_dir = TempDir::new("geniza-test").unwrap(); + let mut dd = DatDrive::create(tmp_dir.path()).unwrap(); + + dd.import_dir("test-data/dat/tree/Animalia/", "/").unwrap(); + + assert_eq!(dd.read_dir("/").count(), 0); + assert_eq!(dd.read_dir_recursive("/").count(), 2); + + dd.import_file("test-data/dat/alphabet/a", "/a").unwrap(); + assert!(dd.import_dir("test-data/dat/tree/Animalia/", "/a/").is_err()); + +} + +#[test] +fn test_dd_export_dir() { + + use tempdir::TempDir; + //use env_logger; + //env_logger::init().unwrap(); + let tmp_dir = TempDir::new("geniza-test").unwrap(); + let mut dd = DatDrive::create(tmp_dir.path()).unwrap(); + + dd.import_dir("test-data/dat/tree/Animalia/", "/").unwrap(); + + dd.export_dir("/", tmp_dir.path()).unwrap(); + dd.export_dir("/Chordata/Mammalia/Carnivora/Caniformia/", tmp_dir.path()).unwrap(); + //assert!(dd.export_dir("/Fruit/", tmp_dir.path()).is_err()); +} + +#[test] fn test_dd_remove_file() { use tempdir::TempDir; |