From dbd0e068f64ab72a4e3877a70b831b5806592472 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 19 Oct 2020 02:24:14 +0100 Subject: [PATCH] start db --- src/database.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 21 ++++++++--- src/resolve.rs | 64 ++++++++++++++++++++++++++++----- 3 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 src/database.rs diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..c18b7f9 --- /dev/null +++ b/src/database.rs @@ -0,0 +1,94 @@ +//! Database manipulation stuffs +use super::*; +use std::{ + path::{ + PathBuf, + }, + error, + fmt, + io, + marker::Unpin, +}; +/// An error in database operations +#[derive(Debug)] +#[non_exhaustive] +pub enum Error { + ExpectedLine(Option), + IO(io::Error), + Unknown, +} +impl error::Error for Error +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match &self { + Self::IO(io) => Some(io), + _ => None, + } + } +} +impl fmt::Display for Error +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self { + Self::IO(_)=> write!(f, "i/o"), + Self::ExpectedLine(None) => write!(f, "expected a line that was not present in the file"), + Self::ExpectedLine(Some(msg)) => write!(f, "{}", msg), + _ => write!(f, "unknown"), + } + } +} + + + +/// Contains Videl information for a database directory +#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd, Hash)] +pub struct Database +{ + pub path: PathBuf, +} + +impl Database +{ + /// Save this database to a stream + pub async fn save(&self, stream: &mut T) -> Result + { + let bytes = resolve::path_bytes(&self.path); + stream.write_all(&bytes[..]).await?; + stream.write_u8(b'\n').await?; + Ok(bytes.len() + 1) + } +} + + +/// Load database info from this file +pub async fn load(stream: &mut T) -> Result +{ + let mut buffer = String::new(); + macro_rules! line { + ($message:literal $($tt:tt)*) => { + { + buffer.clear(); + let read = stream.read_line(&mut buffer).await?; + if read == 0 { + return Err(Error::ExpectedLine(Some(format!($message $($tt)*)))); + } + &buffer[..] + } + } + } + + let location_encoded = line!("expected the location line"); + + Ok(Database{ + path: PathBuf::from(location_encoded), + }) +} + +impl From for Error +{ + #[inline] fn from(from: io::Error) -> Self + { + Self::IO(from) + } +} diff --git a/src/main.rs b/src/main.rs index 58d4ce7..b87897c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,11 @@ use cfg_if::cfg_if; use lazy_static::lazy_static; -use futures::prelude::*; +//use futures::prelude::*; +use tokio::prelude::*; +use futures::{ + Future, +}; #[allow(unused_imports)] use color_eyre::{ @@ -21,12 +25,15 @@ use std::{ mod ext; use ext::*; - mod util; +mod dedup; + +mod resolve; +mod database; + mod args; mod config; -mod resolve; -mod dedup; + cfg_if!{ if #[cfg(nightly)] { @@ -50,7 +57,11 @@ async fn process(config: Arc, file: String) println!(" -> {:?}", file); let dbdir = resolve::mangle_path(&config, &file); println!("Database path for this file {:?}", dbdir); - println!("Demangle: {:?}", resolve::demangle_path(&dbdir).await); + println!("Demangle: {:?}", resolve::demangle_path(&dbdir).await + .wrap_err(eyre!("Failed to demangle path")) + .with_section(|| dbdir.to_string_lossy().into_owned().header("Path was")) + .with_section(|| config.base_dir.clone().to_string_lossy().into_owned().header("The videl database root directory is")) + .with_suggestion(|| "Are you sure this database location is correct")); } async fn begin() -> eyre::Result diff --git a/src/resolve.rs b/src/resolve.rs index 5506b43..61940a1 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -8,8 +8,14 @@ use std::{ collections::HashMap, fmt, error, + borrow::Cow, }; use std::os::unix::ffi::{OsStrExt, OsStringExt}; +use tokio::{ + fs::{ + OpenOptions, + }, +}; #[cfg(not(feature="fast-pathnames"))] fn compute_hash_string(from: impl AsRef<[u8]>) -> String @@ -55,14 +61,44 @@ pub fn mangle_path(config: &config::Config, path: impl AsRef) -> PathBuf } #[derive(Debug)] -pub struct ResolutionError; +#[non_exhaustive] +pub enum ResolutionError +{ + Name, + Utf8, + #[cfg(feature="fast-pathnames")] + Base64Decode(base64::Error), + IO(io::Error), + Open(io::Error), + Database(database::Error), + Unknown, +} -impl error::Error for ResolutionError{} +impl error::Error for ResolutionError +{ + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + Some(match &self { + #[cfg(feature="fast-pathnames")] Self::Base64Decode(er) => er, + Self::IO(er)=>er, + Self::Open(er)=>er, + Self::Database(er)=>er, + _ => return None, + }) + } +} impl fmt::Display for ResolutionError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "database path was in an invalid format") + match self { + Self::Name => write!(f, "invalid pathname"), + Self::Utf8 => write!(f, "pathname contained invalid UTF-8"), + #[cfg(feature="fast-pathnames")] Self::Base64Decode(_) => write!(f, "failed to decode base64 pathname"), + Self::IO(_) => write!(f, "i/o error"), + Self::Open(_) => write!(f, "failed to open file"), + Self::Database(_) => write!(f, "failed to parse database"), + _ => write!(f, "unknown error") + } } } @@ -71,14 +107,26 @@ pub async fn demangle_path(path: impl AsRef) -> Result + ?Sized>(path: &'a P) -> Cow<'a, [u8]> +{ + //for now, just use unix ext'ss things + Cow::Borrowed(path.as_ref().as_os_str().as_bytes()) +}