mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-03 03:33:16 +03:00
Merge pull request #1645 from gitbutlerapp/remove-app-wide-lock
remove app wide lock
This commit is contained in:
commit
aa5011264d
@ -154,7 +154,8 @@ pub async fn get_base_branch_data(
|
||||
})?;
|
||||
if let Some(base_branch) = handle
|
||||
.state::<Controller>()
|
||||
.get_base_branch_data(&project_id)?
|
||||
.get_base_branch_data(&project_id)
|
||||
.await?
|
||||
{
|
||||
let proxy = handle.state::<assets::Proxy>();
|
||||
let base_branch = proxy.proxy_base_branch(base_branch).await;
|
||||
@ -180,7 +181,8 @@ pub async fn set_base_branch(
|
||||
.context("Invalid branch name")?;
|
||||
let base_branch = handle
|
||||
.state::<Controller>()
|
||||
.set_base_branch(&project_id, &branch_name)?;
|
||||
.set_base_branch(&project_id, &branch_name)
|
||||
.await?;
|
||||
let base_branch = handle
|
||||
.state::<assets::Proxy>()
|
||||
.proxy_base_branch(base_branch)
|
||||
@ -353,6 +355,7 @@ pub async fn can_apply_virtual_branch(
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.can_apply_virtual_branch(&project_id, &branch_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -374,6 +377,7 @@ pub async fn can_apply_remote_branch(
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.can_apply_remote_branch(&project_id, &branch)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -395,6 +399,7 @@ pub async fn list_remote_commit_files(
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.list_remote_commit_files(&project_id, commit_oid)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
@ -494,7 +499,8 @@ pub async fn list_remote_branches(
|
||||
})?;
|
||||
let branches = handle
|
||||
.state::<Controller>()
|
||||
.list_remote_branches(&project_id)?;
|
||||
.list_remote_branches(&project_id)
|
||||
.await?;
|
||||
let branches = handle
|
||||
.state::<assets::Proxy>()
|
||||
.proxy_remote_branches(branches)
|
||||
|
@ -22,11 +22,11 @@ use super::{
|
||||
#[derive(Clone)]
|
||||
pub struct Controller {
|
||||
local_data_dir: DataDir,
|
||||
semaphores: Arc<tokio::sync::Mutex<HashMap<String, Semaphore>>>,
|
||||
|
||||
projects: projects::Controller,
|
||||
users: users::Controller,
|
||||
keys: keys::Controller,
|
||||
|
||||
by_project_id: Arc<tokio::sync::Mutex<HashMap<ProjectId, ControllerInner>>>,
|
||||
}
|
||||
|
||||
impl TryFrom<&AppHandle> for Controller {
|
||||
@ -44,6 +44,299 @@ impl TryFrom<&AppHandle> for Controller {
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
pub fn new(
|
||||
data_dir: &DataDir,
|
||||
projects: &projects::Controller,
|
||||
users: &users::Controller,
|
||||
keys: &keys::Controller,
|
||||
) -> Self {
|
||||
Self {
|
||||
by_project_id: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
|
||||
|
||||
local_data_dir: data_dir.clone(),
|
||||
projects: projects.clone(),
|
||||
users: users.clone(),
|
||||
keys: keys.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn inner(&self, project_id: &ProjectId) -> ControllerInner {
|
||||
self.by_project_id
|
||||
.lock()
|
||||
.await
|
||||
.entry(*project_id)
|
||||
.or_insert_with(|| {
|
||||
ControllerInner::new(
|
||||
&self.local_data_dir,
|
||||
&self.projects,
|
||||
&self.users,
|
||||
&self.keys,
|
||||
)
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub async fn create_commit(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
message: &str,
|
||||
ownership: Option<&Ownership>,
|
||||
) -> Result<git::Oid, ControllerError<errors::CommitError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.create_commit(project_id, branch_id, message, ownership)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn can_apply_remote_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_name: &git::BranchName,
|
||||
) -> Result<bool, ControllerError<IsRemoteBranchMergableError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.can_apply_remote_branch(project_id, branch_name)
|
||||
}
|
||||
|
||||
pub async fn can_apply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<bool, Error> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.can_apply_virtual_branch(project_id, branch_id)
|
||||
}
|
||||
|
||||
pub async fn list_virtual_branches(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<Vec<super::VirtualBranch>, ControllerError<errors::ListVirtualBranchesError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.list_virtual_branches(project_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
create: &super::branch::BranchCreateRequest,
|
||||
) -> Result<BranchId, ControllerError<errors::CreateVirtualBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.create_virtual_branch(project_id, create)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_virtual_branch_from_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch: &git::BranchName,
|
||||
) -> Result<BranchId, ControllerError<errors::CreateVirtualBranchFromBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.create_virtual_branch_from_branch(project_id, branch)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_base_branch_data(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<Option<super::BaseBranch>, ControllerError<GetBaseBranchDataError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.get_base_branch_data(project_id)
|
||||
}
|
||||
|
||||
pub async fn list_remote_commit_files(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
commit_oid: git::Oid,
|
||||
) -> Result<Vec<RemoteBranchFile>, Error> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.list_remote_commit_files(project_id, commit_oid)
|
||||
}
|
||||
|
||||
pub async fn set_base_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
target_branch: &git::RemoteBranchName,
|
||||
) -> Result<super::BaseBranch, Error> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.set_base_branch(project_id, target_branch)
|
||||
}
|
||||
|
||||
pub async fn merge_virtual_branch_upstream(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::MergeVirtualBranchUpstreamError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.merge_virtual_branch_upstream(project_id, branch_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_base_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<(), ControllerError<errors::UpdateBaseBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.update_base_branch(project_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_update: super::branch::BranchUpdateRequest,
|
||||
) -> Result<(), ControllerError<errors::UpdateBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.update_virtual_branch(project_id, branch_update)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::DeleteBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.delete_virtual_branch(project_id, branch_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn apply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::ApplyBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.apply_virtual_branch(project_id, branch_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn unapply_ownership(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
ownership: &Ownership,
|
||||
) -> Result<(), ControllerError<errors::UnapplyOwnershipError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.unapply_ownership(project_id, ownership)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn amend(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
ownership: &Ownership,
|
||||
) -> Result<git::Oid, ControllerError<errors::AmendError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.amend(project_id, branch_id, ownership)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn reset_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
target_commit_oid: git::Oid,
|
||||
) -> Result<(), ControllerError<errors::ResetBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.reset_virtual_branch(project_id, branch_id, target_commit_oid)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn unapply_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::UnapplyBranchError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.unapply_virtual_branch(project_id, branch_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn push_virtual_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
) -> Result<(), ControllerError<errors::PushError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.push_virtual_branch(project_id, branch_id, with_force)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn flush_vbranches(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
) -> Result<(), ControllerError<errors::FlushAppliedVbranchesError>> {
|
||||
self.inner(&project_id)
|
||||
.await
|
||||
.flush_vbranches(project_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn cherry_pick(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
commit_oid: git::Oid,
|
||||
) -> Result<Option<git::Oid>, ControllerError<errors::CherryPickError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.cherry_pick(project_id, branch_id, commit_oid)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_remote_branches(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<Vec<super::RemoteBranch>, ControllerError<ListRemoteBranchesError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.list_remote_branches(project_id)
|
||||
}
|
||||
|
||||
pub async fn squash(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
commit_oid: git::Oid,
|
||||
) -> Result<(), ControllerError<errors::SquashError>> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
.squash(project_id, branch_id, commit_oid)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ControllerInner {
|
||||
local_data_dir: DataDir,
|
||||
semaphore: Arc<Semaphore>,
|
||||
|
||||
projects: projects::Controller,
|
||||
users: users::Controller,
|
||||
keys: keys::Controller,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ControllerError<E>
|
||||
where
|
||||
@ -59,7 +352,7 @@ where
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<&DataDir> for Controller {
|
||||
impl From<&DataDir> for ControllerInner {
|
||||
fn from(value: &DataDir) -> Self {
|
||||
Self::new(
|
||||
value,
|
||||
@ -70,7 +363,7 @@ impl From<&DataDir> for Controller {
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
impl ControllerInner {
|
||||
pub fn new(
|
||||
data_dir: &DataDir,
|
||||
projects: &projects::Controller,
|
||||
@ -79,7 +372,7 @@ impl Controller {
|
||||
) -> Self {
|
||||
Self {
|
||||
local_data_dir: data_dir.clone(),
|
||||
semaphores: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
|
||||
semaphore: Arc::new(Semaphore::new(1)),
|
||||
projects: projects.clone(),
|
||||
users: users.clone(),
|
||||
keys: keys.clone(),
|
||||
@ -93,32 +386,31 @@ impl Controller {
|
||||
message: &str,
|
||||
ownership: Option<&Ownership>,
|
||||
) -> Result<git::Oid, ControllerError<errors::CommitError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
super::commit(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
message,
|
||||
ownership,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
super::commit(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
message,
|
||||
ownership,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn can_apply_remote_branch(
|
||||
@ -162,12 +454,11 @@ impl Controller {
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<Vec<super::VirtualBranch>, ControllerError<errors::ListVirtualBranchesError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::list_virtual_branches(gb_repository, project_repository).map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::list_virtual_branches(gb_repository, project_repository).map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_virtual_branch(
|
||||
@ -175,14 +466,13 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
create: &super::branch::BranchCreateRequest,
|
||||
) -> Result<BranchId, ControllerError<errors::CreateVirtualBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
let branch_id =
|
||||
super::create_virtual_branch(gb_repository, project_repository, create)?.id;
|
||||
Ok(branch_id)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
let branch_id =
|
||||
super::create_virtual_branch(gb_repository, project_repository, create)?.id;
|
||||
Ok(branch_id)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_virtual_branch_from_branch(
|
||||
@ -190,41 +480,40 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch: &git::BranchName,
|
||||
) -> Result<BranchId, ControllerError<errors::CreateVirtualBranchFromBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let branch = super::create_virtual_branch_from_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch,
|
||||
None,
|
||||
user,
|
||||
)?;
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let branch = super::create_virtual_branch_from_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch,
|
||||
None,
|
||||
user,
|
||||
)?;
|
||||
|
||||
// also apply the branch
|
||||
super::apply_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
&branch.id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.context("failed to apply branch")?;
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Ok(branch.id)
|
||||
})
|
||||
// also apply the branch
|
||||
super::apply_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
&branch.id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.context("failed to apply branch")?;
|
||||
|
||||
Ok(branch.id)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn get_base_branch_data(
|
||||
@ -288,43 +577,40 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::MergeVirtualBranchUpstreamError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
super::merge_virtual_branch_upstream(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
super::merge_virtual_branch_upstream(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_base_branch(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
) -> Result<(), ControllerError<errors::UpdateBaseBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
super::update_base_branch(gb_repository, project_repository, user)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
super::update_base_branch(gb_repository, project_repository, user).map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_virtual_branch(
|
||||
@ -332,13 +618,12 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_update: super::branch::BranchUpdateRequest,
|
||||
) -> Result<(), ControllerError<errors::UpdateBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::update_branch(gb_repository, project_repository, branch_update)?;
|
||||
Ok(())
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::update_branch(gb_repository, project_repository, branch_update)?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_virtual_branch(
|
||||
@ -346,13 +631,12 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::DeleteBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::delete_branch(gb_repository, project_repository, branch_id)?;
|
||||
Ok(())
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::delete_branch(gb_repository, project_repository, branch_id)?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn apply_virtual_branch(
|
||||
@ -360,30 +644,29 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::ApplyBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
super::apply_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let signing_key = project_repository
|
||||
.config()
|
||||
.sign_commits()
|
||||
.context("failed to get sign commits option")?
|
||||
.then(|| {
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get private key")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
super::apply_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn unapply_ownership(
|
||||
@ -391,13 +674,12 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
ownership: &Ownership,
|
||||
) -> Result<(), ControllerError<errors::UnapplyOwnershipError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::unapply_ownership(gb_repository, project_repository, ownership)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::unapply_ownership(gb_repository, project_repository, ownership)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn amend(
|
||||
@ -406,13 +688,12 @@ impl Controller {
|
||||
branch_id: &BranchId,
|
||||
ownership: &Ownership,
|
||||
) -> Result<git::Oid, ControllerError<errors::AmendError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::amend(gb_repository, project_repository, branch_id, ownership)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::amend(gb_repository, project_repository, branch_id, ownership)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn reset_virtual_branch(
|
||||
@ -421,18 +702,17 @@ impl Controller {
|
||||
branch_id: &BranchId,
|
||||
target_commit_oid: git::Oid,
|
||||
) -> Result<(), ControllerError<errors::ResetBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::reset_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
target_commit_oid,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::reset_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
branch_id,
|
||||
target_commit_oid,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn unapply_virtual_branch(
|
||||
@ -440,13 +720,11 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
) -> Result<(), ControllerError<errors::UnapplyBranchError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::unapply_branch(gb_repository, project_repository, branch_id)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::unapply_branch(gb_repository, project_repository, branch_id).map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn push_virtual_branch(
|
||||
@ -455,40 +733,37 @@ impl Controller {
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
) -> Result<(), ControllerError<errors::PushError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let credentials = git::credentials::Factory::new(
|
||||
project_repository.project(),
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get or create private key")?,
|
||||
user,
|
||||
);
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
super::push(
|
||||
project_repository,
|
||||
gb_repository,
|
||||
branch_id,
|
||||
with_force,
|
||||
&credentials,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, user| {
|
||||
let credentials = git::credentials::Factory::new(
|
||||
project_repository.project(),
|
||||
self.keys
|
||||
.get_or_create()
|
||||
.context("failed to get or create private key")?,
|
||||
user,
|
||||
);
|
||||
|
||||
super::push(
|
||||
project_repository,
|
||||
gb_repository,
|
||||
branch_id,
|
||||
with_force,
|
||||
&credentials,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn flush_vbranches(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
) -> Result<(), ControllerError<errors::FlushAppliedVbranchesError>> {
|
||||
self.with_lock(&project_id, || {
|
||||
self.with_verify_branch(&project_id, |gb_repository, project_repository, _| {
|
||||
super::flush_applied_vbranches(gb_repository, project_repository)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(&project_id, |gb_repository, project_repository, _| {
|
||||
super::flush_applied_vbranches(gb_repository, project_repository).map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn cherry_pick(
|
||||
@ -497,13 +772,12 @@ impl Controller {
|
||||
branch_id: &BranchId,
|
||||
commit_oid: git::Oid,
|
||||
) -> Result<Option<git::Oid>, ControllerError<errors::CherryPickError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::cherry_pick(gb_repository, project_repository, branch_id, commit_oid)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::cherry_pick(gb_repository, project_repository, branch_id, commit_oid)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn list_remote_branches(
|
||||
@ -530,17 +804,16 @@ impl Controller {
|
||||
branch_id: &BranchId,
|
||||
commit_oid: git::Oid,
|
||||
) -> Result<(), ControllerError<errors::SquashError>> {
|
||||
self.with_lock(project_id, || {
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::squash(gb_repository, project_repository, branch_id, commit_oid)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |gb_repository, project_repository, _| {
|
||||
super::squash(gb_repository, project_repository, branch_id, commit_oid)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
impl ControllerInner {
|
||||
fn with_verify_branch<T, E: Into<Error>>(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
@ -563,13 +836,4 @@ impl Controller {
|
||||
super::integration::verify_branch(&gb_repository, &project_repository)?;
|
||||
action(&gb_repository, &project_repository, user.as_ref()).map_err(ControllerError::Action)
|
||||
}
|
||||
|
||||
async fn with_lock<T>(&self, project_id: &ProjectId, action: impl FnOnce() -> T) -> T {
|
||||
let mut semaphores = self.semaphores.lock().await;
|
||||
let semaphore = semaphores
|
||||
.entry(project_id.to_string())
|
||||
.or_insert_with(|| Semaphore::new(1));
|
||||
let _permit = semaphore.acquire().await;
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ mod create_commit {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -128,6 +129,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -162,6 +164,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -220,6 +223,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -273,6 +277,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -342,6 +347,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let id = controller
|
||||
@ -389,6 +395,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -444,6 +451,7 @@ mod references {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = {
|
||||
@ -538,8 +546,8 @@ mod references {
|
||||
mod set_base_branch {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn success() {
|
||||
#[tokio::test]
|
||||
async fn success() {
|
||||
let Test {
|
||||
project_id,
|
||||
controller,
|
||||
@ -551,14 +559,15 @@ mod set_base_branch {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
mod errors {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing() {
|
||||
#[tokio::test]
|
||||
async fn missing() {
|
||||
let Test {
|
||||
project_id,
|
||||
controller,
|
||||
@ -566,10 +575,12 @@ mod set_base_branch {
|
||||
} = Test::default();
|
||||
|
||||
assert!(matches!(
|
||||
controller.set_base_branch(
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/missing").unwrap(),
|
||||
),
|
||||
controller
|
||||
.set_base_branch(
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/missing").unwrap(),
|
||||
)
|
||||
.await,
|
||||
Err(Error::UserError { .. })
|
||||
));
|
||||
}
|
||||
@ -595,6 +606,7 @@ mod conflicts {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = {
|
||||
@ -626,6 +638,7 @@ mod conflicts {
|
||||
// it should not be possible to apply the first branch
|
||||
assert!(!controller
|
||||
.can_apply_virtual_branch(&project_id, &branch1_id)
|
||||
.await
|
||||
.unwrap());
|
||||
|
||||
assert!(matches!(
|
||||
@ -663,6 +676,7 @@ mod conflicts {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = {
|
||||
@ -785,6 +799,7 @@ mod conflicts {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = {
|
||||
@ -890,6 +905,7 @@ mod conflicts {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = {
|
||||
@ -988,6 +1004,7 @@ mod reset_virtual_branch {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1051,6 +1068,7 @@ mod reset_virtual_branch {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1111,6 +1129,7 @@ mod reset_virtual_branch {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1197,6 +1216,7 @@ mod reset_virtual_branch {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1258,6 +1278,7 @@ mod upstream {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1326,6 +1347,7 @@ mod upstream {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch1_id = controller
|
||||
@ -1414,6 +1436,7 @@ mod cherry_pick {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1487,6 +1510,7 @@ mod cherry_pick {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1571,6 +1595,7 @@ mod cherry_pick {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1637,6 +1662,7 @@ mod cherry_pick {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1758,6 +1784,7 @@ mod cherry_pick {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1800,6 +1827,7 @@ mod amend {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1833,6 +1861,7 @@ mod amend {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1896,6 +1925,7 @@ mod amend {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -1968,6 +1998,7 @@ mod amend {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -2034,6 +2065,7 @@ mod init {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
@ -2058,6 +2090,7 @@ mod init {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branches = controller.list_virtual_branches(&project_id).await.unwrap();
|
||||
@ -2084,6 +2117,7 @@ mod squash {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -2150,6 +2184,7 @@ mod squash {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
@ -2222,6 +2257,7 @@ mod squash {
|
||||
&project_id,
|
||||
&git::RemoteBranchName::from_str("refs/remotes/origin/master").unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let branch_id = controller
|
||||
|
Loading…
Reference in New Issue
Block a user