aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2017-11-24 18:45:37 -0800
committerBryan Newbold <bnewbold@robocracy.org>2017-11-24 18:45:37 -0800
commit9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0 (patch)
tree8ab695c63102700402eb7984d0099457cfd5a407
parent23a1fa44e8f69dedf23ea1e713a02b5112f9413a (diff)
downloadgeniza-9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0.tar.gz
geniza-9ca88a1ecdad6c492e1d07f7fff77e199a5fefd0.zip
import/export drive directories
-rw-r--r--src/bin/geniza-drive.rs31
-rw-r--r--src/drive.rs85
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;