From 9e019b462ff05315641c95442faf7f8fc80f76b1 Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 21 Sep 2021 01:04:49 +0200 Subject: Slightly more consistent error handling --- Cargo.lock | 7 +++ Cargo.toml | 1 + cli/src/main.rs | 8 +-- src/actions/create.rs | 6 ++- src/actions/mod.rs | 11 ++-- src/actions/shift.rs | 12 +++-- src/actions/update.rs | 14 ++--- src/files.rs | 139 +++++++++++++++++++++++++++----------------------- src/history.rs | 17 +++--- 9 files changed, 121 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3292b2..b22eca6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" + [[package]] name = "difference" version = "2.0.0" @@ -18,6 +24,7 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" name = "ka" version = "0.1.0" dependencies = [ + "anyhow", "difference", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 6c055ec..7605ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" serde = {version = "1.0", features = ["derive"] } serde_json = "1.0" difference = "2.0.0" +anyhow = "1.0" [workspace] members = ["cli"] \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index 3105f9a..3b0203d 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -10,18 +10,18 @@ fn main() { match command { "create" => { - create(options).unwrap(); + create(options).expect("Failed executing Create action."); } "update" => { - update(options).unwrap(); + update(options).expect("Failed executing Update action."); } "shift" => { let file_path = args[2].as_str(); let new_cursor: usize = args[3].as_str().parse().expect("Invalid cursor."); - shift(options, file_path, new_cursor).unwrap(); + shift(options, file_path, new_cursor).expect("Failed executing Shift actions."); } - _ => println!("Unknown command: {}", command), + _ => panic!("Unknown command: {}", command), } } diff --git a/src/actions/create.rs b/src/actions/create.rs index 26d20c8..f00e95d 100644 --- a/src/actions/create.rs +++ b/src/actions/create.rs @@ -1,10 +1,12 @@ -use std::{fs, io}; +use std::fs; + +use anyhow::Result; use crate::{actions::update, files::Locations}; use super::ActionOptions; -pub fn create(command_options: ActionOptions) -> io::Result<()> { +pub fn create(command_options: ActionOptions) -> Result<()> { let locations = Locations::from(&command_options); if locations.ka_path.exists() { diff --git a/src/actions/mod.rs b/src/actions/mod.rs index 588ce8f..86af955 100644 --- a/src/actions/mod.rs +++ b/src/actions/mod.rs @@ -4,6 +4,7 @@ mod update; use std::path::{Path, PathBuf}; +use anyhow::Result; pub use create::create; pub use shift::shift; pub use update::update; @@ -19,12 +20,8 @@ impl ActionOptions { } } - pub fn from_pwd() -> Result { - let current_path = std::env::current_dir(); - if let Ok(repository_path) = current_path { - Ok(ActionOptions { repository_path }) - } else { - Err(()) - } + pub fn from_pwd() -> Result { + let repository_path = std::env::current_dir()?; + Ok(ActionOptions { repository_path }) } } diff --git a/src/actions/shift.rs b/src/actions/shift.rs index c02f0ed..1bd8864 100644 --- a/src/actions/shift.rs +++ b/src/actions/shift.rs @@ -1,9 +1,11 @@ use std::{ fs, - io::{self, Seek, Write}, + io::{Seek, Write}, path::Path, }; +use anyhow::Result; + use crate::{ files::{Locations, RepositoryPaths}, history::FileHistory, @@ -11,14 +13,14 @@ use crate::{ use super::ActionOptions; -pub fn shift(command_options: ActionOptions, path: &str, new_cursor: usize) -> io::Result<()> { +pub fn shift(command_options: ActionOptions, path: &str, new_cursor: usize) -> Result<()> { let locations = Locations::from(&command_options); - match RepositoryPaths::from_tracked(&locations, Path::new(path)) { + match RepositoryPaths::from_tracked(&locations, Path::new(path))? { RepositoryPaths::Tracked(tracked) => { let mut history_file = tracked.load_history_file()?; - let mut file_history = FileHistory::from_file(&mut history_file).unwrap(); + let mut file_history = FileHistory::from_file(&mut history_file)?; file_history.set_cursor(new_cursor); if file_history.file_is_deleted() { @@ -38,7 +40,7 @@ pub fn shift(command_options: ActionOptions, path: &str, new_cursor: usize) -> i RepositoryPaths::Deleted(deleted) => { let mut history_file = deleted.load_history_file()?; - let mut file_history = FileHistory::from_file(&mut history_file).unwrap(); + let mut file_history = FileHistory::from_file(&mut history_file)?; file_history.set_cursor(new_cursor); if !file_history.file_is_deleted() { diff --git a/src/actions/update.rs b/src/actions/update.rs index a2bc08d..a7d1aad 100644 --- a/src/actions/update.rs +++ b/src/actions/update.rs @@ -1,4 +1,6 @@ -use std::io::{self, Read}; +use std::io::Read; + +use anyhow::{Context, Result}; use crate::{ files::{Locations, RepositoryPaths}, @@ -8,12 +10,12 @@ use crate::{ use super::ActionOptions; -pub fn update(command_options: ActionOptions) -> io::Result<()> { +pub fn update(command_options: ActionOptions) -> Result<()> { let locations = Locations::from(&command_options); let entries = locations .get_repository_paths() - .expect("Could not traverse files."); + .context("Could not traverse files.")?; for element in entries { update_file(element, &locations)?; @@ -22,11 +24,11 @@ pub fn update(command_options: ActionOptions) -> io::Result<()> { Ok(()) } -fn update_file(paths: RepositoryPaths, locations: &Locations) -> io::Result<()> { +fn update_file(paths: RepositoryPaths, locations: &Locations) -> Result<()> { let new_state = match paths { RepositoryPaths::Deleted(deleted) => { let mut history_file = deleted.load_history_file()?; - let file_history = FileHistory::from_file(&mut history_file).unwrap(); + let file_history = FileHistory::from_file(&mut history_file)?; if !file_history.file_is_deleted() { let mut new_history = file_history; new_history.add_change(FileChange::Deleted); @@ -55,7 +57,7 @@ fn update_file(paths: RepositoryPaths, locations: &Locations) -> io::Result<()> let mut history_file = tracked.load_history_file()?; let mut tracked_file = tracked.load_tracked_file()?; - let file_history = FileHistory::from_file(&mut history_file).unwrap(); + let file_history = FileHistory::from_file(&mut history_file)?; let mut new_content = String::new(); tracked_file.read_to_string(&mut new_content)?; diff --git a/src/files.rs b/src/files.rs index 2512fa5..81bdd25 100644 --- a/src/files.rs +++ b/src/files.rs @@ -1,9 +1,11 @@ use std::{ - fs::{self, DirEntry, File, OpenOptions}, + fs::{self, DirEntry, File, OpenOptions, ReadDir}, io, path::{Path, PathBuf}, }; +use anyhow::{Context, Error, Result}; + use crate::actions::ActionOptions; pub struct Locations { @@ -13,61 +15,68 @@ pub struct Locations { } impl Locations { - pub fn get_repository_paths(&self) -> Result, ()> { - let repository_entries = fs::read_dir(&self.repository_path).map_err(|_| ())?; - let history_entries = fs::read_dir(&self.ka_files_path).map_err(|_| ())?; - - let tracked_paths = repository_entries - .map(Result::unwrap) - .filter(|entry| entry.path() != self.ka_path) - .flat_map(Self::flatten_directories) - .map(|entry| { - let path = entry.path(); - RepositoryPaths::from_tracked(&self, &path) - }); - - let deleted_paths = history_entries - .map(Result::unwrap) - .flat_map(Self::flatten_directories) - .filter_map(|entry| { - let path = entry.path(); - let file = RepositoryPaths::from_history(&self, &path); - match file { - RepositoryPaths::Deleted { .. } => Some(file), - RepositoryPaths::Tracked { .. } => None, - _ => unreachable!(), - } - }); + pub fn get_repository_paths(&self) -> Result, Error> { + let repository_entries = + fs::read_dir(&self.repository_path).context("Failed reading tracked file entries.")?; + let history_entries = + fs::read_dir(&self.ka_files_path).context("Failed reading history file entries.")?; + + let tracked_paths = Self::walk_directory(repository_entries, &|entry| { + let file_path = entry.path(); + if file_path != self.ka_path { + RepositoryPaths::from_tracked(&self, &file_path).ok() + } else { + None + } + })?; + + let deleted_paths = Self::walk_directory(history_entries, &|entry| { + let file_path = entry.path(); + let file = RepositoryPaths::from_history(&self, &file_path).ok()?; + match file { + RepositoryPaths::Deleted { .. } => Some(file), + RepositoryPaths::Tracked { .. } => None, + _ => unreachable!(), + } + })?; - let all_paths = tracked_paths.chain(deleted_paths); + let mut all_paths = tracked_paths; + all_paths.extend(deleted_paths); - Ok(all_paths.collect()) + Ok(all_paths) } - pub fn tracked_from_history(&self, history_file_path: &Path) -> PathBuf { - self.repository_path - .join(history_file_path.strip_prefix(&self.ka_files_path).unwrap()) + pub fn tracked_from_history(&self, history_file_path: &Path) -> Result { + let raw_path = history_file_path.strip_prefix(&self.ka_files_path)?; + Ok(self.repository_path.join(raw_path)) } - pub fn history_from_tracked(&self, tracked_file_path: &Path) -> PathBuf { - self.ka_files_path.join( - tracked_file_path - .strip_prefix(&self.repository_path) - .unwrap(), - ) + pub fn history_from_tracked(&self, tracked_file_path: &Path) -> Result { + let raw_path = tracked_file_path.strip_prefix(&self.repository_path)?; + Ok(self.ka_files_path.join(raw_path)) } - fn flatten_directories(entry: DirEntry) -> Vec { - let file_type = entry.file_type().expect("Could not read a file type."); - if file_type.is_dir() { - fs::read_dir(entry.path()) - .expect("Could not read nested directory.") - .map(Result::unwrap) - .flat_map(Self::flatten_directories) - .collect() - } else { - vec![entry] + fn walk_directory( + directory: ReadDir, + filter_map: &dyn Fn(DirEntry) -> Option, + ) -> Result> { + let mut entries = Vec::new(); + + for res in directory { + let entry = res?; + let file_type = entry.file_type()?; + if file_type.is_dir() { + let nested_directory = fs::read_dir(entry.path())?; + let nested_paths = Self::walk_directory(nested_directory, filter_map)?; + entries.extend(nested_paths); + } else { + if let Some(paths) = filter_map(entry) { + entries.push(paths); + } + } } + + Ok(entries) } } @@ -91,9 +100,9 @@ pub enum RepositoryPaths { } impl RepositoryPaths { - pub fn from_history(locations: &Locations, history_file_path: &Path) -> Self { - let tracked_path = locations.tracked_from_history(history_file_path); - if !tracked_path.exists() { + pub fn from_history(locations: &Locations, history_file_path: &Path) -> Result { + let tracked_path = locations.tracked_from_history(history_file_path)?; + Ok(if !tracked_path.exists() { RepositoryPaths::Deleted(FileDeleted { history_path: history_file_path.to_path_buf(), }) @@ -102,12 +111,12 @@ impl RepositoryPaths { history_path: history_file_path.to_path_buf(), tracked_path, }) - } + }) } - pub fn from_tracked(locations: &Locations, tracked_file_path: &Path) -> Self { - let history_path = locations.history_from_tracked(tracked_file_path); - if !history_path.exists() { + pub fn from_tracked(locations: &Locations, tracked_file_path: &Path) -> Result { + let history_path = locations.history_from_tracked(tracked_file_path)?; + Ok(if !history_path.exists() { RepositoryPaths::Untracked(FileUntracked { path: tracked_file_path.to_path_buf(), }) @@ -116,7 +125,7 @@ impl RepositoryPaths { history_path, tracked_path: tracked_file_path.to_path_buf(), }) - } + }) } } @@ -132,8 +141,10 @@ impl FileDeleted { .open(&self.history_path) } - pub fn create_tracked_file(&self, locations: &Locations) -> io::Result { - File::create(locations.tracked_from_history(&self.history_path)) + pub fn create_tracked_file(&self, locations: &Locations) -> Result { + Ok(File::create( + locations.tracked_from_history(&self.history_path)?, + )?) } } @@ -146,16 +157,16 @@ impl FileUntracked { OpenOptions::new().read(true).open(&self.path) } - pub fn create_history_file(&self, locations: &Locations) -> io::Result { - let history_path = locations.history_from_tracked(&self.path); + pub fn create_history_file(&self, locations: &Locations) -> Result { + let history_path = locations.history_from_tracked(&self.path)?; - history_path.parent().map(|dir_path| { - if !dir_path.exists() { - fs::create_dir_all(dir_path).unwrap(); + if let Some(parent_path) = history_path.parent(){ + if !parent_path.exists() { + fs::create_dir_all(parent_path)?; } - }); + } - File::create(history_path) + Ok(File::create(history_path)?) } } diff --git a/src/history.rs b/src/history.rs index 25a9555..13b2838 100644 --- a/src/history.rs +++ b/src/history.rs @@ -1,7 +1,12 @@ -use std::{fs::File, io::{self, Read, Seek, Write}}; +use std::{ + fs::File, + io::{Read, Seek, Write}, +}; use serde::{Deserialize, Serialize}; +use anyhow::{Context, Result}; + use crate::text_diff::TextChange; #[derive(Serialize, Deserialize, Debug)] @@ -11,13 +16,13 @@ pub struct FileHistory { } impl FileHistory { - pub fn from_file(file: &mut File) -> Result { + pub fn from_file(file: &mut File) -> Result { let mut buffer = Vec::new(); file.read_to_end(&mut buffer) - .expect("Could not read file history,"); + .context("Failed reading file history.")?; let file_history = serde_json::from_slice::(&buffer); - Ok(file_history.expect("Corrupted file history.")) + Ok(file_history.context("Corrupted file history.")?) } pub fn cursor(&self) -> usize { @@ -48,8 +53,8 @@ impl FileHistory { buffer } - pub fn write_to_file(&self, file: &mut File) -> io::Result<()> { - let encoded: Vec = serde_json::to_vec(self).unwrap(); + pub fn write_to_file(&self, file: &mut File) -> anyhow::Result<()> { + let encoded: Vec = serde_json::to_vec(self)?; file.rewind()?; file.set_len(0)?; file.write_all(encoded.as_ref())?; -- cgit 1.4.1