From 5876bc8ed38a633bfb3810447dd7c1fa7d94f704 Mon Sep 17 00:00:00 2001 From: Nikita Galaiko Date: Tue, 8 Aug 2023 16:25:59 +0200 Subject: [PATCH] verify user is on gitbutler/integration --- src-tauri/src/error.rs | 13 +++- src-tauri/src/virtual_branches/commands.rs | 68 ++++++++------------ src-tauri/src/virtual_branches/controller.rs | 47 ++++++++++++++ src-tauri/src/virtual_branches/vbranch.rs | 15 +++-- 4 files changed, 96 insertions(+), 47 deletions(-) diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index da9bbd8b6..aadc76b92 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -12,6 +12,7 @@ pub enum Code { Conflicting, ProjectCreateFailed, GitAutenticationFailed, + InvalidHead, } impl fmt::Display for Code { @@ -22,6 +23,7 @@ impl fmt::Display for Code { Code::FetchFailed => write!(f, "errors.fetch"), Code::Conflicting => write!(f, "errors.conflict"), Code::GitAutenticationFailed => write!(f, "errors.git.authentication"), + Code::InvalidHead => write!(f, "errors.git.head"), Code::ProjectCreateFailed => write!(f, "errors.projects.create"), } } @@ -74,8 +76,15 @@ impl From for Error { message: "Project is in conflicting state. Resolve all conflicts and try again." .to_string(), }, - virtual_branches::controller::Error::LockError(_) => Error::Unknown, - virtual_branches::controller::Error::Other(e) => Error::from(e), + virtual_branches::controller::Error::DetachedHead => Error::UserError { + code: Code::InvalidHead, + message: format!("Project in detached head state. Please checkout {0} to continue.", virtual_branches::GITBUTLER_INTEGRATION_REFERENCE), + }, + virtual_branches::controller::Error::InvalidHead(head_name) => Error::UserError { + code: Code::InvalidHead, + message: format!("Project is on {0}. Please checkout {1} to continue.", head_name, virtual_branches::GITBUTLER_INTEGRATION_REFERENCE), + }, + e => Error::from(e), } } } diff --git a/src-tauri/src/virtual_branches/commands.rs b/src-tauri/src/virtual_branches/commands.rs index 34d5487d2..4d1032918 100644 --- a/src-tauri/src/virtual_branches/commands.rs +++ b/src-tauri/src/virtual_branches/commands.rs @@ -1,4 +1,3 @@ -use anyhow::Context; use futures::future::join_all; use tauri::{AppHandle, Manager}; use timed::timed; @@ -19,8 +18,7 @@ pub async fn commit_virtual_branch( .state::() .create_commit(project_id, branch, message) .await - .context("failed to create commit")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -29,12 +27,11 @@ pub async fn list_virtual_branches( handle: tauri::AppHandle, project_id: &str, ) -> Result, Error> { - let branches = handle + handle .state::() .list_virtual_branches(project_id) .await - .context("failed to list virtual branches")?; - Ok(branches) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -48,8 +45,7 @@ pub async fn create_virtual_branch( .state::() .create_virtual_branch(project_id, &branch) .await - .context("failed to create virtual branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -59,12 +55,11 @@ pub async fn create_virtual_branch_from_branch( project_id: &str, branch: branch::Name, ) -> Result { - let branch_id = handle + handle .state::() .create_virtual_branch_from_branch(project_id, &branch) .await - .context("failed to create virtual branch from branch")?; - Ok(branch_id) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -74,10 +69,7 @@ pub async fn get_base_branch_data( project_id: &str, ) -> Result, Error> { let controller = handle.state::(); - let target = match controller - .get_base_branch_data(project_id) - .context("failed to get base branch data")? - { + let target = match controller.get_base_branch_data(project_id)? { None => return Ok(None), Some(target) => target, }; @@ -148,23 +140,21 @@ pub async fn set_base_branch( project_id: &str, branch: &str, ) -> Result { - let controller = handle.state::(); - let target = controller + handle + .state::() .set_base_branch(project_id, branch) .await - .context("failed to get target data")?; - Ok(target) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] #[tauri::command(async)] pub async fn update_base_branch(handle: tauri::AppHandle, project_id: &str) -> Result<(), Error> { - let controller = handle.state::(); - controller + handle + .state::() .update_base_branch(project_id) .await - .context("failed to update base branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -174,12 +164,11 @@ pub async fn update_virtual_branch( project_id: &str, branch: super::branch::BranchUpdateRequest, ) -> Result<(), Error> { - let controller = handle.state::(); - controller + handle + .state::() .update_virtual_branch(project_id, branch) .await - .context("failed to update virtual branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -189,12 +178,11 @@ pub async fn delete_virtual_branch( project_id: &str, branch_id: &str, ) -> Result<(), Error> { - let controller = handle.state::(); - controller + handle + .state::() .delete_virtual_branch(project_id, branch_id) .await - .context("failed to update virtual branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -204,12 +192,11 @@ pub async fn apply_branch( project_id: &str, branch: &str, ) -> Result<(), Error> { - let controller = handle.state::(); - controller + handle + .state::() .apply_virtual_branch(project_id, branch) .await - .context("failed to apply branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -219,12 +206,11 @@ pub async fn unapply_branch( project_id: &str, branch: &str, ) -> Result<(), Error> { - let controller = handle.state::(); - controller + handle + .state::() .unapply_virtual_branch(project_id, branch) .await - .context("failed to unapply branch")?; - Ok(()) + .map_err(Into::into) } #[timed(duration(printer = "debug!"))] @@ -237,6 +223,6 @@ pub async fn push_virtual_branch( handle .state::() .push_virtual_branch(project_id, branch_id) - .await?; - Ok(()) + .await + .map_err(Into::into) } diff --git a/src-tauri/src/virtual_branches/controller.rs b/src-tauri/src/virtual_branches/controller.rs index df8d2d105..f564866b0 100644 --- a/src-tauri/src/virtual_branches/controller.rs +++ b/src-tauri/src/virtual_branches/controller.rs @@ -21,6 +21,10 @@ pub struct Controller { #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("detached head detected, go back to gitbutler/integration to continue")] + DetachedHead, + #[error("unexpected head {0}, go back to gitbutler/integration to continue")] + InvalidHead(String), #[error("failed to open project repository")] PushError(#[from] project_repository::Error), #[error("project is in a conflicted state")] @@ -67,6 +71,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::commit(&gb_repository, &project_repository, branch, message) @@ -92,6 +97,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::list_virtual_branches(&gb_repository, &project_repository) @@ -117,6 +123,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; if conflicts::is_resolving(&project_repository) { @@ -148,6 +155,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; let branch_id = super::create_virtual_branch_from_branch( @@ -179,6 +187,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; let base_branch = super::get_base_branch_data(&gb_repository, &project_repository)?; Ok(base_branch) @@ -222,6 +231,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::update_base_branch(&gb_repository, &project_repository) @@ -236,8 +246,20 @@ impl Controller { project_id: &str, branch_update: super::branch::BranchUpdateRequest, ) -> Result<(), Error> { + let project = self + .projects_storage + .get_project(project_id) + .context("failed to get project")? + .context("project not found")?; + self.with_lock(project_id, || { let gb_repository = self.open_gb_repository(project_id)?; + let project_repository = project + .as_ref() + .try_into() + .context("failed to open project repository")?; + + self.verify_branch(&project_repository)?; super::update_branch(&gb_repository, branch_update) }) .await?; @@ -250,8 +272,19 @@ impl Controller { project_id: &str, branch_id: &str, ) -> Result<(), Error> { + let project = self + .projects_storage + .get_project(project_id) + .context("failed to get project")? + .context("project not found")?; + self.with_lock(project_id, || { let gb_repository = self.open_gb_repository(project_id)?; + let project_repository = project + .as_ref() + .try_into() + .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; super::delete_branch(&gb_repository, branch_id) }) .await?; @@ -275,6 +308,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::apply_branch(&gb_repository, &project_repository, branch_id) }) @@ -299,6 +333,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::unapply_branch(&gb_repository, &project_repository, branch_id) }) @@ -328,6 +363,7 @@ impl Controller { .as_ref() .try_into() .context("failed to open project repository")?; + self.verify_branch(&project_repository)?; let gb_repository = self.open_gb_repository(project_id)?; super::push(&project_repository, &gb_repository, branch_id, &private_key).map_err(|e| { @@ -361,4 +397,15 @@ impl Controller { .context("failed to open repository") .map_err(Error::Other) } + + fn verify_branch( + &self, + project_repository: &project_repository::Repository, + ) -> Result<(), Error> { + match project_repository.get_head().map_err(Error::Other)?.name() { + None => Err(Error::DetachedHead), + Some(super::vbranch::GITBUTLER_INTEGRATION_REFERENCE) => Ok(()), + Some(head_name) => Err(Error::InvalidHead(head_name.to_string())), + } + } } diff --git a/src-tauri/src/virtual_branches/vbranch.rs b/src-tauri/src/virtual_branches/vbranch.rs index cb8b6c133..a3f671f87 100644 --- a/src-tauri/src/virtual_branches/vbranch.rs +++ b/src-tauri/src/virtual_branches/vbranch.rs @@ -1670,6 +1670,8 @@ fn get_virtual_branches( Ok(applied_virtual_branches) } +pub const GITBUTLER_INTEGRATION_REFERENCE: &str = "refs/heads/gitbutler/integration"; + pub fn update_gitbutler_integration( gb_repository: &gb_repository::Repository, project_repository: &project_repository::Repository, @@ -1682,8 +1684,12 @@ pub fn update_gitbutler_integration( let repo = &project_repository.git_repository; // write the currrent target sha to a temp branch as a parent - let my_ref = "refs/heads/gitbutler/integration"; - repo.reference(my_ref, target.sha, true, "update target")?; + repo.reference( + GITBUTLER_INTEGRATION_REFERENCE, + target.sha, + true, + "update target", + )?; // get commit object from target.sha let target_commit = repo.find_commit(target.sha)?; @@ -1693,7 +1699,7 @@ pub fn update_gitbutler_integration( let mut prev_head = head.name().unwrap().to_string(); let mut prev_sha = head.target().unwrap().to_string(); let integration_file = repo.path().join("integration"); - if prev_head != my_ref { + if prev_head != GITBUTLER_INTEGRATION_REFERENCE { // we are moving from a regular branch to our gitbutler integration branch, save the original // write a file to .git/integration with the previous head and name let mut file = std::fs::File::create(integration_file)?; @@ -1713,7 +1719,8 @@ pub fn update_gitbutler_integration( } // commit index to temp head for the merge - repo.set_head(my_ref).context("failed to set head")?; + repo.set_head(GITBUTLER_INTEGRATION_REFERENCE) + .context("failed to set head")?; // get all virtual branches, we need to try to update them all let applied_virtual_branches = get_virtual_branches(gb_repository, Some(true))?;