Merge pull request #4262 from gitbutlerapp/feature-add-virtual-branches-access-trait

Move branch state to a separate crate
This commit is contained in:
Kiril Videlov 2024-07-07 21:48:38 +02:00 committed by GitHub
commit b72e3de178
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 99 additions and 131 deletions

View File

@ -22,6 +22,7 @@ jobs:
gitbutler-branch: ${{ steps.filter.outputs.gitbutler-branch }}
gitbutler-sync: ${{ steps.filter.outputs.gitbutler-sync }}
gitbutler-oplog: ${{ steps.filter.outputs.gitbutler-oplog }}
gitbutler-branchstate: ${{ steps.filter.outputs.gitbutler-branchstate }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
@ -67,6 +68,9 @@ jobs:
gitbutler-oplog:
- *rust
- 'crates/gitbutler-oplog/**'
gitbutler-branchstate:
- *rust
- 'crates/gitbutler-branchstate/**'
lint-node:
needs: changes
@ -266,6 +270,30 @@ jobs:
features: ${{ toJson(matrix.features) }}
action: ${{ matrix.action }}
check-gitbutler-branchstate:
needs: changes
if: ${{ needs.changes.outputs.gitbutler-branchstate == 'true' }}
runs-on: ubuntu-latest
container:
image: ghcr.io/gitbutlerapp/ci-base-image:latest
strategy:
matrix:
action:
- test
- check
features:
- ''
- '*'
- []
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/init-env-rust
- uses: ./.github/actions/check-crate
with:
crate: gitbutler-branchstate
features: ${{ toJson(matrix.features) }}
action: ${{ matrix.action }}
check-gitbutler-cli:
needs: changes
if: ${{ needs.changes.outputs.gitbutler-cli == 'true' }}
@ -325,6 +353,7 @@ jobs:
- check-gitbutler-branch
- check-gitbutler-sync
- check-gitbutler-oplog
- check-gitbutler-branchstate
- check-gitbutler-git
- check-gitbutler-cli
- check-gitbutler-watcher

15
Cargo.lock generated
View File

@ -2112,6 +2112,7 @@ dependencies = [
"futures",
"git2",
"git2-hooks",
"gitbutler-branchstate",
"gitbutler-core",
"gitbutler-git",
"gitbutler-oplog",
@ -2131,6 +2132,17 @@ dependencies = [
"url",
]
[[package]]
name = "gitbutler-branchstate"
version = "0.0.0"
dependencies = [
"anyhow",
"gitbutler-core",
"itertools 0.13.0",
"serde",
"toml 0.8.14",
]
[[package]]
name = "gitbutler-cli"
version = "0.0.0"
@ -2234,6 +2246,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"git2",
"gitbutler-branchstate",
"gitbutler-core",
"gix",
"itertools 0.13.0",
@ -2251,6 +2264,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"git2",
"gitbutler-branchstate",
"gitbutler-core",
"gitbutler-oplog",
"itertools 0.13.0",
@ -2303,6 +2317,7 @@ dependencies = [
"anyhow",
"git2",
"gitbutler-branch",
"gitbutler-branchstate",
"gitbutler-core",
"keyring",
"once_cell",

View File

@ -9,7 +9,8 @@ members = [
"crates/gitbutler-cli",
"crates/gitbutler-branch",
"crates/gitbutler-sync",
"crates/gitbutler-oplog",
"crates/gitbutler-oplog",
"crates/gitbutler-branchstate",
]
resolver = "2"
@ -31,6 +32,7 @@ gitbutler-cli ={ path = "crates/gitbutler-cli" }
gitbutler-branch = { path = "crates/gitbutler-branch" }
gitbutler-sync = { path = "crates/gitbutler-sync" }
gitbutler-oplog = { path = "crates/gitbutler-oplog" }
gitbutler-branchstate = { path = "crates/gitbutler-branchstate" }
[profile.release]
codegen-units = 1 # Compile crates one after another so the compiler can optimize better

View File

@ -12,6 +12,7 @@ git2.workspace = true
tokio.workspace = true
gitbutler-core.workspace = true
gitbutler-oplog.workspace = true
gitbutler-branchstate.workspace = true
serde = { workspace = true, features = ["std"]}
bstr = "1.9.1"
diffy = "0.3.0"

View File

@ -2,6 +2,7 @@ use std::{path::Path, time};
use anyhow::{anyhow, Context, Result};
use git2::Index;
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesHandle};
use serde::Serialize;
use super::r#virtual as vb;
@ -9,9 +10,7 @@ use super::r#virtual::convert_to_real_branch;
use crate::integration::{get_workspace_head, update_gitbutler_integration};
use crate::remote::{commit_to_remote_commit, RemoteCommit};
use crate::VirtualBranchHunk;
use gitbutler_core::virtual_branches::{
branch, target, BranchId, VirtualBranchesHandle, GITBUTLER_INTEGRATION_REFERENCE,
};
use gitbutler_core::virtual_branches::{branch, target, BranchId, GITBUTLER_INTEGRATION_REFERENCE};
use gitbutler_core::{error::Marker, git::RepositoryExt, rebase::cherry_rebase};
use gitbutler_core::{
git::{self, diff},

View File

@ -1,4 +1,5 @@
use anyhow::Result;
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesHandle};
use gitbutler_core::{
git::{credentials::Helper, BranchExt},
project_repository::Repository,
@ -28,7 +29,7 @@ use gitbutler_core::virtual_branches;
use crate::files::RemoteBranchFile;
use gitbutler_core::virtual_branches::{
branch::{BranchId, BranchOwnershipClaims},
target, VirtualBranchesHandle,
target,
};
use gitbutler_core::{
git,

View File

@ -3,11 +3,12 @@ use std::{path::PathBuf, vec};
use anyhow::{anyhow, bail, Context, Result};
use bstr::ByteSlice;
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesHandle};
use gitbutler_core::error::Marker;
use gitbutler_core::git::RepositoryExt;
use gitbutler_core::virtual_branches::{
VirtualBranchesHandle, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL,
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME, GITBUTLER_INTEGRATION_REFERENCE,
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
GITBUTLER_INTEGRATION_REFERENCE,
};
use gitbutler_core::{
git::CommitExt,

View File

@ -2,9 +2,10 @@ use std::path::Path;
use anyhow::{Context, Result};
use bstr::BString;
use gitbutler_branchstate::VirtualBranchesHandle;
use serde::Serialize;
use gitbutler_core::virtual_branches::{target, Author, VirtualBranchesHandle};
use gitbutler_core::virtual_branches::{target, Author};
use gitbutler_core::{
git::{self, CommitExt, RepositoryExt},
project_repository::{self, LogUntil},

View File

@ -1,3 +1,4 @@
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesHandle};
use gitbutler_oplog::snapshot::Snapshot;
use std::borrow::Borrow;
#[cfg(target_family = "unix")]
@ -35,7 +36,7 @@ use gitbutler_core::virtual_branches::{
branch::{
self, Branch, BranchCreateRequest, BranchId, BranchOwnershipClaims, Hunk, OwnershipClaim,
},
target, VirtualBranchesHandle,
target,
};
use gitbutler_core::{
dedup::{dedup, dedup_fmt},

View File

@ -17,6 +17,7 @@ use gitbutler_branch::r#virtual::{
commit, create_virtual_branch, create_virtual_branch_from_branch, integrate_upstream_commits,
is_remote_branch_mergeable, list_virtual_branches, unapply_ownership, update_branch,
};
use gitbutler_branchstate::VirtualBranchesAccess;
use gitbutler_core::{
git::{self, CommitExt, RepositoryExt},
virtual_branches::branch::{BranchCreateRequest, BranchOwnershipClaims, BranchUpdateRequest},

View File

@ -1,4 +1,5 @@
use super::*;
use gitbutler_branchstate::VirtualBranchesAccess;
use gitbutler_oplog::oplog::Oplog;
use itertools::Itertools;
use std::io::Write;

View File

@ -0,0 +1,13 @@
[package]
name = "gitbutler-branchstate"
version = "0.0.0"
edition = "2021"
authors = ["GitButler <gitbutler@gitbutler.com>"]
publish = false
[dependencies]
gitbutler-core.workspace = true
itertools = "0.13"
anyhow = "1.0.86"
toml = "0.8.13"
serde = { workspace = true, features = ["std"]}

View File

@ -0,0 +1,4 @@
mod state;
pub use state::VirtualBranches as VirtualBranchesState;
pub use state::VirtualBranchesAccess;
pub use state::VirtualBranchesHandle;

View File

@ -3,13 +3,12 @@ use std::{
path::{Path, PathBuf},
};
use crate::{error::Code, fs::read_toml_file_or_default};
use anyhow::{anyhow, Result};
use gitbutler_core::{error::Code, fs::read_toml_file_or_default, projects::Project};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use super::{target::Target, Branch};
use crate::virtual_branches::BranchId;
use gitbutler_core::virtual_branches::{target::Target, Branch, BranchId};
/// The state of virtual branches data, as persisted in a TOML file.
#[derive(Serialize, Deserialize, Debug, Default)]
@ -29,6 +28,16 @@ pub struct VirtualBranchesHandle {
file_path: PathBuf,
}
pub trait VirtualBranchesAccess {
fn virtual_branches(&self) -> VirtualBranchesHandle;
}
impl VirtualBranchesAccess for Project {
fn virtual_branches(&self) -> VirtualBranchesHandle {
VirtualBranchesHandle::new(self.gb_dir())
}
}
impl VirtualBranchesHandle {
/// Creates a new concurrency-safe handle to the state of virtual branches.
pub fn new<P: AsRef<Path>>(base_path: P) -> Self {
@ -162,5 +171,5 @@ impl VirtualBranchesHandle {
}
fn write<P: AsRef<Path>>(file_path: P, virtual_branches: &VirtualBranches) -> Result<()> {
crate::fs::write(file_path, toml::to_string(&virtual_branches)?)
gitbutler_core::fs::write(file_path, toml::to_string(&virtual_branches)?)
}

View File

@ -5,7 +5,7 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{id::Id, types::default_true::DefaultTrue, virtual_branches::VirtualBranchesHandle};
use crate::{id::Id, types::default_true::DefaultTrue};
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
@ -117,11 +117,6 @@ impl Project {
self.path.join(".git").join("gitbutler")
}
/// Returns a handle to the virtual branches manager of the project.
pub fn virtual_branches(&self) -> VirtualBranchesHandle {
VirtualBranchesHandle::new(self.gb_dir())
}
pub fn snapshot_lines_threshold(&self) -> usize {
self.snapshot_lines_threshold.unwrap_or(20)
}

View File

@ -2,10 +2,6 @@ pub mod branch;
pub use branch::{Branch, BranchId};
pub mod target;
mod state;
pub use state::VirtualBranches as VirtualBranchesState;
pub use state::VirtualBranchesHandle;
mod author;
pub use author::Author;

View File

@ -1,105 +0,0 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use anyhow::Result;
use gitbutler_core::virtual_branches;
use once_cell::sync::Lazy;
use gitbutler_testsupport::{Case, Suite};
static TEST_INDEX: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
fn new_test_branch() -> virtual_branches::branch::Branch {
TEST_INDEX.fetch_add(1, Ordering::Relaxed);
virtual_branches::branch::Branch {
id: virtual_branches::BranchId::generate(),
name: format!("branch_name_{}", TEST_INDEX.load(Ordering::Relaxed)),
notes: String::new(),
applied: true,
upstream: Some(
format!(
"refs/remotes/origin/upstream_{}",
TEST_INDEX.load(Ordering::Relaxed)
)
.parse()
.unwrap(),
),
upstream_head: None,
created_timestamp_ms: TEST_INDEX.load(Ordering::Relaxed) as u128,
updated_timestamp_ms: (TEST_INDEX.load(Ordering::Relaxed) + 100) as u128,
head: format!(
"0123456789abcdef0123456789abcdef0123456{}",
TEST_INDEX.load(Ordering::Relaxed)
)
.parse()
.unwrap(),
tree: format!(
"0123456789abcdef0123456789abcdef012345{}",
TEST_INDEX.load(Ordering::Relaxed) + 10
)
.parse()
.unwrap(),
ownership: virtual_branches::branch::BranchOwnershipClaims::default(),
order: TEST_INDEX.load(Ordering::Relaxed),
selected_for_changes: Some(1),
allow_rebasing: true,
}
}
static TEST_TARGET_INDEX: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
fn new_test_target() -> virtual_branches::target::Target {
virtual_branches::target::Target {
branch: format!(
"refs/remotes/branch name{}/remote name {}",
TEST_TARGET_INDEX.load(Ordering::Relaxed),
TEST_TARGET_INDEX.load(Ordering::Relaxed)
)
.parse()
.unwrap(),
remote_url: format!("remote url {}", TEST_TARGET_INDEX.load(Ordering::Relaxed)),
sha: format!(
"0123456789abcdef0123456789abcdef0123456{}",
TEST_TARGET_INDEX.load(Ordering::Relaxed)
)
.parse()
.unwrap(),
push_remote_name: None,
}
}
#[test]
fn empty_iterator() -> Result<()> {
let suite = Suite::default();
let Case { project, .. } = &suite.new_case();
let vb_state = project.virtual_branches();
let iter = vb_state.list_branches()?;
assert_eq!(iter.len(), 0);
Ok(())
}
#[test]
fn iterate_all() -> Result<()> {
let suite = Suite::default();
let Case { project, .. } = &suite.new_case();
let vb_state = project.virtual_branches();
vb_state.set_default_target(new_test_target())?;
let branch_1 = new_test_branch();
vb_state.set_branch(branch_1.clone())?;
let branch_2 = new_test_branch();
vb_state.set_branch(branch_2.clone())?;
let branch_3 = new_test_branch();
vb_state.set_branch(branch_3.clone())?;
let iter = vb_state.list_branches()?;
assert_eq!(iter.len(), 3);
assert!(iter.contains(&branch_1));
assert!(iter.contains(&branch_2));
assert!(iter.contains(&branch_3));
Ok(())
}

View File

@ -1,2 +1 @@
mod branch;
mod iterator;

View File

@ -9,6 +9,7 @@ publish = false
anyhow = "1.0.86"
git2.workspace = true
gitbutler-core.workspace = true
gitbutler-branchstate.workspace = true
serde = { workspace = true, features = ["std"]}
itertools = "0.13"
strum = { version = "0.26", features = ["derive"] }

View File

@ -1,5 +1,6 @@
use anyhow::{anyhow, bail, Context};
use git2::{DiffOptions, FileMode};
use gitbutler_branchstate::{VirtualBranchesAccess, VirtualBranchesState};
use std::collections::HashMap;
use std::path::Path;
use std::str::{from_utf8, FromStr};
@ -807,8 +808,7 @@ fn tree_from_applied_vbranches(
.find_blob(vb_toml_entry.id())
.context("failed to convert virtual_branches tree entry to blob")?;
let vbs_from_toml: gitbutler_core::virtual_branches::VirtualBranchesState =
toml::from_str(from_utf8(vb_toml_blob.content())?)?;
let vbs_from_toml: VirtualBranchesState = toml::from_str(from_utf8(vb_toml_blob.content())?)?;
let applied_branch_trees: Vec<git2::Oid> = vbs_from_toml
.branches
.values()

View File

@ -12,3 +12,4 @@ itertools = "0.13"
git2.workspace = true
gitbutler-core.workspace = true
gitbutler-oplog.workspace = true
gitbutler-branchstate.workspace = true

View File

@ -1,6 +1,7 @@
use std::time;
use anyhow::{Context, Result};
use gitbutler_branchstate::VirtualBranchesAccess;
use gitbutler_core::id::Id;
use gitbutler_core::{
git::{self},

View File

@ -19,3 +19,4 @@ keyring.workspace = true
serde_json = "1.0"
gitbutler-core = { path = "../gitbutler-core" }
gitbutler-branch = { path = "../gitbutler-branch" }
gitbutler-branchstate = { path = "../gitbutler-branchstate" }

View File

@ -18,6 +18,7 @@ pub mod paths {
}
pub mod virtual_branches {
use gitbutler_branchstate::VirtualBranchesAccess;
use gitbutler_core::{project_repository, virtual_branches};
use crate::empty_bare_repository;