diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2017-10-29 13:59:47 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2017-10-29 13:59:47 -0700 | 
| commit | 58a0dc3387cfc88991bd93fad6d16a84bd7e4902 (patch) | |
| tree | 02f5f783815f7f13b830d4cf261dfdb103816923 /src | |
| parent | ad63a8f64fa434c25ecd9e5d3437f6885f586706 (diff) | |
| download | geniza-58a0dc3387cfc88991bd93fad6d16a84bd7e4902.tar.gz geniza-58a0dc3387cfc88991bd93fad6d16a84bd7e4902.zip  | |
progress on drive: basic history dump (un-pretty output)
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/geniza-drive.rs | 70 | ||||
| -rw-r--r-- | src/drive.rs | 106 | 
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> {  | 
