2024-04-27 00:20:31 +03:00
use crate ::{
error ::Error ,
2024-05-08 01:24:57 +03:00
ops ::{
2024-04-27 00:20:31 +03:00
entry ::{ OperationType , SnapshotDetails } ,
2024-05-08 01:16:44 +03:00
oplog ::Oplog ,
2024-05-13 02:07:42 +03:00
snapshot ::Snapshot ,
2024-04-27 00:20:31 +03:00
} ,
} ;
2024-04-21 10:26:34 +03:00
use std ::{ collections ::HashMap , path ::Path , sync ::Arc } ;
2024-03-29 12:04:26 +03:00
use anyhow ::Context ;
use tokio ::{ sync ::Semaphore , task ::JoinHandle } ;
2024-03-31 00:25:36 +03:00
use super ::{
branch ::{ BranchId , BranchOwnershipClaims } ,
2024-05-21 11:16:37 +03:00
errors ::{ self } ,
2024-04-21 10:26:34 +03:00
target , target_to_base_branch , BaseBranch , RemoteBranchFile , VirtualBranchesHandle ,
2024-03-31 00:25:36 +03:00
} ;
2024-03-31 00:27:56 +03:00
use crate ::{
2024-05-07 16:15:25 +03:00
git , project_repository ,
2024-03-31 00:27:56 +03:00
projects ::{ self , ProjectId } ,
users ,
} ;
2024-03-31 00:25:36 +03:00
2024-03-29 12:04:26 +03:00
#[ derive(Clone) ]
pub struct Controller {
projects : projects ::Controller ,
users : users ::Controller ,
helper : git ::credentials ::Helper ,
by_project_id : Arc < tokio ::sync ::Mutex < HashMap < ProjectId , ControllerInner > > > ,
}
impl Controller {
pub fn new (
projects : projects ::Controller ,
users : users ::Controller ,
helper : git ::credentials ::Helper ,
) -> Self {
Self {
by_project_id : Arc ::new ( tokio ::sync ::Mutex ::new ( HashMap ::new ( ) ) ) ,
projects ,
users ,
helper ,
}
}
async fn inner ( & self , project_id : & ProjectId ) -> ControllerInner {
self . by_project_id
. lock ( )
. await
. entry ( * project_id )
2024-05-07 16:15:25 +03:00
. or_insert_with ( | | ControllerInner ::new ( & self . projects , & self . users , & self . helper ) )
2024-03-29 12:04:26 +03:00
. clone ( )
}
pub async fn create_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
message : & str ,
ownership : Option < & BranchOwnershipClaims > ,
run_hooks : bool ,
2024-04-01 16:57:09 +03:00
) -> Result < git ::Oid , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. create_commit ( project_id , branch_id , message , ownership , run_hooks )
. await
}
pub async fn can_apply_remote_branch (
& self ,
project_id : & ProjectId ,
branch_name : & git ::RemoteRefname ,
2024-04-01 16:57:09 +03:00
) -> Result < bool , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < bool , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. can_apply_virtual_branch ( project_id , branch_id )
}
pub async fn list_virtual_branches (
& self ,
project_id : & ProjectId ,
2024-04-17 08:14:43 +03:00
) -> Result < ( Vec < super ::VirtualBranch > , Vec < git ::diff ::FileDiff > ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < BranchId , Error > {
2024-03-29 12:04:26 +03:00
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 ::Refname ,
2024-04-01 16:57:09 +03:00
) -> Result < BranchId , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. create_virtual_branch_from_branch ( project_id , branch )
. await
}
2024-05-21 11:16:37 +03:00
pub async fn get_base_branch_data ( & self , project_id : & ProjectId ) -> Result < BaseBranch , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < Vec < RemoteBranchFile > , Error > {
2024-03-29 12:04:26 +03:00
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 ::RemoteRefname ,
2024-04-01 16:57:09 +03:00
) -> Result < super ::BaseBranch , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. set_base_branch ( project_id , target_branch )
}
2024-05-03 12:20:47 +03:00
pub async fn set_target_push_remote (
& self ,
project_id : & ProjectId ,
push_remote : & str ,
) -> Result < ( ) , Error > {
self . inner ( project_id )
. await
. set_target_push_remote ( project_id , push_remote )
}
2024-05-23 05:41:13 +03:00
pub async fn integrate_upstream_commits (
2024-03-29 12:04:26 +03:00
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
2024-05-23 05:41:13 +03:00
. integrate_upstream_commits ( project_id , branch_id )
2024-03-29 12:04:26 +03:00
. await
}
2024-04-01 16:57:09 +03:00
pub async fn update_base_branch ( & self , project_id : & ProjectId ) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. apply_virtual_branch ( project_id , branch_id )
. await
}
pub async fn unapply_ownership (
& self ,
project_id : & ProjectId ,
ownership : & BranchOwnershipClaims ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. unapply_ownership ( project_id , ownership )
. await
}
pub async fn reset_files (
& self ,
project_id : & ProjectId ,
files : & Vec < String > ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. reset_files ( project_id , files )
. await
}
pub async fn amend (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-29 16:03:01 +03:00
commit_oid : git ::Oid ,
2024-03-29 12:04:26 +03:00
ownership : & BranchOwnershipClaims ,
2024-04-01 16:57:09 +03:00
) -> Result < git ::Oid , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
2024-04-29 16:03:01 +03:00
. amend ( project_id , branch_id , commit_oid , ownership )
. await
}
pub async fn move_commit_file (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
from_commit_oid : git ::Oid ,
to_commit_oid : git ::Oid ,
ownership : & BranchOwnershipClaims ,
) -> Result < git ::Oid , Error > {
self . inner ( project_id )
. await
. move_commit_file (
project_id ,
branch_id ,
from_commit_oid ,
to_commit_oid ,
ownership ,
)
. await
}
pub async fn undo_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
) -> Result < ( ) , Error > {
self . inner ( project_id )
. await
. undo_commit ( project_id , branch_id , commit_oid )
. await
}
pub async fn insert_blank_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
offset : i32 ,
) -> Result < ( ) , Error > {
self . inner ( project_id )
. await
. insert_blank_commit ( project_id , branch_id , commit_oid , offset )
. await
}
pub async fn reorder_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
offset : i32 ,
) -> Result < ( ) , Error > {
self . inner ( project_id )
. await
. reorder_commit ( project_id , branch_id , commit_oid , offset )
2024-03-29 12:04:26 +03:00
. await
}
pub async fn reset_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
target_commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
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 ,
2024-05-07 17:07:37 +03:00
askpass : Option < Option < BranchId > > ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. push_virtual_branch ( project_id , branch_id , with_force , askpass )
. await
}
pub async fn cherry_pick (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < Option < git ::Oid > , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. cherry_pick ( project_id , branch_id , commit_oid )
. await
}
pub async fn list_remote_branches (
& self ,
project_id : & ProjectId ,
2024-04-01 16:57:09 +03:00
) -> Result < Vec < super ::RemoteBranch > , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. list_remote_branches ( project_id )
}
pub async fn get_remote_branch_data (
& self ,
project_id : & ProjectId ,
refname : & git ::Refname ,
2024-04-01 16:57:09 +03:00
) -> Result < super ::RemoteBranchData , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. get_remote_branch_data ( project_id , refname )
}
pub async fn squash (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. squash ( project_id , branch_id , commit_oid )
. await
}
pub async fn update_commit_message (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
message : & str ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. update_commit_message ( project_id , branch_id , commit_oid , message )
. await
}
pub async fn fetch_from_target (
& self ,
project_id : & ProjectId ,
2024-05-07 17:07:37 +03:00
askpass : Option < String > ,
2024-04-01 16:57:09 +03:00
) -> Result < BaseBranch , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. fetch_from_target ( project_id , askpass )
. await
}
pub async fn move_commit (
& self ,
project_id : & ProjectId ,
target_branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
self . inner ( project_id )
. await
. move_commit ( project_id , target_branch_id , commit_oid )
. await
}
}
#[ derive(Clone) ]
struct ControllerInner {
semaphore : Arc < Semaphore > ,
projects : projects ::Controller ,
users : users ::Controller ,
helper : git ::credentials ::Helper ,
}
impl ControllerInner {
pub fn new (
projects : & projects ::Controller ,
users : & users ::Controller ,
helper : & git ::credentials ::Helper ,
) -> Self {
Self {
semaphore : Arc ::new ( Semaphore ::new ( 1 ) ) ,
projects : projects . clone ( ) ,
users : users . clone ( ) ,
helper : helper . clone ( ) ,
}
}
pub async fn create_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
message : & str ,
ownership : Option < & BranchOwnershipClaims > ,
run_hooks : bool ,
2024-04-01 16:57:09 +03:00
) -> Result < git ::Oid , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-23 12:45:14 +03:00
let _ = project_repository
. project ( )
. snapshot_commit_creation ( message . to_owned ( ) , Some ( " " . to_string ( ) ) ) ; // TODO(kv): We can do this properly when we make the snapshotting in 2 parts (create tree + commit)
super ::commit (
2024-03-29 12:04:26 +03:00
project_repository ,
branch_id ,
message ,
ownership ,
user ,
run_hooks ,
)
2024-05-23 12:45:14 +03:00
. map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
} )
}
pub fn can_apply_remote_branch (
& self ,
project_id : & ProjectId ,
branch_name : & git ::RemoteRefname ,
2024-04-01 16:57:09 +03:00
) -> Result < bool , Error > {
2024-03-31 22:52:56 +03:00
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 ,
) ? )
2024-03-29 12:04:26 +03:00
}
pub fn can_apply_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < bool , Error > {
2024-03-29 12:04:26 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-19 23:11:30 +03:00
super ::is_virtual_branch_mergeable ( & project_repository , branch_id ) . map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
}
pub async fn list_virtual_branches (
& self ,
project_id : & ProjectId ,
2024-04-17 08:14:43 +03:00
) -> Result < ( Vec < super ::VirtualBranch > , Vec < git ::diff ::FileDiff > ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-19 23:48:43 +03:00
super ::list_virtual_branches ( project_repository ) . map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
} )
}
pub async fn create_virtual_branch (
& self ,
project_id : & ProjectId ,
create : & super ::branch ::BranchCreateRequest ,
2024-04-01 16:57:09 +03:00
) -> Result < BranchId , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-19 23:05:33 +03:00
let branch_id = super ::create_virtual_branch ( project_repository , create ) ? . id ;
2024-03-29 12:04:26 +03:00
Ok ( branch_id )
} )
}
pub async fn create_virtual_branch_from_branch (
& self ,
project_id : & ProjectId ,
branch : & git ::Refname ,
2024-04-01 16:57:09 +03:00
) -> Result < BranchId , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-07 16:15:25 +03:00
let result =
super ::create_virtual_branch_from_branch ( project_repository , branch , user ) ? ;
2024-04-25 16:31:51 +03:00
Ok ( result )
2024-03-29 12:04:26 +03:00
} )
}
2024-05-21 11:16:37 +03:00
pub fn get_base_branch_data ( & self , project_id : & ProjectId ) -> Result < BaseBranch , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-21 10:10:37 +03:00
Ok ( super ::get_base_branch_data ( & project_repository ) ? )
2024-03-29 12:04:26 +03:00
}
pub fn list_remote_commit_files (
& self ,
project_id : & ProjectId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < Vec < RemoteBranchFile > , Error > {
2024-03-29 12:04:26 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-17 07:59:13 +03:00
super ::list_remote_commit_files ( & project_repository . git_repository , commit_oid )
2024-04-17 07:52:08 +03:00
. map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
}
pub fn set_base_branch (
& self ,
project_id : & ProjectId ,
target_branch : & git ::RemoteRefname ,
2024-04-01 16:57:09 +03:00
) -> Result < super ::BaseBranch , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-25 16:31:51 +03:00
let result = super ::set_base_branch ( & project_repository , target_branch ) ? ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::SetBaseBranch ) ) ;
2024-04-25 16:31:51 +03:00
Ok ( result )
2024-03-29 12:04:26 +03:00
}
2024-05-03 12:20:47 +03:00
pub fn set_target_push_remote (
& self ,
project_id : & ProjectId ,
push_remote : & str ,
) -> 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 ( ( ) )
}
2024-05-23 05:41:13 +03:00
pub async fn integrate_upstream_commits (
2024-03-29 12:04:26 +03:00
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-23 04:52:13 +03:00
let result = super ::integrate_upstream_commits ( project_repository , branch_id , user )
2024-05-07 16:15:25 +03:00
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::MergeUpstream ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
2024-04-01 16:57:09 +03:00
pub async fn update_base_branch ( & self , project_id : & ProjectId ) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-07 16:15:25 +03:00
let result = super ::update_base_branch ( project_repository , user ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::UpdateWorkspaceBase ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn update_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_update : super ::branch ::BranchUpdateRequest ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-19 23:23:24 +03:00
super ::update_branch ( project_repository , branch_update ) ? ;
2024-03-29 12:04:26 +03:00
Ok ( ( ) )
} )
}
pub async fn delete_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-05-08 01:00:18 +03:00
super ::delete_branch ( project_repository , branch_id )
2024-03-29 12:04:26 +03:00
} )
}
pub async fn apply_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-15 14:40:27 +03:00
super ::apply_branch ( project_repository , branch_id , user ) . map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
} )
}
pub async fn unapply_ownership (
& self ,
project_id : & ProjectId ,
ownership : & BranchOwnershipClaims ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result =
super ::unapply_ownership ( project_repository , ownership ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::DiscardHunk ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn reset_files (
& self ,
project_id : & ProjectId ,
ownership : & Vec < String > ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result = super ::reset_files ( project_repository , ownership ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::DiscardFile ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn amend (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-29 16:03:01 +03:00
commit_oid : git ::Oid ,
2024-03-29 12:04:26 +03:00
ownership : & BranchOwnershipClaims ,
2024-04-01 16:57:09 +03:00
) -> Result < git ::Oid , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-29 16:03:01 +03:00
let result = super ::amend ( project_repository , branch_id , commit_oid , ownership )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::AmendCommit ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
2024-04-29 16:03:01 +03:00
pub async fn move_commit_file (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
from_commit_oid : git ::Oid ,
to_commit_oid : git ::Oid ,
ownership : & BranchOwnershipClaims ,
) -> Result < git ::Oid , Error > {
let _permit = self . semaphore . acquire ( ) . await ;
self . with_verify_branch ( project_id , | project_repository , _ | {
let result = super ::move_commit_file (
project_repository ,
branch_id ,
from_commit_oid ,
to_commit_oid ,
ownership ,
)
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::MoveCommitFile ) ) ;
2024-04-29 16:03:01 +03:00
result
} )
}
pub async fn undo_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
) -> Result < ( ) , Error > {
let _permit = self . semaphore . acquire ( ) . await ;
self . with_verify_branch ( project_id , | project_repository , _ | {
let result =
super ::undo_commit ( project_repository , branch_id , commit_oid ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-13 17:37:37 +03:00
. snapshot_commit_undo ( commit_oid . to_string ( ) ) ;
2024-04-29 16:03:01 +03:00
result
} )
}
pub async fn insert_blank_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
offset : i32 ,
) -> Result < ( ) , Error > {
let _permit = self . semaphore . acquire ( ) . await ;
self . with_verify_branch ( project_id , | project_repository , user | {
let result =
super ::insert_blank_commit ( project_repository , branch_id , commit_oid , user , offset )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::InsertBlankCommit ) ) ;
2024-04-29 16:03:01 +03:00
result
} )
}
pub async fn reorder_commit (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
offset : i32 ,
) -> Result < ( ) , Error > {
let _permit = self . semaphore . acquire ( ) . await ;
self . with_verify_branch ( project_id , | project_repository , _ | {
let result = super ::reorder_commit ( project_repository , branch_id , commit_oid , offset )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::ReorderCommit ) ) ;
2024-04-29 16:03:01 +03:00
result
} )
}
2024-03-29 12:04:26 +03:00
pub async fn reset_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
target_commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result = super ::reset_branch ( project_repository , branch_id , target_commit_oid )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::UndoCommit ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn unapply_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-05-14 15:35:47 +03:00
let result = super ::unapply_branch ( project_repository , branch_id ) ;
result . map ( | _ | ( ) ) . map_err ( Into ::into )
2024-03-29 12:04:26 +03:00
} )
}
pub async fn push_virtual_branch (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
with_force : bool ,
2024-05-07 17:07:37 +03:00
askpass : Option < Option < BranchId > > ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
let helper = self . helper . clone ( ) ;
let project_id = * project_id ;
let branch_id = * branch_id ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch_async ( & project_id , move | project_repository , _ | {
2024-03-31 22:52:56 +03:00
Ok ( super ::push (
2024-03-29 12:04:26 +03:00
project_repository ,
& branch_id ,
with_force ,
& helper ,
askpass ,
2024-03-31 22:52:56 +03:00
) ? )
2024-03-29 12:04:26 +03:00
} ) ?
. await
2024-04-01 16:57:09 +03:00
. map_err ( Error ::from_err ) ?
2024-03-29 12:04:26 +03:00
}
pub async fn cherry_pick (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < Option < git ::Oid > , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result =
super ::cherry_pick ( project_repository , branch_id , commit_oid ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::CherryPick ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub fn list_remote_branches (
& self ,
project_id : & ProjectId ,
2024-04-01 16:57:09 +03:00
) -> Result < Vec < super ::RemoteBranch > , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-21 10:16:14 +03:00
Ok ( super ::list_remote_branches ( & project_repository ) ? )
2024-03-29 12:04:26 +03:00
}
pub fn get_remote_branch_data (
& self ,
project_id : & ProjectId ,
refname : & git ::Refname ,
2024-04-01 16:57:09 +03:00
) -> Result < super ::RemoteBranchData , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-04-21 10:16:14 +03:00
Ok ( super ::get_branch_data ( & project_repository , refname ) ? )
2024-03-29 12:04:26 +03:00
}
pub async fn squash (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result =
super ::squash ( project_repository , branch_id , commit_oid ) . map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::SquashCommit ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn update_commit_message (
& self ,
project_id : & ProjectId ,
branch_id : & BranchId ,
commit_oid : git ::Oid ,
message : & str ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , _ | {
2024-04-25 16:31:51 +03:00
let result =
super ::update_commit_message ( project_repository , branch_id , commit_oid , message )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::UpdateCommitMessage ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
pub async fn fetch_from_target (
& self ,
project_id : & ProjectId ,
2024-05-07 17:07:37 +03:00
askpass : Option < String > ,
2024-04-01 16:57:09 +03:00
) -> Result < BaseBranch , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let mut project_repository = project_repository ::Repository ::open ( & project ) ? ;
2024-03-29 12:04:26 +03:00
2024-05-21 11:16:37 +03:00
let default_target = default_target ( & project_repository . project ( ) . gb_dir ( ) ) ? ;
2024-03-29 12:04:26 +03:00
let project_data_last_fetched = match project_repository
2024-05-06 17:01:06 +03:00
. fetch (
default_target . branch . remote ( ) ,
& self . helper ,
askpass . clone ( ) ,
)
2024-03-29 12:04:26 +03:00
. map_err ( errors ::FetchFromTargetError ::Remote )
{
Ok ( ( ) ) = > projects ::FetchResult ::Fetched {
timestamp : std ::time ::SystemTime ::now ( ) ,
} ,
Err ( error ) = > projects ::FetchResult ::Error {
timestamp : std ::time ::SystemTime ::now ( ) ,
error : error . to_string ( ) ,
} ,
} ;
2024-05-06 17:01:06 +03:00
// if we have a push remote, let's fetch from this too
if let Some ( push_remote ) = & default_target . push_remote_name {
let _ = project_repository
. fetch ( push_remote , & self . helper , askpass . clone ( ) )
. map_err ( errors ::FetchFromTargetError ::Remote ) ;
}
2024-03-29 12:04:26 +03:00
let updated_project = self
. projects
. update ( & projects ::UpdateRequest {
id : * project_id ,
project_data_last_fetched : Some ( project_data_last_fetched ) ,
.. Default ::default ( )
} )
. await
. context ( " failed to update project " ) ? ;
project_repository . set_project ( & updated_project ) ;
let base_branch = target_to_base_branch ( & project_repository , & default_target )
. context ( " failed to convert target to base branch " ) ? ;
Ok ( base_branch )
}
pub async fn move_commit (
& self ,
project_id : & ProjectId ,
target_branch_id : & BranchId ,
commit_oid : git ::Oid ,
2024-04-01 16:57:09 +03:00
) -> Result < ( ) , Error > {
2024-03-29 12:04:26 +03:00
let _permit = self . semaphore . acquire ( ) . await ;
2024-04-21 10:26:34 +03:00
self . with_verify_branch ( project_id , | project_repository , user | {
2024-05-07 16:15:25 +03:00
let result = super ::move_commit ( project_repository , target_branch_id , commit_oid , user )
. map_err ( Into ::into ) ;
2024-05-05 23:34:15 +03:00
let _ = project_repository
2024-05-05 23:28:12 +03:00
. project ( )
2024-05-05 23:34:15 +03:00
. create_snapshot ( SnapshotDetails ::new ( OperationType ::MoveCommit ) ) ;
2024-04-25 16:31:51 +03:00
result
2024-03-29 12:04:26 +03:00
} )
}
}
impl ControllerInner {
2024-03-31 22:52:56 +03:00
fn with_verify_branch < T > (
2024-03-29 12:04:26 +03:00
& self ,
project_id : & ProjectId ,
2024-04-21 10:26:34 +03:00
action : impl FnOnce ( & project_repository ::Repository , Option < & users ::User > ) -> Result < T , Error > ,
2024-04-01 16:57:09 +03:00
) -> Result < T , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
let user = self . users . get_user ( ) ? ;
2024-04-19 23:09:28 +03:00
super ::integration ::verify_branch ( & project_repository ) ? ;
2024-04-21 10:26:34 +03:00
action ( & project_repository , user . as_ref ( ) )
2024-03-29 12:04:26 +03:00
}
2024-03-31 22:52:56 +03:00
fn with_verify_branch_async < T : Send + 'static > (
2024-03-29 12:04:26 +03:00
& self ,
project_id : & ProjectId ,
2024-04-21 10:26:34 +03:00
action : impl FnOnce ( & project_repository ::Repository , Option < & users ::User > ) -> Result < T , Error >
2024-03-29 12:04:26 +03:00
+ Send
+ 'static ,
2024-04-01 16:57:09 +03:00
) -> Result < JoinHandle < Result < T , Error > > , Error > {
2024-03-31 22:52:56 +03:00
let project = self . projects . get ( project_id ) ? ;
let project_repository = project_repository ::Repository ::open ( & project ) ? ;
let user = self . users . get_user ( ) ? ;
2024-04-19 23:09:28 +03:00
super ::integration ::verify_branch ( & project_repository ) ? ;
2024-03-29 12:04:26 +03:00
Ok ( tokio ::task ::spawn_blocking ( move | | {
2024-04-21 10:26:34 +03:00
action ( & project_repository , user . as_ref ( ) )
2024-03-29 12:04:26 +03:00
} ) )
}
}
2024-04-21 10:26:34 +03:00
2024-05-21 11:16:37 +03:00
fn default_target ( base_path : & Path ) -> anyhow ::Result < target ::Target > {
VirtualBranchesHandle ::new ( base_path ) . get_default_target ( )
2024-04-21 10:26:34 +03:00
}