From 20d84247e913ac4967142adac251eaca4d86c1de Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 30 May 2024 10:44:42 +0200 Subject: [PATCH] Prune `Code` to only what's used by the UI Also adjust the `Code` documentation to clarify this - otherwise we will have more and more variants and nobody actually cares. The frontend code is adjusted as well, as its `Code` counterpart contained unsused variants which are now removed. --- app/src/lib/backend/ipc.ts | 6 +- crates/gitbutler-core/src/error.rs | 45 +-- crates/gitbutler-core/src/git/credentials.rs | 16 +- .../src/project_repository/mod.rs | 2 +- .../src/project_repository/repository.rs | 125 +++----- .../gitbutler-core/src/projects/controller.rs | 123 ++----- .../src/virtual_branches/controller.rs | 47 ++- .../src/virtual_branches/errors.rs | 301 ++---------------- .../src/virtual_branches/virtual.rs | 4 +- crates/gitbutler-core/tests/error/mod.rs | 8 +- crates/gitbutler-core/tests/suite/projects.rs | 2 +- .../tests/virtual_branches/mod.rs | 2 +- crates/gitbutler-tauri/src/error.rs | 33 +- crates/gitbutler-tauri/src/menu.rs | 4 +- crates/gitbutler-tauri/src/projects.rs | 18 +- 15 files changed, 185 insertions(+), 551 deletions(-) diff --git a/app/src/lib/backend/ipc.ts b/app/src/lib/backend/ipc.ts index 04bb6129d..02cd0573e 100644 --- a/app/src/lib/backend/ipc.ts +++ b/app/src/lib/backend/ipc.ts @@ -5,11 +5,7 @@ import type { EventCallback, EventName } from '@tauri-apps/api/event'; export enum Code { Unknown = 'errors.unknown', Validation = 'errors.validation', - Projects = 'errors.projects', - ProjectsGitAuth = 'errors.projects.git.auth', - ProjectsGitRemote = 'errors.projects.git.remote', - ProjectHead = 'errors.projects.head', - ProjectConflict = 'errors.projects.conflict' + ProjectsGitAuth = 'errors.projects.git.auth' } export class UserError extends Error { diff --git a/crates/gitbutler-core/src/error.rs b/crates/gitbutler-core/src/error.rs index a26de1520..c15f4e0fb 100644 --- a/crates/gitbutler-core/src/error.rs +++ b/crates/gitbutler-core/src/error.rs @@ -123,49 +123,44 @@ use std::borrow::Cow; use std::fmt::{self, Debug, Display}; /// A unique code that consumers of the API may rely on to identify errors. +/// +/// ### Important +/// +/// **Only add variants if a consumer, like the *frontend*, is actually using them**. +/// Remove variants when no longer in use. +/// +/// In practice, it should match its [frontend counterpart](https://github.com/gitbutlerapp/gitbutler/blob/fa973fd8f1ae8807621f47601803d98b8a9cf348/app/src/lib/backend/ipc.ts#L5). #[derive(Debug, Default, Copy, Clone, PartialOrd, PartialEq)] pub enum Code { + /// Much like a catch-all error code. It shouldn't be attached explicitly unless + /// a message is provided as well as part of a [`Context`]. #[default] Unknown, Validation, - Projects, - Branches, ProjectGitAuth, - ProjectGitRemote, - /// The push operation failed, specifically because the remote rejected it. - ProjectGitPush, + // TODO(ST): try to remove this and replace it with downcasting or thiserror pattern matching ProjectConflict, - ProjectHead, - Menu, - PreCommitHook, - CommitMsgHook, } impl std::fmt::Display for Code { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let code = match self { - Code::Menu => "errors.menu", Code::Unknown => "errors.unknown", Code::Validation => "errors.validation", - Code::Projects => "errors.projects", - Code::Branches => "errors.branches", Code::ProjectGitAuth => "errors.projects.git.auth", - Code::ProjectGitRemote => "errors.projects.git.remote", - Code::ProjectGitPush => "errors.projects.git.push", - Code::ProjectHead => "errors.projects.head", Code::ProjectConflict => "errors.projects.conflict", - //TODO: rename js side to be more precise what kind of hook error this is - Code::PreCommitHook => "errors.hook", - Code::CommitMsgHook => "errors.hooks.commit.msg", }; f.write_str(code) } } -/// A context to wrap around lower errors to allow its classification, along with a message for the user. +/// A context for classifying errors. +/// +/// It provides a [`Code`], which may be [unknown](Code::Unknown), and a `message` which explains +/// more about the problem at hand. #[derive(Default, Debug, Clone)] pub struct Context { - /// The identifier of the error. + /// The classification of the error. pub code: Code, /// A description of what went wrong, if available. pub message: Option>, @@ -188,9 +183,9 @@ impl From for Context { impl Context { /// Create a new instance with `code` and an owned `message`. - pub fn new(code: Code, message: impl Into) -> Self { + pub fn new(message: impl Into) -> Self { Context { - code, + code: Code::Unknown, message: Some(Cow::Owned(message.into())), } } @@ -202,6 +197,12 @@ impl Context { message: Some(Cow::Borrowed(message)), } } + + /// Adjust the `code` of this instance to the given one. + pub fn with_code(mut self, code: Code) -> Self { + self.code = code; + self + } } mod private { diff --git a/crates/gitbutler-core/src/git/credentials.rs b/crates/gitbutler-core/src/git/credentials.rs index a7b49b7b2..b6d02d609 100644 --- a/crates/gitbutler-core/src/git/credentials.rs +++ b/crates/gitbutler-core/src/git/credentials.rs @@ -1,7 +1,6 @@ use std::path::PathBuf; -use crate::error::{AnyhowContextExt, Code, Context, ErrorWithContext}; -use crate::{error, keys, project_repository, projects, users}; +use crate::{keys, project_repository, projects, users}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum SshCredential { @@ -87,19 +86,6 @@ pub enum HelpError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for HelpError { - fn context(&self) -> Option { - Some(match self { - HelpError::NoUrlSet => { - error::Context::new_static(Code::ProjectGitRemote, "no url set for remote") - } - HelpError::UrlConvertError(_) => Code::ProjectGitRemote.into(), - HelpError::Git(_) => return None, - HelpError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - impl Helper { pub fn new( keys: keys::Controller, diff --git a/crates/gitbutler-core/src/project_repository/mod.rs b/crates/gitbutler-core/src/project_repository/mod.rs index 79ba8b1d0..1e86f4c40 100644 --- a/crates/gitbutler-core/src/project_repository/mod.rs +++ b/crates/gitbutler-core/src/project_repository/mod.rs @@ -3,6 +3,6 @@ pub mod conflicts; mod repository; pub use config::Config; -pub use repository::{LogUntil, OpenError, RemoteError, Repository}; +pub use repository::{LogUntil, RemoteError, Repository}; pub mod signatures; diff --git a/crates/gitbutler-core/src/project_repository/repository.rs b/crates/gitbutler-core/src/project_repository/repository.rs index 8ecabc249..1abe3a459 100644 --- a/crates/gitbutler-core/src/project_repository/repository.rs +++ b/crates/gitbutler-core/src/project_repository/repository.rs @@ -4,7 +4,7 @@ use std::{ sync::{atomic::AtomicUsize, Arc}, }; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use super::conflicts; use crate::{ @@ -24,82 +24,63 @@ pub struct Repository { project: projects::Project, } -#[derive(Debug, thiserror::Error)] -pub enum OpenError { - #[error("repository not found at {0}")] - NotFound(path::PathBuf), - #[error(transparent)] - Other(anyhow::Error), -} - -impl ErrorWithContext for OpenError { - fn context(&self) -> Option { - match self { - OpenError::NotFound(path) => { - error::Context::new(Code::Projects, format!("{} not found", path.display())).into() - } - OpenError::Other(error) => error.custom_context_or_root_cause().into(), - } - } -} - impl Repository { - pub fn open(project: &projects::Project) -> Result { - git::Repository::open(&project.path) - .map_err(|error| match error { - git::Error::NotFound(_) => OpenError::NotFound(project.path.clone()), - other => OpenError::Other(other.into()), - }) - .map(|git_repository| { - // XXX(qix-): This is a temporary measure to disable GC on the project repository. - // XXX(qix-): We do this because the internal repository we use to store the "virtual" - // XXX(qix-): refs and information use Git's alternative-objects mechanism to refer - // XXX(qix-): to the project repository's objects. However, the project repository - // XXX(qix-): has no knowledge of these refs, and will GC them away (usually after - // XXX(qix-): about 2 weeks) which will corrupt the internal repository. - // XXX(qix-): - // XXX(qix-): We will ultimately move away from an internal repository for a variety - // XXX(qix-): of reasons, but for now, this is a simple, short-term solution that we - // XXX(qix-): can clean up later on. We're aware this isn't ideal. - if let Ok(config) = git_repository.config().as_mut() { - let should_set = match config.get_bool("gitbutler.didSetPrune") { - Ok(None | Some(false)) => true, - Ok(Some(true)) => false, - Err(error) => { - tracing::warn!( + pub fn open(project: &projects::Project) -> Result { + let repo = git::Repository::open(&project.path).or_else(|err| match err { + git::Error::NotFound(_) => Err(anyhow::Error::from(err)).context(format!( + "repository not found at \"{}\"", + project.path.display() + )), + other => Err(other.into()), + })?; + + // XXX(qix-): This is a temporary measure to disable GC on the project repository. + // XXX(qix-): We do this because the internal repository we use to store the "virtual" + // XXX(qix-): refs and information use Git's alternative-objects mechanism to refer + // XXX(qix-): to the project repository's objects. However, the project repository + // XXX(qix-): has no knowledge of these refs, and will GC them away (usually after + // XXX(qix-): about 2 weeks) which will corrupt the internal repository. + // XXX(qix-): + // XXX(qix-): We will ultimately move away from an internal repository for a variety + // XXX(qix-): of reasons, but for now, this is a simple, short-term solution that we + // XXX(qix-): can clean up later on. We're aware this isn't ideal. + if let Ok(config) = repo.config().as_mut() { + let should_set = match config.get_bool("gitbutler.didSetPrune") { + Ok(None | Some(false)) => true, + Ok(Some(true)) => false, + Err(err) => { + tracing::warn!( "failed to get gitbutler.didSetPrune for repository at {}; cannot disable gc: {}", project.path.display(), - error + err ); - false - } - }; + false + } + }; - if should_set { - if let Err(error) = config - .set_str("gc.pruneExpire", "never") - .and_then(|()| config.set_bool("gitbutler.didSetPrune", true)) - { - tracing::warn!( + if should_set { + if let Err(error) = config + .set_str("gc.pruneExpire", "never") + .and_then(|()| config.set_bool("gitbutler.didSetPrune", true)) + { + tracing::warn!( "failed to set gc.auto to false for repository at {}; cannot disable gc: {}", project.path.display(), error ); - } - } - } else { - tracing::warn!( - "failed to get config for repository at {}; cannot disable gc", - project.path.display() - ); } + } + } else { + tracing::warn!( + "failed to get config for repository at {}; cannot disable gc", + project.path.display() + ); + } - git_repository - }) - .map(|git_repository| Self { - git_repository, - project: project.clone(), - }) + Ok(Self { + git_repository: repo, + project: project.clone(), + }) } pub fn is_resolving(&self) -> bool { @@ -517,9 +498,7 @@ impl Repository { } Err(err) => { if let Some(err) = update_refs_error.as_ref() { - return Err(RemoteError::Other( - anyhow::anyhow!(err.to_string()).context(Code::ProjectGitPush), - )); + return Err(RemoteError::Other(anyhow!(err.to_string()))); } return Err(RemoteError::Other(err.into())); } @@ -630,17 +609,13 @@ pub enum RemoteError { impl ErrorWithContext for RemoteError { fn context(&self) -> Option { Some(match self { - RemoteError::Help(error) => return error.context(), - RemoteError::Network => { - error::Context::new_static(Code::ProjectGitRemote, "Network error occurred") + RemoteError::Help(_) | RemoteError::Network | RemoteError::Git(_) => { + error::Context::default() } RemoteError::Auth => error::Context::new_static( Code::ProjectGitAuth, "Project remote authentication error", ), - RemoteError::Git(_) => { - error::Context::new_static(Code::ProjectGitRemote, "Git command failed") - } RemoteError::Other(error) => { return error.custom_context_or_root_cause().into(); } diff --git a/crates/gitbutler-core/src/projects/controller.rs b/crates/gitbutler-core/src/projects/controller.rs index b35f93c07..c7a080350 100644 --- a/crates/gitbutler-core/src/projects/controller.rs +++ b/crates/gitbutler-core/src/projects/controller.rs @@ -7,11 +7,8 @@ use anyhow::{Context, Result}; use async_trait::async_trait; use super::{storage, storage::UpdateRequest, Project, ProjectId}; -use crate::{error, project_repository}; -use crate::{ - error::{AnyhowContextExt, Code, Error, ErrorWithContext}, - projects::AuthKey, -}; +use crate::project_repository; +use crate::{error::Error, projects::AuthKey}; #[async_trait] pub trait Watchers { @@ -160,40 +157,28 @@ impl Controller { Ok(updated) } - pub fn get(&self, id: ProjectId) -> Result { - let project = self.projects_storage.get(id).map_err(|error| match error { - super::storage::Error::NotFound => GetError::NotFound, - error => GetError::Other(error.into()), - }); - if let Ok(project) = &project { - if !project.gb_dir().exists() { - if let Err(error) = std::fs::create_dir_all(project.gb_dir()) { - tracing::error!(project_id = %project.id, ?error, "failed to create {:?} on project get", project.gb_dir()); - } + pub fn get(&self, id: ProjectId) -> Result { + let project = self.projects_storage.get(id)?; + if !project.gb_dir().exists() { + if let Err(error) = std::fs::create_dir_all(project.gb_dir()) { + tracing::error!(project_id = %project.id, ?error, "failed to create \"{}\" on project get", project.gb_dir().display()); } - // Clean up old virtual_branches.toml that was never used - if project - .path - .join(".git") - .join("virtual_branches.toml") - .exists() - { - if let Err(error) = - std::fs::remove_file(project.path.join(".git").join("virtual_branches.toml")) - { - tracing::error!(project_id = %project.id, ?error, "failed to remove old virtual_branches.toml"); - } + } + // Clean up old virtual_branches.toml that was never used + let old_virtual_branches_path = project.path.join(".git").join("virtual_branches.toml"); + if old_virtual_branches_path.exists() { + if let Err(error) = std::fs::remove_file(old_virtual_branches_path) { + tracing::error!(project_id = %project.id, ?error, "failed to remove old virtual_branches.toml"); } } // FIXME(qix-): On windows, we have to force to system executable #[cfg(windows)] - let project = project.map(|mut p| { - p.preferred_key = AuthKey::SystemExecutable; - p - }); + { + project.preferred_key = AuthKey::SystemExecutable; + } - project + Ok(project) } pub fn list(&self) -> Result> { @@ -246,8 +231,7 @@ impl Controller { error => ConfigError::Other(error.into()), })?; - let repo = project_repository::Repository::open(&project) - .map_err(|e| ConfigError::Other(e.into()))?; + let repo = project_repository::Repository::open(&project).map_err(ConfigError::Other)?; repo.config() .get_local(key) .map_err(|e| ConfigError::Other(e.into())) @@ -264,8 +248,7 @@ impl Controller { error => ConfigError::Other(error.into()), })?; - let repo = project_repository::Repository::open(&project) - .map_err(|e| ConfigError::Other(e.into()))?; + let repo = project_repository::Repository::open(&project).map_err(ConfigError::Other)?; repo.config() .set_local(key, value) .map_err(|e| ConfigError::Other(e.into()))?; @@ -290,17 +273,6 @@ pub enum GetError { Other(#[from] anyhow::Error), } -impl error::ErrorWithContext for GetError { - fn context(&self) -> Option { - match self { - GetError::NotFound => { - error::Context::new_static(Code::Projects, "Project not found").into() - } - GetError::Other(error) => error.custom_context_or_root_cause().into(), - } - } -} - #[derive(Debug, thiserror::Error)] pub enum UpdateError { #[error("project not found")] @@ -311,26 +283,6 @@ pub enum UpdateError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for UpdateError { - fn context(&self) -> Option { - Some(match self { - UpdateError::Validation(UpdateValidationError::KeyNotFound(path)) => { - error::Context::new(Code::Projects, format!("'{}' not found", path.display())) - } - UpdateError::Validation(UpdateValidationError::KeyNotFile(path)) => { - error::Context::new( - Code::Projects, - format!("'{}' is not a file", path.display()), - ) - } - UpdateError::NotFound => { - error::Context::new_static(Code::Projects, "Project not found") - } - UpdateError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum UpdateValidationError { #[error("{0} not found")] @@ -343,47 +295,18 @@ pub enum UpdateValidationError { pub enum AddError { #[error("not a directory")] NotADirectory, - #[error("not a git repository")] + #[error("must be a Git repository")] NotAGitRepository(#[from] Box), - #[error("bare repositories are not supported")] + #[error("bare repositories are unsupported")] BareUnsupported, - #[error("worktrees unsupported")] + #[error("can only work in main worktrees")] WorktreeNotSupported, #[error("path not found")] PathNotFound, #[error("project already exists")] AlreadyExists, - #[error("submodules not supported")] + #[error("repositories with git submodules are not supported")] SubmodulesNotSupported, #[error(transparent)] - OpenProjectRepository(#[from] project_repository::OpenError), - #[error(transparent)] Other(#[from] anyhow::Error), } - -impl ErrorWithContext for AddError { - fn context(&self) -> Option { - Some(match self { - AddError::NotAGitRepository(_) => { - error::Context::new_static(Code::Projects, "Must be a git directory") - } - AddError::BareUnsupported => { - error::Context::new_static(Code::Projects, "Bare repositories are unsupported") - } - AddError::AlreadyExists => { - error::Context::new_static(Code::Projects, "Project already exists") - } - AddError::OpenProjectRepository(error) => return error.context(), - AddError::NotADirectory => error::Context::new(Code::Projects, "Not a directory"), - AddError::WorktreeNotSupported => { - error::Context::new(Code::Projects, "Can only work in main worktrees") - } - AddError::PathNotFound => error::Context::new(Code::Projects, "Path not found"), - AddError::SubmodulesNotSupported => error::Context::new_static( - Code::Projects, - "Repositories with git submodules are not supported", - ), - AddError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} diff --git a/crates/gitbutler-core/src/virtual_branches/controller.rs b/crates/gitbutler-core/src/virtual_branches/controller.rs index fcf5bd78f..51d5f9722 100644 --- a/crates/gitbutler-core/src/virtual_branches/controller.rs +++ b/crates/gitbutler-core/src/virtual_branches/controller.rs @@ -455,7 +455,7 @@ impl ControllerInner { user, run_hooks, ) - .map_err(Into::into); + .map_err(Error::from_err); let _ = snapshot_tree.and_then(|snapshot_tree| { project_repository.project().snapshot_commit_creation( snapshot_tree, @@ -475,10 +475,7 @@ impl ControllerInner { ) -> Result { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; - Ok(super::is_remote_branch_mergeable( - &project_repository, - branch_name, - )?) + super::is_remote_branch_mergeable(&project_repository, branch_name).map_err(Error::from_err) } pub fn can_apply_virtual_branch( @@ -523,9 +520,8 @@ impl ControllerInner { let _permit = self.semaphore.acquire().await; self.with_verify_branch(project_id, |project_repository, user| { - let result = - super::create_virtual_branch_from_branch(project_repository, branch, user)?; - Ok(result) + super::create_virtual_branch_from_branch(project_repository, branch, user) + .map_err(Error::from_err) }) } @@ -543,7 +539,7 @@ impl ControllerInner { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; super::list_remote_commit_files(&project_repository.git_repository, commit_oid) - .map_err(Into::into) + .map_err(Error::from_err) } pub fn set_base_branch( @@ -556,8 +552,7 @@ impl ControllerInner { let _ = project_repository .project() .create_snapshot(SnapshotDetails::new(OperationKind::SetBaseBranch)); - let result = super::set_base_branch(&project_repository, target_branch)?; - Ok(result) + super::set_base_branch(&project_repository, target_branch).map_err(Error::from_err) } pub fn set_target_push_remote( @@ -567,8 +562,7 @@ impl ControllerInner { ) -> Result<(), Error> { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; - super::set_target_push_remote(&project_repository, push_remote)?; - Ok(()) + super::set_target_push_remote(&project_repository, push_remote).map_err(Error::from_err) } pub async fn integrate_upstream_commits( @@ -633,7 +627,7 @@ impl ControllerInner { self.with_verify_branch(project_id, |project_repository, user| { let snapshot_tree = project_repository.project().prepare_snapshot(); let result = - super::apply_branch(project_repository, branch_id, user).map_err(Into::into); + super::apply_branch(project_repository, branch_id, user).map_err(Error::from_err); let _ = snapshot_tree.and_then(|snapshot_tree| { project_repository @@ -687,7 +681,8 @@ impl ControllerInner { let _ = project_repository .project() .create_snapshot(SnapshotDetails::new(OperationKind::AmendCommit)); - super::amend(project_repository, branch_id, commit_oid, ownership).map_err(Into::into) + super::amend(project_repository, branch_id, commit_oid, ownership) + .map_err(Error::from_err) }) } @@ -712,7 +707,7 @@ impl ControllerInner { to_commit_oid, ownership, ) - .map_err(Into::into) + .map_err(Error::from_err) }) } @@ -727,7 +722,7 @@ impl ControllerInner { self.with_verify_branch(project_id, |project_repository, _| { let snapshot_tree = project_repository.project().prepare_snapshot(); let result: Result<(), Error> = - super::undo_commit(project_repository, branch_id, commit_oid).map_err(Into::into); + super::undo_commit(project_repository, branch_id, commit_oid).map_err(Error::from_err); let _ = snapshot_tree.and_then(|snapshot_tree| { project_repository.project().snapshot_commit_undo( snapshot_tree, @@ -753,7 +748,7 @@ impl ControllerInner { .project() .create_snapshot(SnapshotDetails::new(OperationKind::InsertBlankCommit)); super::insert_blank_commit(project_repository, branch_id, commit_oid, user, offset) - .map_err(Into::into) + .map_err(Error::from_err) }) } @@ -771,7 +766,7 @@ impl ControllerInner { .project() .create_snapshot(SnapshotDetails::new(OperationKind::ReorderCommit)); super::reorder_commit(project_repository, branch_id, commit_oid, offset) - .map_err(Into::into) + .map_err(Error::from_err) }) } @@ -788,7 +783,7 @@ impl ControllerInner { .project() .create_snapshot(SnapshotDetails::new(OperationKind::UndoCommit)); super::reset_branch(project_repository, branch_id, target_commit_oid) - .map_err(Into::into) + .map_err(Error::from_err) }) } @@ -845,7 +840,7 @@ impl ControllerInner { let _ = project_repository .project() .create_snapshot(SnapshotDetails::new(OperationKind::CherryPick)); - super::cherry_pick(project_repository, branch_id, commit_oid).map_err(Into::into) + super::cherry_pick(project_repository, branch_id, commit_oid).map_err(Error::from_err) }) } @@ -880,7 +875,7 @@ impl ControllerInner { let _ = project_repository .project() .create_snapshot(SnapshotDetails::new(OperationKind::SquashCommit)); - super::squash(project_repository, branch_id, commit_oid).map_err(Into::into) + super::squash(project_repository, branch_id, commit_oid).map_err(Error::from_err) }) } @@ -897,7 +892,7 @@ impl ControllerInner { .project() .create_snapshot(SnapshotDetails::new(OperationKind::UpdateCommitMessage)); super::update_commit_message(project_repository, branch_id, commit_oid, message) - .map_err(Into::into) + .map_err(Error::from_err) }) } @@ -977,7 +972,7 @@ impl ControllerInner { .project() .create_snapshot(SnapshotDetails::new(OperationKind::MoveCommit)); super::move_commit(project_repository, target_branch_id, commit_oid, user) - .map_err(Into::into) + .map_err(Error::from_err) }) } } @@ -991,7 +986,7 @@ impl ControllerInner { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; let user = self.users.get_user()?; - super::integration::verify_branch(&project_repository)?; + super::integration::verify_branch(&project_repository).map_err(Error::from_err)?; action(&project_repository, user.as_ref()) } @@ -1005,7 +1000,7 @@ impl ControllerInner { let project = self.projects.get(project_id)?; let project_repository = project_repository::Repository::open(&project)?; let user = self.users.get_user()?; - super::integration::verify_branch(&project_repository)?; + super::integration::verify_branch(&project_repository).map_err(Error::from_err)?; Ok(tokio::task::spawn_blocking(move || { action(&project_repository, user.as_ref()) })) diff --git a/crates/gitbutler-core/src/virtual_branches/errors.rs b/crates/gitbutler-core/src/virtual_branches/errors.rs index 9de74a619..de4eed6d1 100644 --- a/crates/gitbutler-core/src/virtual_branches/errors.rs +++ b/crates/gitbutler-core/src/virtual_branches/errors.rs @@ -25,49 +25,21 @@ pub enum VirtualBranchError { RebaseFailed, #[error("force push not allowed")] ForcePushNotAllowed(ForcePushNotAllowed), - #[error("branch has no commits")] + #[error("Branch has no commits - there is nothing to amend to")] BranchHasNoCommits, #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for VirtualBranchError { - fn context(&self) -> Option { - Some(match self { - VirtualBranchError::Conflict(ctx) => ctx.to_context(), - VirtualBranchError::BranchNotFound(ctx) => ctx.to_context(), - VirtualBranchError::DefaultTargetNotSet(ctx) => ctx.to_context(), - VirtualBranchError::TargetOwnerhshipNotFound(_) => { - error::Context::new_static(Code::Branches, "target ownership not found") - } - VirtualBranchError::GitObjectNotFound(oid) => { - error::Context::new(Code::Branches, format!("git object {oid} not found")) - } - VirtualBranchError::CommitFailed => { - error::Context::new_static(Code::Branches, "commit failed") - } - VirtualBranchError::RebaseFailed => { - error::Context::new_static(Code::Branches, "rebase failed") - } - VirtualBranchError::BranchHasNoCommits => error::Context::new_static( - Code::Branches, - "Branch has no commits - there is nothing to amend to", - ), - VirtualBranchError::ForcePushNotAllowed(ctx) => ctx.to_context(), - VirtualBranchError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum VerifyError { - #[error("head is detached")] + #[error("project in detached head state. Please checkout {} to continue", GITBUTLER_INTEGRATION_REFERENCE.branch())] DetachedHead, - #[error("head is {0}")] + #[error("project is on {0}. Please checkout {} to continue", GITBUTLER_INTEGRATION_REFERENCE.branch())] InvalidHead(String), - #[error("head not found")] + #[error("Repo HEAD is unavailable")] HeadNotFound, - #[error("integration commit not found")] + #[error("GibButler's integration commit not found on head.")] NoIntegrationCommit, #[error(transparent)] GitError(#[from] git::Error), @@ -75,39 +47,6 @@ pub enum VerifyError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for VerifyError { - fn context(&self) -> Option { - Some(match self { - VerifyError::DetachedHead => error::Context::new( - Code::ProjectHead, - format!( - "Project in detached head state. Please checkout {0} to continue.", - GITBUTLER_INTEGRATION_REFERENCE.branch() - ), - ), - VerifyError::InvalidHead(head) => error::Context::new( - Code::ProjectHead, - format!( - "Project is on {}. Please checkout {} to continue.", - head, - GITBUTLER_INTEGRATION_REFERENCE.branch() - ), - ), - VerifyError::NoIntegrationCommit => error::Context::new_static( - Code::ProjectHead, - "GibButler's integration commit not found on head.", - ), - VerifyError::HeadNotFound => { - error::Context::new_static(Code::Validation, "Repo HEAD is unavailable") - } - VerifyError::GitError(error) => { - error::Context::new(Code::Validation, error.to_string()) - } - VerifyError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum ResetBranchError { #[error("commit {0} not in the branch")] @@ -122,27 +61,13 @@ pub enum ResetBranchError { Git(#[from] git::Error), } -impl ErrorWithContext for ResetBranchError { - fn context(&self) -> Option { - Some(match self { - ResetBranchError::BranchNotFound(ctx) => ctx.to_context(), - ResetBranchError::DefaultTargetNotSet(ctx) => ctx.to_context(), - ResetBranchError::CommitNotFoundInBranch(oid) => { - error::Context::new(Code::Branches, format!("commit {} not found", oid)) - } - ResetBranchError::Other(error) => return error.custom_context_or_root_cause().into(), - ResetBranchError::Git(_err) => return None, - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum ApplyBranchError { #[error("project")] Conflict(ProjectConflict), #[error("branch not found")] BranchNotFound(BranchNotFound), - #[error("branch being applied conflicts with other branch: {0}")] + #[error("branch {0} is in a conflicting state")] BranchConflicts(BranchId), #[error("default target not set")] DefaultTargetNotSet(DefaultTargetNotSet), @@ -152,22 +77,6 @@ pub enum ApplyBranchError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for ApplyBranchError { - fn context(&self) -> Option { - Some(match self { - ApplyBranchError::DefaultTargetNotSet(ctx) => ctx.to_context(), - ApplyBranchError::Conflict(ctx) => ctx.to_context(), - ApplyBranchError::BranchNotFound(ctx) => ctx.to_context(), - ApplyBranchError::BranchConflicts(id) => error::Context::new( - Code::Branches, - format!("Branch {} is in a conflicting state", id), - ), - ApplyBranchError::GitError(_) => return None, - ApplyBranchError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum UnapplyOwnershipError { #[error("default target not set")] @@ -252,31 +161,14 @@ pub enum CommitError { DefaultTargetNotSet(DefaultTargetNotSet), #[error("will not commit conflicted files")] Conflicted(ProjectConflict), - #[error("commit hook rejected")] + #[error("commit hook rejected: {0}")] CommitHookRejected(String), - #[error("commit msg hook rejected")] + #[error("commit-msg hook rejected: {0}")] CommitMsgHookRejected(String), #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for CommitError { - fn context(&self) -> Option { - Some(match self { - CommitError::BranchNotFound(ctx) => ctx.to_context(), - CommitError::DefaultTargetNotSet(ctx) => ctx.to_context(), - CommitError::Conflicted(ctx) => ctx.to_context(), - CommitError::CommitHookRejected(error) => { - error::Context::new(Code::PreCommitHook, error) - } - CommitError::CommitMsgHookRejected(error) => { - error::Context::new(Code::CommitMsgHook, error) - } - CommitError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum PushError { #[error("default target not set")] @@ -304,26 +196,12 @@ impl ErrorWithContext for PushError { pub enum IsRemoteBranchMergableError { #[error("default target not set")] DefaultTargetNotSet(DefaultTargetNotSet), - #[error("branch not found")] + #[error("Remote branch {0} not found")] BranchNotFound(git::RemoteRefname), #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for IsRemoteBranchMergableError { - fn context(&self) -> Option { - Some(match self { - IsRemoteBranchMergableError::BranchNotFound(name) => { - error::Context::new(Code::Branches, format!("Remote branch {} not found", name)) - } - IsRemoteBranchMergableError::DefaultTargetNotSet(ctx) => ctx.to_context(), - IsRemoteBranchMergableError::Other(error) => { - return error.custom_context_or_root_cause().into() - } - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum IsVirtualBranchMergeable { #[error("default target not set")] @@ -354,7 +232,7 @@ pub struct ForcePushNotAllowed { impl ForcePushNotAllowed { fn to_context(&self) -> error::Context { error::Context::new_static( - Code::Branches, + Code::Unknown, "Action will lead to force pushing, which is not allowed for this", ) } @@ -362,7 +240,7 @@ impl ForcePushNotAllowed { #[derive(Debug, thiserror::Error)] pub enum CherryPickError { - #[error("target commit {0} not found ")] + #[error("commit {0} not found ")] CommitNotFound(git::Oid), #[error("can not cherry pick not applied branch")] NotApplied, @@ -372,21 +250,6 @@ pub enum CherryPickError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for CherryPickError { - fn context(&self) -> Option { - Some(match self { - CherryPickError::NotApplied => { - error::Context::new_static(Code::Branches, "can not cherry pick non applied branch") - } - CherryPickError::Conflict(ctx) => ctx.to_context(), - CherryPickError::CommitNotFound(oid) => { - error::Context::new(Code::Branches, format!("commit {oid} not found")) - } - CherryPickError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum SquashError { #[error("force push not allowed")] @@ -405,25 +268,6 @@ pub enum SquashError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for SquashError { - fn context(&self) -> Option { - Some(match self { - SquashError::ForcePushNotAllowed(ctx) => ctx.to_context(), - SquashError::DefaultTargetNotSet(ctx) => ctx.to_context(), - SquashError::BranchNotFound(ctx) => ctx.to_context(), - SquashError::Conflict(ctx) => ctx.to_context(), - SquashError::CantSquashRootCommit => { - error::Context::new_static(Code::Branches, "can not squash root branch commit") - } - SquashError::CommitNotFound(oid) => error::Context::new( - crate::error::Code::Branches, - format!("commit {oid} not found"), - ), - SquashError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum FetchFromTargetError { #[error("default target not set")] @@ -448,7 +292,7 @@ impl ErrorWithContext for FetchFromTargetError { pub enum UpdateCommitMessageError { #[error("force push not allowed")] ForcePushNotAllowed(ForcePushNotAllowed), - #[error("empty message")] + #[error("Commit message can not be empty")] EmptyMessage, #[error("default target not set")] DefaultTargetNotSet(DefaultTargetNotSet), @@ -462,51 +306,16 @@ pub enum UpdateCommitMessageError { Other(#[from] anyhow::Error), } -impl ErrorWithContext for UpdateCommitMessageError { - fn context(&self) -> Option { - Some(match self { - UpdateCommitMessageError::ForcePushNotAllowed(ctx) => ctx.to_context(), - UpdateCommitMessageError::EmptyMessage => { - error::Context::new_static(Code::Branches, "Commit message can not be empty") - } - UpdateCommitMessageError::DefaultTargetNotSet(ctx) => ctx.to_context(), - UpdateCommitMessageError::CommitNotFound(oid) => { - error::Context::new(Code::Branches, format!("Commit {} not found", oid)) - } - UpdateCommitMessageError::BranchNotFound(ctx) => ctx.to_context(), - UpdateCommitMessageError::Conflict(ctx) => ctx.to_context(), - UpdateCommitMessageError::Other(error) => { - return error.custom_context_or_root_cause().into() - } - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum SetBaseBranchError { - #[error("wd is dirty")] + #[error("Current HEAD is dirty.")] DirtyWorkingDirectory, - #[error("branch {0} not found")] + #[error("remote branch '{0}' not found")] BranchNotFound(git::RemoteRefname), #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for SetBaseBranchError { - fn context(&self) -> Option { - Some(match self { - SetBaseBranchError::DirtyWorkingDirectory => { - error::Context::new(Code::ProjectConflict, "Current HEAD is dirty.") - } - SetBaseBranchError::BranchNotFound(name) => error::Context::new( - Code::Branches, - format!("remote branch '{}' not found", name), - ), - SetBaseBranchError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum UpdateBaseBranchError { #[error("project is in conflicting state")] @@ -539,65 +348,26 @@ pub enum MoveCommitError { DefaultTargetNotSet(DefaultTargetNotSet), #[error("branch not found")] BranchNotFound(BranchNotFound), - #[error("commit not found")] + #[error("commit {0} not found")] CommitNotFound(git::Oid), #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for MoveCommitError { - fn context(&self) -> Option { - Some(match self { - MoveCommitError::SourceLocked => error::Context::new_static( - Code::Branches, - "Source branch contains hunks locked to the target commit", - ), - MoveCommitError::Conflicted(ctx) => ctx.to_context(), - MoveCommitError::DefaultTargetNotSet(ctx) => ctx.to_context(), - MoveCommitError::BranchNotFound(ctx) => ctx.to_context(), - MoveCommitError::CommitNotFound(oid) => { - error::Context::new(Code::Branches, format!("Commit {} not found", oid)) - } - MoveCommitError::Other(error) => return error.custom_context_or_root_cause().into(), - }) - } -} - #[derive(Debug, thiserror::Error)] pub enum CreateVirtualBranchFromBranchError { #[error("failed to apply")] ApplyBranch(ApplyBranchError), - #[error("can't make branch from default target")] + #[error("can not create a branch from default target")] CantMakeBranchFromDefaultTarget, #[error("default target not set")] DefaultTargetNotSet(DefaultTargetNotSet), - #[error("{0} not found")] + #[error("branch {0} not found")] BranchNotFound(git::Refname), #[error(transparent)] Other(#[from] anyhow::Error), } -impl ErrorWithContext for CreateVirtualBranchFromBranchError { - fn context(&self) -> Option { - Some(match self { - CreateVirtualBranchFromBranchError::ApplyBranch(err) => return err.context(), - CreateVirtualBranchFromBranchError::CantMakeBranchFromDefaultTarget => { - error::Context::new_static( - Code::Branches, - "Can not create a branch from default target", - ) - } - CreateVirtualBranchFromBranchError::DefaultTargetNotSet(ctx) => ctx.to_context(), - CreateVirtualBranchFromBranchError::BranchNotFound(name) => { - error::Context::new(Code::Branches, format!("Branch {} not found", name)) - } - CreateVirtualBranchFromBranchError::Other(error) => { - return error.custom_context_or_root_cause().into() - } - }) - } -} - #[derive(Debug)] pub struct ProjectConflict { pub project_id: ProjectId, @@ -605,10 +375,10 @@ pub struct ProjectConflict { impl ProjectConflict { fn to_context(&self) -> error::Context { - error::Context::new( - Code::ProjectConflict, - format!("project {} is in a conflicted state", self.project_id), - ) + error::Context::new(format!( + "project {} is in a conflicted state", + self.project_id + )) } } @@ -619,13 +389,10 @@ pub struct DefaultTargetNotSet { impl DefaultTargetNotSet { fn to_context(&self) -> error::Context { - error::Context::new( - Code::ProjectConflict, - format!( - "project {} does not have a default target set", - self.project_id - ), - ) + error::Context::new(format!( + "project {} does not have a default target set", + self.project_id + )) } } @@ -637,10 +404,7 @@ pub struct BranchNotFound { impl BranchNotFound { fn to_context(&self) -> error::Context { - error::Context::new( - Code::Branches, - format!("branch {} not found", self.branch_id), - ) + error::Context::new(format!("branch {} not found", self.branch_id)) } } @@ -666,23 +430,12 @@ impl ErrorWithContext for UpdateBranchError { #[derive(Debug, thiserror::Error)] pub enum ListRemoteCommitFilesError { - #[error("failed to find commit {0}")] + #[error("commit {0} not found")] CommitNotFound(git::Oid), #[error("failed to find commit")] Other(#[from] anyhow::Error), } -impl ErrorWithContext for ListRemoteCommitFilesError { - fn context(&self) -> Option { - match self { - ListRemoteCommitFilesError::CommitNotFound(oid) => { - error::Context::new(Code::Branches, format!("Commit {} not found", oid)).into() - } - ListRemoteCommitFilesError::Other(error) => error.custom_context_or_root_cause().into(), - } - } -} - #[derive(Debug, thiserror::Error)] pub enum ListRemoteBranchesError { #[error("default target not set")] diff --git a/crates/gitbutler-core/src/virtual_branches/virtual.rs b/crates/gitbutler-core/src/virtual_branches/virtual.rs index c36283886..0a56be681 100644 --- a/crates/gitbutler-core/src/virtual_branches/virtual.rs +++ b/crates/gitbutler-core/src/virtual_branches/virtual.rs @@ -1233,7 +1233,7 @@ pub fn integrate_upstream_commits( if has_rebased_commits && !can_use_force { let message = "Aborted because force push is disallowed and commits have been rebased."; return Err(anyhow!("Cannot merge rebased commits without force push") - .context(error::Context::new(Code::ProjectConflict, message))); + .context(error::Context::new(message))); } let integration_result = match can_use_force { @@ -1243,7 +1243,7 @@ pub fn integrate_upstream_commits( let message = "Aborted because force push is disallowed and commits have been rebased."; return Err(anyhow!("Cannot merge rebased commits without force push") - .context(error::Context::new(Code::ProjectConflict, message))); + .context(error::Context::new(message))); } integrate_with_merge( project_repository, diff --git a/crates/gitbutler-core/tests/error/mod.rs b/crates/gitbutler-core/tests/error/mod.rs index 5b7e64d54..b997d5dea 100644 --- a/crates/gitbutler-core/tests/error/mod.rs +++ b/crates/gitbutler-core/tests/error/mod.rs @@ -13,9 +13,9 @@ mod into_anyhow { } } - let err = into_anyhow(Error(Code::Projects)); + let err = into_anyhow(Error(Code::Validation)); let ctx = err.downcast_ref::().unwrap(); - assert_eq!(ctx.code, Code::Projects, "the context is attached"); + assert_eq!(ctx.code, Code::Validation, "the context is attached"); assert_eq!( ctx.message, None, "there is no message when context was created from bare code" @@ -38,11 +38,11 @@ mod into_anyhow { } } - let err = into_anyhow(Outer::from(Inner(Code::Projects))); + let err = into_anyhow(Outer::from(Inner(Code::Validation))); let ctx = err.downcast_ref::().unwrap(); assert_eq!( ctx.code, - Code::Projects, + Code::Validation, "there is no magic here, it's all about manually implementing the nesting :/" ); } diff --git a/crates/gitbutler-core/tests/suite/projects.rs b/crates/gitbutler-core/tests/suite/projects.rs index dd8d98e5e..310f16fd3 100644 --- a/crates/gitbutler-core/tests/suite/projects.rs +++ b/crates/gitbutler-core/tests/suite/projects.rs @@ -93,7 +93,7 @@ mod add { let worktree = repo.worktree("feature", &worktree_dir, None).unwrap(); let err = controller.add(worktree.path()).unwrap_err(); - assert_eq!(err.to_string(), "worktrees unsupported"); + assert_eq!(err.to_string(), "can only work in main worktrees"); } fn create_initial_commit(repo: &git2::Repository) -> git2::Oid { diff --git a/crates/gitbutler-core/tests/virtual_branches/mod.rs b/crates/gitbutler-core/tests/virtual_branches/mod.rs index 176115164..2280a3334 100644 --- a/crates/gitbutler-core/tests/virtual_branches/mod.rs +++ b/crates/gitbutler-core/tests/virtual_branches/mod.rs @@ -2095,7 +2095,7 @@ fn verify_branch_not_integration() -> Result<()> { assert!(verify_result.is_err()); assert_eq!( verify_result.unwrap_err().to_string(), - "head is refs/heads/master" + "project is on refs/heads/master. Please checkout gitbutler/integration to continue" ); Ok(()) diff --git a/crates/gitbutler-tauri/src/error.rs b/crates/gitbutler-tauri/src/error.rs index a8d13d5b0..fbc9e5607 100644 --- a/crates/gitbutler-tauri/src/error.rs +++ b/crates/gitbutler-tauri/src/error.rs @@ -48,6 +48,17 @@ mod frontend { pub fn from_error_with_context(err: impl ErrorWithContext + Send + Sync + 'static) -> Self { Self(into_anyhow(err)) } + + /// Convert an error without context to our type. + /// + /// For now, we avoid using a conversion as it would be so general, we'd miss errors with context + /// which need [`from_error_with_context`](Self::from_error_with_context) for the context to be + /// picked up. + pub fn from_error_without_context( + err: impl std::error::Error + Send + Sync + 'static, + ) -> Self { + Self(err.into()) + } } impl Serialize for Error { @@ -92,30 +103,30 @@ mod frontend { #[test] fn find_code() { - let err = anyhow!("err msg").context(Code::Projects); + let err = anyhow!("err msg").context(Code::Validation); assert_eq!( json(err), - "{\"code\":\"errors.projects\",\"message\":\"err msg\"}", + "{\"code\":\"errors.validation\",\"message\":\"err msg\"}", "the 'code' is available as string, but the message is taken from the source error" ); } #[test] fn find_context() { - let err = anyhow!("err msg").context(Context::new_static(Code::Projects, "ctx msg")); + let err = anyhow!("err msg").context(Context::new_static(Code::Validation, "ctx msg")); assert_eq!( json(err), - "{\"code\":\"errors.projects\",\"message\":\"ctx msg\"}", + "{\"code\":\"errors.validation\",\"message\":\"ctx msg\"}", "Contexts often provide their own message, so the error message is ignored" ); } #[test] fn find_context_without_message() { - let err = anyhow!("err msg").context(Context::from(Code::Projects)); + let err = anyhow!("err msg").context(Context::from(Code::Validation)); assert_eq!( json(err), - "{\"code\":\"errors.projects\",\"message\":\"err msg\"}", + "{\"code\":\"errors.validation\",\"message\":\"err msg\"}", "Contexts without a message show the error's message as well" ); } @@ -124,10 +135,10 @@ mod frontend { fn find_nested_code() { let err = anyhow!("bottom msg") .context("top msg") - .context(Code::Projects); + .context(Code::Validation); assert_eq!( json(err), - "{\"code\":\"errors.projects\",\"message\":\"top msg\"}", + "{\"code\":\"errors.validation\",\"message\":\"top msg\"}", "the 'code' gets the message of the error that it provides context to, and it finds it down the chain" ); } @@ -135,12 +146,12 @@ mod frontend { #[test] fn multiple_codes() { let err = anyhow!("bottom msg") - .context(Code::Menu) + .context(Code::ProjectGitAuth) .context("top msg") - .context(Code::Projects); + .context(Code::Validation); assert_eq!( json(err), - "{\"code\":\"errors.projects\",\"message\":\"top msg\"}", + "{\"code\":\"errors.validation\",\"message\":\"top msg\"}", "it finds the most recent 'code' (and the same would be true for contexts, of course)" ); } diff --git a/crates/gitbutler-tauri/src/menu.rs b/crates/gitbutler-tauri/src/menu.rs index 3bc484cff..11c12c8f0 100644 --- a/crates/gitbutler-tauri/src/menu.rs +++ b/crates/gitbutler-tauri/src/menu.rs @@ -27,9 +27,7 @@ pub async fn menu_item_set_enabled( let menu_item = window .menu_handle() .try_get_item(menu_item_id) - .with_context(|| { - error::Context::new(Code::Menu, format!("menu item not found: {}", menu_item_id)) - })?; + .with_context(|| error::Context::new(format!("menu item not found: {}", menu_item_id)))?; menu_item.set_enabled(enabled).context(Code::Unknown)?; diff --git a/crates/gitbutler-tauri/src/projects.rs b/crates/gitbutler-tauri/src/projects.rs index bfe89734b..ea0932eda 100644 --- a/crates/gitbutler-tauri/src/projects.rs +++ b/crates/gitbutler-tauri/src/projects.rs @@ -2,7 +2,6 @@ pub mod commands { use anyhow::Context; use std::path; - use gitbutler_core::error::Code; use gitbutler_core::projects::{self, controller::Controller, ProjectId}; use tauri::Manager; use tracing::instrument; @@ -20,7 +19,7 @@ pub mod commands { .state::() .update(&project) .await - .map_err(Error::from_error_with_context) + .map_err(Error::from_error_without_context) } #[tauri::command(async)] @@ -32,7 +31,7 @@ pub mod commands { handle .state::() .add(path) - .map_err(Error::from_error_with_context) + .map_err(Error::from_error_without_context) } #[tauri::command(async)] @@ -41,10 +40,7 @@ pub mod commands { handle: tauri::AppHandle, id: ProjectId, ) -> Result { - handle - .state::() - .get(id) - .map_err(Error::from_error_with_context) + Ok(handle.state::().get(id)?) } #[tauri::command(async)] @@ -83,10 +79,10 @@ pub mod commands { id: ProjectId, key: &str, ) -> Result, Error> { - Ok(handle + handle .state::() .get_local_config(id, key) - .context(Code::Projects)?) + .map_err(Error::from_error_without_context) } #[tauri::command(async)] @@ -97,9 +93,9 @@ pub mod commands { key: &str, value: &str, ) -> Result<(), Error> { - Ok(handle + handle .state::() .set_local_config(id, key, value) - .context(Code::Projects)?) + .map_err(Error::from_error_without_context) } }