aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2017-10-29 13:59:47 -0700
committerBryan Newbold <bnewbold@robocracy.org>2017-10-29 13:59:47 -0700
commit58a0dc3387cfc88991bd93fad6d16a84bd7e4902 (patch)
tree02f5f783815f7f13b830d4cf261dfdb103816923
parentad63a8f64fa434c25ecd9e5d3437f6885f586706 (diff)
downloadgeniza-58a0dc3387cfc88991bd93fad6d16a84bd7e4902.tar.gz
geniza-58a0dc3387cfc88991bd93fad6d16a84bd7e4902.zip
progress on drive: basic history dump (un-pretty output)
-rw-r--r--src/bin/geniza-drive.rs70
-rw-r--r--src/drive.rs106
2 files changed, 145 insertions, 31 deletions
diff --git a/src/bin/geniza-drive.rs b/src/bin/geniza-drive.rs
new file mode 100644
index 0000000..05c7fb7
--- /dev/null
+++ b/src/bin/geniza-drive.rs
@@ -0,0 +1,70 @@
+// Free Software under GPL-3.0, see LICENSE
+// Copyright 2017 Bryan Newbold
+
+#[macro_use]
+extern crate clap;
+extern crate env_logger;
+#[macro_use]
+extern crate error_chain;
+extern crate geniza;
+
+// TODO: more careful import
+use geniza::*;
+use std::path::Path;
+use clap::{App, Arg, SubCommand};
+
+fn run() -> Result<()> {
+ env_logger::init().unwrap();
+
+ let matches = App::new("geniza-drive")
+ .version(env!("CARGO_PKG_VERSION"))
+ // TODO: dat-dir for all commands up here, and have a default vaule ('./dat')
+ .arg(Arg::with_name("dat-dir")
+ .short("d")
+ .long("dat-dir")
+ .value_name("PATH")
+ .help("dat drive directory")
+ .default_value(".dat") // TODO: needs to be default_value_os?
+ .takes_value(true))
+ .subcommand(
+ SubCommand::with_name("ls")
+ .about("Lists current files in this dat")
+ )
+ .subcommand(
+ SubCommand::with_name("log")
+ .about("History of additions/deletions from this dat")
+ )
+ .get_matches();
+
+/*
+ mode: ::std::option::Option<u32>,
+ uid: ::std::option::Option<u32>,
+ gid: ::std::option::Option<u32>,
+ size: ::std::option::Option<u64>,
+ blocks: ::std::option::Option<u64>,
+ offset: ::std::option::Option<u64>,
+ byteOffset: ::std::option::Option<u64>,
+ mtime: ::std::option::Option<u64>,
+ ctime: ::std::option::Option<u64>,
+*/
+
+ let dir = Path::new(matches.value_of("dat-dir").unwrap());
+ match matches.subcommand() {
+ ("ls", Some(_subm)) => {
+ }
+ ("log", Some(_subm)) => {
+ let mut drive = DatDrive::open(dir, false)?;
+ for entry in drive.history(1) {
+ println!("{:?}", entry?);
+ }
+ }
+ _ => {
+ println!("Missing or unimplemented command!");
+ println!("{}", matches.usage());
+ ::std::process::exit(-1);
+ }
+ }
+ Ok(())
+}
+
+quick_main!(run);
diff --git a/src/drive.rs b/src/drive.rs
index 179bebb..7369fb2 100644
--- a/src/drive.rs
+++ b/src/drive.rs
@@ -1,12 +1,12 @@
-use std::io::{Read, Write};
+use std::io::Read;
use std::path::Path;
-use protobuf::Message;
+//XXX: use protobuf::Message;
use protobuf::parse_from_bytes;
use errors::*;
use sleep_register::*;
-use metadata_msgs::{Index, Stat, Node};
+use metadata_msgs::{Stat, Node};
/// "Sort of" follows rust std::fs API for file system access.
pub struct DatDrive {
@@ -19,53 +19,76 @@ impl DatDrive {
/// Instantiates a drive in the given directory. Path should be the complete path (eg, ending
/// in '/.dat/'), not an enclosing directory containing files.
pub fn create<P: AsRef<Path>>(path: P) -> Result<DatDrive> {
+ // Calculate content discovery key and write as Index entry in metadata register
unimplemented!()
}
/// Path should be the complete path (eg, ending in '/.dat/'), not an enclosing directory
/// containing files.
- pub fn open<P: AsRef<Path>>(path: P) -> Result<DatDrive> {
- unimplemented!()
+ pub fn open<P: AsRef<Path>>(path: P, writable: bool) -> Result<DatDrive> {
+ let mdrive = SleepDirRegister::open(path.as_ref(), "metadata", writable)?;
+ if mdrive.len()? == 0 {
+ bail!("Expected at least one entry (Index) in metadata register");
+ }
+ let cdrive = SleepDirRegister::open(path.as_ref(), "content", writable)?;
+ Ok(DatDrive {
+ metadata: mdrive,
+ content: cdrive,
+ })
}
}
impl<'a> DatDrive {
- pub fn history(start: u64) -> DriveHistory<'a> {
+ fn find_path(path: &Path) -> Result<u64> {
unimplemented!()
}
- pub fn read_dir_recursive<P: AsRef<Path>>(path: P) -> ReadDriveDir<'a> {
+ pub fn history<'b>(&'b mut self, start: u64) -> DriveHistory<'b> {
+ // Start must be at least 1; index 0 is the Index item
+ let start = if start == 0 { 1 } else { start };
+ DriveHistory {
+ drive: self,
+ current: start,
+ }
+ }
+
+ pub fn read_dir_recursive<P: AsRef<Path>>(&mut self, path: P) -> ReadDriveDir<'a> {
unimplemented!()
}
- pub fn read_dir<P: AsRef<Path>>(path: P) -> ReadDriveDir<'a> {
+ pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> ReadDriveDir<'a> {
unimplemented!()
}
- pub fn file_metadata<P: AsRef<Path>>(path: P) -> Result<Stat> {
+ pub fn file_metadata<P: AsRef<Path>>(&mut self, path: P) -> Result<Stat> {
unimplemented!()
}
- pub fn create_file_bytes<P: AsRef<Path>>(path: P, stat: &Stat, data: &[u8]) -> Result<()> {
+ pub fn create_file_bytes<P: AsRef<Path>>(&mut self, path: P, stat: &Stat, data: &[u8]) -> Result<()> {
unimplemented!()
}
- pub fn create_file<P: AsRef<Path>, R: Read>(path: P, stat: &Stat, source: R) -> Result<()> {
+ pub fn create_file<P: AsRef<Path>, R: Read>(&mut self, path: P, stat: &Stat, source: R) -> Result<()> {
unimplemented!()
}
/// Copies Stat metadata and all content from a file in the "real" filesystem into the
/// DatDrive.
- pub fn import_file<P: AsRef<Path>, Q: AsRef<Path>>(source: P, dest: Q) -> Result<()> {
+ pub fn import_file<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> {
+ unimplemented!()
+ }
+
+ /// Copies a file from the drive to the "real" filesystem, preserving Stat metadata.
+ pub fn export_file<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> {
unimplemented!()
}
/* Possible future helper functions to be even more like std::fs
- pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()>
- pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()>
- pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()>
- pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()>
+ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, from: P, to: Q) -> Result<()>
+ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, from: P, to: Q) -> Result<()>
+ pub fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()>
+ pub fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> Result<()>
*/
}
@@ -74,12 +97,12 @@ impl<'a> DatDrive {
fn test_dd_open() {
let mut dd =
- DatDrive::open(Path::new("test-data/dat/simple/.dat/")).unwrap();
+ DatDrive::open(Path::new("test-data/dat/simple/.dat/"), false).unwrap();
// verified from dat log
- assert_eq!(dd.history().collect().len(), 2);
- assert_eq!(dd.read_dir().collect().len(), 1);
- assert_eq!(dd.read_dir_recurisve().collect().len(), 1);
+ assert_eq!(dd.history(1).count(), 2);
+ assert_eq!(dd.read_dir("/").count(), 1);
+ assert_eq!(dd.read_dir_recursive("/").count(), 1);
}
#[test]
@@ -88,21 +111,49 @@ fn test_dd_create() {
let tmp_dir = TempDir::new("geniza-test").unwrap();
let mut dd = DatDrive::create(tmp_dir.path()).unwrap();
- assert_eq!(dd.history().collect().len(), 0);
- assert_eq!(dd.read_dir().collect().len(), 0);
- assert_eq!(dd.read_dir_recurisve().collect().len(), 0);
+ assert_eq!(dd.history(1).count(), 0);
+ assert_eq!(dd.read_dir("/").count(), 0);
+ assert_eq!(dd.read_dir_recursive("/").count(), 0);
}
+// TODO: unpack Node into a pub struct
+#[derive(Debug)]
pub struct DriveEntry {
node: Node,
index: u64,
}
+/// Iterator over full drive history (file additions/deletions).
pub struct DriveHistory<'a> {
drive: &'a mut DatDrive,
+ current: u64,
}
-/// Iterator
+impl<'a> Iterator for DriveHistory<'a> {
+ type Item = Result<DriveEntry>;
+ fn next(&mut self) -> Option<Result<DriveEntry>> {
+ if self.current >= self.drive.metadata.len().unwrap() {
+ return None;
+ }
+ // TODO: handle Err, not unwrap
+ let data = match self.drive.metadata.get_data_entry(self.current) {
+ Err(e) => { return Some(Err(e)) },
+ Ok(v) => v,
+ };
+ let node = match parse_from_bytes::<Node>(&data) {
+ Err(e) => { return Some(Err(e.into())) },
+ Ok(v) => v,
+ };
+ let de = Ok(DriveEntry {
+ node,
+ index: self.current,
+ });
+ self.current += 1;
+ return Some(de);
+ }
+}
+
+/// Iterator over drive file entries.
pub struct ReadDriveDir<'a> {
drive: &'a mut DatDrive,
recursive: bool,
@@ -124,13 +175,6 @@ impl<'a> ReadDriveDir<'a> {
}
}
-impl<'a> Iterator for DriveHistory<'a> {
- type Item = DriveEntry;
- fn next(&mut self) -> Option<DriveEntry> {
- unimplemented!();
- }
-}
-
impl<'a> Iterator for ReadDriveDir<'a> {
type Item = DriveEntry;
fn next(&mut self) -> Option<DriveEntry> {