2024-07-07 14:32:35 +03:00
|
|
|
use anyhow::Result;
|
2024-07-07 22:26:07 +03:00
|
|
|
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesHandle};
|
2024-07-07 14:32:35 +03:00
|
|
|
use gitbutler_core::{
|
2024-07-08 00:37:15 +03:00
|
|
|
git::{credentials::Helper, BranchExt, RepositoryExt},
|
2024-07-07 23:28:27 +03:00
|
|
|
project_repository::{ProjectRepo, RepoActions},
|
2024-07-04 17:34:53 +03:00
|
|
|
projects::FetchResult,
|
2024-07-01 17:13:52 +03:00
|
|
|
types::ReferenceName,
|
|
|
|
};
|
2024-07-07 21:00:01 +03:00
|
|
|
use gitbutler_oplog::{
|
|
|
|
entry::{OperationKind, SnapshotDetails},
|
|
|
|
oplog::Oplog,
|
|
|
|
snapshot::Snapshot,
|
|
|
|
};
|
2024-07-04 13:21:22 +03:00
|
|
|
use std::{path::Path, sync::Arc};
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
use tokio::sync::Semaphore;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-07 21:48:12 +03:00
|
|
|
use crate::{
|
|
|
|
base::{
|
|
|
|
get_base_branch_data, set_base_branch, set_target_push_remote, update_base_branch,
|
|
|
|
BaseBranch,
|
|
|
|
},
|
|
|
|
remote::{get_branch_data, list_remote_branches, RemoteBranch, RemoteBranchData},
|
2024-07-07 17:29:24 +03:00
|
|
|
};
|
|
|
|
|
2024-07-07 16:51:07 +03:00
|
|
|
use super::r#virtual as branch;
|
2024-07-07 14:32:35 +03:00
|
|
|
use gitbutler_core::virtual_branches;
|
|
|
|
|
2024-07-07 21:35:26 +03:00
|
|
|
use crate::files::RemoteBranchFile;
|
2024-07-07 14:32:35 +03:00
|
|
|
use gitbutler_core::virtual_branches::{
|
2024-03-31 00:25:36 +03:00
|
|
|
branch::{BranchId, BranchOwnershipClaims},
|
2024-07-07 22:26:07 +03:00
|
|
|
target,
|
2024-03-31 00:25:36 +03:00
|
|
|
};
|
2024-07-07 14:32:35 +03:00
|
|
|
use gitbutler_core::{
|
2024-07-04 18:12:20 +03:00
|
|
|
git,
|
2024-07-04 16:26:10 +03:00
|
|
|
projects::{self, Project},
|
2024-03-31 00:27:56 +03:00
|
|
|
};
|
2024-03-31 00:25:36 +03:00
|
|
|
|
2024-03-29 12:04:26 +03:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Controller {
|
2024-07-04 13:21:22 +03:00
|
|
|
semaphore: Arc<Semaphore>,
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-06 18:03:46 +03:00
|
|
|
impl Default for Controller {
|
|
|
|
fn default() -> Self {
|
2024-03-29 12:04:26 +03:00
|
|
|
Self {
|
2024-07-04 13:21:22 +03:00
|
|
|
semaphore: Arc::new(Semaphore::new(1)),
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
}
|
2024-07-06 18:03:46 +03:00
|
|
|
}
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-06 18:03:46 +03:00
|
|
|
impl Controller {
|
2024-03-29 12:04:26 +03:00
|
|
|
pub async fn create_commit(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
message: &str,
|
|
|
|
ownership: Option<&BranchOwnershipClaims>,
|
|
|
|
run_hooks: bool,
|
2024-06-05 23:56:03 +03:00
|
|
|
) -> Result<git2::Oid> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
2024-07-07 16:51:07 +03:00
|
|
|
let result = branch::commit(
|
2024-07-04 18:12:20 +03:00
|
|
|
&project_repository,
|
|
|
|
branch_id,
|
|
|
|
message,
|
|
|
|
ownership,
|
|
|
|
run_hooks,
|
|
|
|
)
|
|
|
|
.map_err(Into::into);
|
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository.project().snapshot_commit_creation(
|
|
|
|
snapshot_tree,
|
|
|
|
result.as_ref().err(),
|
|
|
|
message.to_owned(),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
result
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 13:21:22 +03:00
|
|
|
pub async fn can_apply_remote_branch(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch_name: &git::RemoteRefname,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<bool> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::is_remote_branch_mergeable(&project_repository, branch_name).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn list_virtual_branches(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-07-07 16:51:07 +03:00
|
|
|
) -> Result<(Vec<branch::VirtualBranch>, Vec<git::diff::FileDiff>)> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::list_virtual_branches(&project_repository).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-07-07 14:32:35 +03:00
|
|
|
create: &virtual_branches::branch::BranchCreateRequest,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<BranchId> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
let branch_id = branch::create_virtual_branch(&project_repository, create)?.id;
|
2024-07-04 18:12:20 +03:00
|
|
|
Ok(branch_id)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn create_virtual_branch_from_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-03-29 12:04:26 +03:00
|
|
|
branch: &git::Refname,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<BranchId> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::create_virtual_branch_from_branch(&project_repository, branch).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 16:26:10 +03:00
|
|
|
pub async fn get_base_branch_data(&self, project: &Project) -> Result<BaseBranch> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 17:29:24 +03:00
|
|
|
get_base_branch_data(&project_repository)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 13:21:22 +03:00
|
|
|
pub async fn list_remote_commit_files(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<Vec<RemoteBranchFile>> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 21:35:26 +03:00
|
|
|
crate::files::list_remote_commit_files(project_repository.repo(), commit_oid)
|
2024-07-07 14:32:35 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 13:21:22 +03:00
|
|
|
pub async fn set_base_branch(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-03-29 12:04:26 +03:00
|
|
|
target_branch: &git::RemoteRefname,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<BaseBranch> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-05-05 23:34:15 +03:00
|
|
|
let _ = project_repository
|
2024-05-05 23:28:12 +03:00
|
|
|
.project()
|
2024-05-26 10:52:43 +03:00
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::SetBaseBranch));
|
2024-07-07 17:29:24 +03:00
|
|
|
set_base_branch(&project_repository, target_branch)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 16:26:10 +03:00
|
|
|
pub async fn set_target_push_remote(&self, project: &Project, push_remote: &str) -> Result<()> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 17:29:24 +03:00
|
|
|
set_target_push_remote(&project_repository, push_remote)
|
2024-05-03 12:20:47 +03:00
|
|
|
}
|
|
|
|
|
2024-05-23 05:41:13 +03:00
|
|
|
pub async fn integrate_upstream_commits(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MergeUpstream));
|
2024-07-07 18:30:18 +03:00
|
|
|
branch::integrate_upstream_commits(&project_repository, branch_id).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 16:26:10 +03:00
|
|
|
pub async fn update_base_branch(&self, project: &Project) -> Result<Vec<ReferenceName>> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UpdateWorkspaceBase));
|
2024-07-07 17:29:24 +03:00
|
|
|
update_base_branch(&project_repository)
|
2024-07-04 18:12:20 +03:00
|
|
|
.map(|unapplied_branches| {
|
|
|
|
unapplied_branches
|
|
|
|
.iter()
|
|
|
|
.filter_map(|unapplied_branch| unapplied_branch.reference_name().ok())
|
|
|
|
.collect()
|
|
|
|
})
|
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_virtual_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-07-07 14:32:35 +03:00
|
|
|
branch_update: virtual_branches::branch::BranchUpdateRequest,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let old_branch = project_repository
|
|
|
|
.project()
|
|
|
|
.virtual_branches()
|
|
|
|
.get_branch(branch_update.id)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
let result = branch::update_branch(&project_repository, &branch_update);
|
2024-07-04 18:12:20 +03:00
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository.project().snapshot_branch_update(
|
|
|
|
snapshot_tree,
|
|
|
|
&old_branch,
|
|
|
|
&branch_update,
|
|
|
|
result.as_ref().err(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
result?;
|
|
|
|
Ok(())
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
pub async fn delete_virtual_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::delete_branch(&project_repository, branch_id)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn unapply_ownership(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::DiscardHunk));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::unapply_ownership(&project_repository, ownership).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 16:26:10 +03:00
|
|
|
pub async fn reset_files(&self, project: &Project, files: &Vec<String>) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::DiscardFile));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::reset_files(&project_repository, files).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn amend(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-03-29 12:04:26 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-06-05 23:56:03 +03:00
|
|
|
) -> Result<git2::Oid> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::AmendCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::amend(&project_repository, branch_id, commit_oid, ownership)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-04-29 16:03:01 +03:00
|
|
|
pub async fn move_commit_file(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
from_commit_oid: git2::Oid,
|
|
|
|
to_commit_oid: git2::Oid,
|
2024-04-29 16:03:01 +03:00
|
|
|
ownership: &BranchOwnershipClaims,
|
2024-06-05 23:56:03 +03:00
|
|
|
) -> Result<git2::Oid> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-04-29 16:03:01 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MoveCommitFile));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::move_commit_file(
|
2024-07-04 18:12:20 +03:00
|
|
|
&project_repository,
|
|
|
|
branch_id,
|
|
|
|
from_commit_oid,
|
|
|
|
to_commit_oid,
|
|
|
|
ownership,
|
|
|
|
)
|
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn undo_commit(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-04-29 16:03:01 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
|
|
|
let result: Result<()> =
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::undo_commit(&project_repository, branch_id, commit_oid).map_err(Into::into);
|
2024-07-04 18:12:20 +03:00
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository.project().snapshot_commit_undo(
|
|
|
|
snapshot_tree,
|
|
|
|
result.as_ref(),
|
|
|
|
commit_oid,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
result
|
2024-04-29 16:03:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn insert_blank_commit(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-04-29 16:03:01 +03:00
|
|
|
offset: i32,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-04-29 16:03:01 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::InsertBlankCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::insert_blank_commit(&project_repository, branch_id, commit_oid, offset)
|
2024-07-04 18:12:20 +03:00
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reorder_commit(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-04-29 16:03:01 +03:00
|
|
|
offset: i32,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-04-29 16:03:01 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::ReorderCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::reorder_commit(&project_repository, branch_id, commit_oid, offset)
|
2024-07-04 18:12:20 +03:00
|
|
|
.map_err(Into::into)
|
2024-04-29 16:03:01 +03:00
|
|
|
}
|
|
|
|
|
2024-03-29 12:04:26 +03:00
|
|
|
pub async fn reset_virtual_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
target_commit_oid: git2::Oid,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UndoCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::reset_branch(&project_repository, branch_id, target_commit_oid).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-01 17:13:52 +03:00
|
|
|
pub async fn convert_to_real_branch(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-07-07 16:51:07 +03:00
|
|
|
name_conflict_resolution: branch::NameConflitResolution,
|
2024-07-01 17:13:52 +03:00
|
|
|
) -> Result<ReferenceName> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let snapshot_tree = project_repository.project().prepare_snapshot();
|
2024-07-07 16:51:07 +03:00
|
|
|
let result = branch::convert_to_real_branch(
|
2024-07-07 14:32:35 +03:00
|
|
|
&project_repository,
|
|
|
|
branch_id,
|
|
|
|
name_conflict_resolution,
|
|
|
|
)
|
|
|
|
.map_err(Into::into);
|
2024-07-04 18:12:20 +03:00
|
|
|
let _ = snapshot_tree.and_then(|snapshot_tree| {
|
|
|
|
project_repository
|
|
|
|
.project()
|
|
|
|
.snapshot_branch_unapplied(snapshot_tree, result.as_ref())
|
|
|
|
});
|
|
|
|
result.and_then(|b| b.reference_name())
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn push_virtual_branch(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-03-29 12:04:26 +03:00
|
|
|
with_force: bool,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<Option<BranchId>>,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-07-06 18:03:46 +03:00
|
|
|
let helper = Helper::default();
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::push(&project_repository, branch_id, with_force, &helper, askpass)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-07 21:48:12 +03:00
|
|
|
pub async fn list_remote_branches(&self, project: Project) -> Result<Vec<RemoteBranch>> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(&project)?;
|
2024-07-07 21:48:12 +03:00
|
|
|
list_remote_branches(&project_repository)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-04 13:21:22 +03:00
|
|
|
pub async fn get_remote_branch_data(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-03-29 12:04:26 +03:00
|
|
|
refname: &git::Refname,
|
2024-07-07 21:48:12 +03:00
|
|
|
) -> Result<RemoteBranchData> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 21:48:12 +03:00
|
|
|
get_branch_data(&project_repository, refname)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn squash(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::SquashCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::squash(&project_repository, branch_id, commit_oid).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn update_commit_message(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-03-29 12:04:26 +03:00
|
|
|
message: &str,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::UpdateCommitMessage));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::update_commit_message(&project_repository, branch_id, commit_oid, message)
|
2024-07-04 18:12:20 +03:00
|
|
|
.map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-05-28 11:14:35 +03:00
|
|
|
pub async fn fetch_from_remotes(
|
2024-03-29 12:04:26 +03:00
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-07 17:07:37 +03:00
|
|
|
askpass: Option<String>,
|
2024-07-04 17:34:53 +03:00
|
|
|
) -> Result<FetchResult> {
|
2024-07-07 23:09:45 +03:00
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-06 18:03:46 +03:00
|
|
|
let helper = Helper::default();
|
2024-07-08 00:37:15 +03:00
|
|
|
let remotes = project_repository.repo().remotes_as_string()?;
|
2024-05-31 17:11:37 +03:00
|
|
|
let fetch_results: Vec<Result<(), _>> = remotes
|
2024-05-24 15:58:56 +03:00
|
|
|
.iter()
|
2024-07-06 18:03:46 +03:00
|
|
|
.map(|remote| project_repository.fetch(remote, &helper, askpass.clone()))
|
2024-05-24 15:58:56 +03:00
|
|
|
.collect();
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-05-24 15:58:56 +03:00
|
|
|
let project_data_last_fetched = if fetch_results.iter().any(Result::is_err) {
|
|
|
|
projects::FetchResult::Error {
|
2024-05-24 11:40:52 +03:00
|
|
|
timestamp: std::time::SystemTime::now(),
|
2024-05-24 15:58:56 +03:00
|
|
|
error: fetch_results
|
|
|
|
.iter()
|
|
|
|
.filter_map(|result| match result {
|
|
|
|
Ok(_) => None,
|
|
|
|
Err(error) => Some(error.to_string()),
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n"),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
projects::FetchResult::Fetched {
|
2024-05-24 11:40:52 +03:00
|
|
|
timestamp: std::time::SystemTime::now(),
|
2024-05-24 15:58:56 +03:00
|
|
|
}
|
2024-03-29 12:04:26 +03:00
|
|
|
};
|
|
|
|
|
2024-05-24 15:58:56 +03:00
|
|
|
let default_target = default_target(&project_repository.project().gb_dir())?;
|
|
|
|
|
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 {
|
2024-07-06 18:03:46 +03:00
|
|
|
if let Err(err) = project_repository.fetch(push_remote, &helper, askpass.clone()) {
|
2024-05-31 17:11:37 +03:00
|
|
|
tracing::warn!(?err, "fetch from push-remote failed");
|
|
|
|
}
|
2024-05-06 17:01:06 +03:00
|
|
|
}
|
2024-07-04 17:34:53 +03:00
|
|
|
Ok(project_data_last_fetched)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn move_commit(
|
|
|
|
&self,
|
2024-07-04 16:26:10 +03:00
|
|
|
project: &Project,
|
2024-05-29 12:07:36 +03:00
|
|
|
target_branch_id: BranchId,
|
2024-06-05 23:56:03 +03:00
|
|
|
commit_oid: git2::Oid,
|
2024-05-31 20:34:04 +03:00
|
|
|
) -> Result<()> {
|
2024-07-06 19:57:58 +03:00
|
|
|
self.permit(project.ignore_project_semaphore).await;
|
2024-03-29 12:04:26 +03:00
|
|
|
|
2024-07-04 18:12:20 +03:00
|
|
|
let project_repository = open_with_verify(project)?;
|
|
|
|
let _ = project_repository
|
|
|
|
.project()
|
|
|
|
.create_snapshot(SnapshotDetails::new(OperationKind::MoveCommit));
|
2024-07-07 16:51:07 +03:00
|
|
|
branch::move_commit(&project_repository, target_branch_id, commit_oid).map_err(Into::into)
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
2024-07-06 19:57:58 +03:00
|
|
|
|
|
|
|
async fn permit(&self, ignore: bool) {
|
|
|
|
if !ignore {
|
|
|
|
let _permit = self.semaphore.acquire().await;
|
|
|
|
}
|
|
|
|
}
|
2024-03-29 12:04:26 +03:00
|
|
|
}
|
|
|
|
|
2024-07-07 23:09:45 +03:00
|
|
|
fn open_with_verify(project: &Project) -> Result<ProjectRepo> {
|
|
|
|
let project_repository = ProjectRepo::open(project)?;
|
2024-07-07 18:30:18 +03:00
|
|
|
crate::integration::verify_branch(&project_repository)?;
|
2024-07-04 18:12:20 +03:00
|
|
|
Ok(project_repository)
|
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
|
|
|
}
|