Skip to content

Commit 323d19d

Browse files
committed
Provide a non-legacy version of branch apply
While at it, make it clearer from dependencies what's legacy and what not, similar to the `but` (CLI) crate.
1 parent 4abed5d commit 323d19d

File tree

9 files changed

+133
-21
lines changed

9 files changed

+133
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-api/Cargo.toml

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@ tauri = ["dep:tauri"]
2222
path-bytes = ["dep:bstr"]
2323
## Make legacy functionality available.
2424
legacy = [
25+
"but-ctx/legacy",
26+
"but-workspace/legacy",
2527
"dep:gitbutler-user",
2628
"dep:gitbutler-project",
2729
"dep:gitbutler-branch",
2830
"dep:gitbutler-branch-actions",
2931
"dep:gitbutler-commit",
30-
"dep:but-ctx",
3132
"dep:gitbutler-reference",
3233
"dep:gitbutler-stack",
3334
"dep:gitbutler-repo",
@@ -36,35 +37,50 @@ legacy = [
3637
"dep:gitbutler-operating-modes",
3738
"dep:gitbutler-sync",
3839
"dep:gitbutler-oplog",
40+
"dep:but-action",
41+
"dep:but-hunk-assignment",
42+
"dep:but-hunk-dependency",
43+
"dep:but-claude",
44+
"dep:but-rules",
45+
"dep:but-gerrit",
46+
"dep:but-worktrees",
3947
]
4048

4149

4250
[dependencies]
51+
but-serde.workspace = true
52+
but-path.workspace = true
53+
but-api-macros.workspace = true
54+
but-oxidize.workspace = true
55+
but-error.workspace = true
56+
but-core.workspace = true
57+
but-graph.workspace = true
58+
but-ctx.workspace = true
59+
but-workspace.workspace = true
4360
but-settings.workspace = true
44-
but-github = { workspace = true, features = ["legacy"] }
4561
but-secret.workspace = true
46-
but-workspace = { workspace = true, features = ["legacy"] }
47-
but-worktrees.workspace = true
48-
but-core.workspace = true
49-
but-gerrit.workspace = true
50-
but-hunk-assignment.workspace = true
51-
but-action.workspace = true
52-
but-api-macros.workspace = true
5362
but-rebase.workspace = true
54-
but-serde.workspace = true
55-
but-graph.workspace = true
56-
but-meta = { workspace = true, features = ["legacy"] }
57-
but-claude.workspace = true
5863
but-cherry-apply.workspace = true
59-
but-hunk-dependency.workspace = true
60-
but-path.workspace = true
61-
but-forge-storage.workspace = true
62-
but-error.workspace = true
6364
but-db.workspace = true
64-
but-rules.workspace = true
65-
but-oxidize.workspace = true
6665
but-forge.workspace = true
67-
but-ctx = {workspace = true, optional = true}
66+
but-forge-storage.workspace = true
67+
# needs `gitbutler_user::User`, which can probably be ported over.
68+
but-github = { workspace = true, features = ["legacy"] }
69+
# 'legacy' is needed while we only have `virtual-branches.toml`
70+
but-meta = { workspace = true, features = ["legacy"] }
71+
# 'legacy' is needed while this is only a sketch of what the oplog could be.
72+
# For single-branch testing, we also want the oplog and just take it as it is.
73+
but-oplog = { workspace = true, features = ["legacy"] }
74+
75+
# What follows is *basically* newly written crates that are built on top of legacy,
76+
# so need some refactoring/rethinking to become usable.
77+
but-action = { workspace = true, optional = true }
78+
but-hunk-assignment = { workspace = true, optional = true }
79+
but-hunk-dependency = { workspace = true, optional = true }
80+
but-claude = { workspace = true, optional = true }
81+
but-rules = { workspace = true, optional = true }
82+
but-gerrit = { workspace = true, optional = true }
83+
but-worktrees = { workspace = true, optional = true }
6884

6985
gitbutler-user = {workspace = true, optional = true}
7086
gitbutler-project = {workspace = true, optional = true}

crates/but-api/src/branch.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use but_core::worktree::checkout::UncommitedWorktreeChanges;
2+
use but_oplog::legacy::{OperationKind, SnapshotDetails, Trailer};
3+
use but_workspace::branch::OnWorkspaceMergeConflict;
4+
use but_workspace::branch::apply::{WorkspaceMerge, WorkspaceReferenceNaming};
5+
6+
/// Just like [apply_without_oplog()] but runs application-specific side effects, typically undo-queue and oplog settings.
7+
pub fn apply_without_oplog(
8+
ctx: &but_ctx::Context,
9+
existing_branch: &gix::refs::FullNameRef,
10+
) -> anyhow::Result<but_workspace::branch::apply::Outcome<'static>> {
11+
let mut guard = ctx.exclusive_worktree_access();
12+
let (repo, mut meta, graph) =
13+
ctx.graph_and_meta_mut_and_repo_from_head(guard.write_permission())?;
14+
let ws = graph.to_workspace()?;
15+
let out = but_workspace::branch::apply(
16+
existing_branch,
17+
&ws,
18+
&repo,
19+
&mut meta,
20+
// NOTE: Options can later be passed as parameter, or we have a separate function for that.
21+
// Showing them off here while leaving defaults.
22+
but_workspace::branch::apply::Options {
23+
workspace_merge: WorkspaceMerge::default(),
24+
on_workspace_conflict: OnWorkspaceMergeConflict::default(),
25+
workspace_reference_naming: WorkspaceReferenceNaming::default(),
26+
uncommitted_changes: UncommitedWorktreeChanges::default(),
27+
order: None,
28+
new_stack_id: None,
29+
},
30+
)?
31+
.into_owned();
32+
Ok(out)
33+
}
34+
35+
/// Apply `existing_branch` to the workspace in the repository that `ctx` refers to, or create the workspace with default name.
36+
// TODO: generate this with an improved `api_cmd_tauri` macro.
37+
pub fn apply(
38+
ctx: &but_ctx::Context,
39+
existing_branch: &gix::refs::FullNameRef,
40+
) -> anyhow::Result<but_workspace::branch::apply::Outcome<'static>> {
41+
// NOTE: since this is optional by nature, the same would be true if snapshotting/undo would be disabled via `ctx` app settings, for instance.
42+
let maybe_oplog_entry = but_oplog::UnmaterializedOplogSnapshot::from_details(
43+
ctx,
44+
SnapshotDetails::new(OperationKind::CreateBranch).with_trailers(vec![Trailer {
45+
key: "name".into(),
46+
value: existing_branch.to_string(),
47+
}]),
48+
)
49+
.ok();
50+
51+
let res = apply_without_oplog(ctx, existing_branch);
52+
if let Some(snapshot) = maybe_oplog_entry.filter(|_| res.is_ok()) {
53+
snapshot.commit(ctx).ok();
54+
}
55+
res
56+
}

crates/but-api/src/github.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//! In place of commands.rs
1+
// TODO: everything should be fully documented.
2+
#![allow(missing_docs)]
23
use anyhow::Result;
34
use but_api_macros::api_cmd_tauri;
45
use but_github::{AuthStatusResponse, AuthenticatedUser, Verification};

crates/but-api/src/json.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! JSON types and utilities to produce decent JSON from API types.
12
pub use error::{Error, ToJsonError, UnmarkedError};
23
use gix::refs::Target;
34
use schemars::{self, JsonSchema};
@@ -195,7 +196,9 @@ mod error {
195196
}
196197
}
197198

199+
/// A utility to convert any `Result<T, impl std::error::Error>` into a [JSON-Error](Error).
198200
pub trait ToJsonError<T> {
201+
/// Convert this instance into a Result<T, [JSON-Error](Error)>.
199202
fn to_json_error(self) -> Result<T, Error>;
200203
}
201204

crates/but-api/src/legacy/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(missing_docs)]
12
//! Legacy data structures and functionality tied to `gitbutler-*` crates.
23
//!
34
pub mod askpass;

crates/but-api/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
//! on this level.
77
//! Lower-level crates like `but-workspace` won't use filesystem-based locking beyond what Git offers natively.
88
#![forbid(unsafe_code)]
9+
#![deny(missing_docs)]
910

1011
#[cfg(feature = "legacy")]
1112
pub mod legacy;
1213

1314
pub mod github;
1415

16+
/// Functions that take a branch as input.
17+
pub mod branch;
18+
1519
/// Types meant to be serialised to JSON, without degenerating information despite the need to be UTF-8 encodable.
1620
/// EXPERIMENTAL
1721
pub mod json;

crates/but-oplog/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
//! with the restore point.
5252
//!
5353
//! Non-legacy commands can use the [`UnmaterializedOplogSnapshot`] utility to insert the snapshot into the log on successful effects.
54+
#![forbid(unsafe_code, missing_docs)]
5455

5556
/// This is just a sketch for an in-memory snapshot that isn't observable through the on-disk repository.
5657
/// It will be committed only if the main effect of a function was successfully applied.
@@ -61,10 +62,17 @@ pub struct UnmaterializedOplogSnapshot {
6162
/// The tree containing all snapshot information.
6263
#[cfg(feature = "legacy")]
6364
tree_id: gix::ObjectId,
65+
/// Details to pass when committing the snapshot.
6466
#[cfg(feature = "legacy")]
6567
details: gitbutler_oplog::entry::SnapshotDetails,
6668
}
6769

70+
/// legacy types for easy of use, all provided by `gitbutler-oplog`.
71+
#[cfg(feature = "legacy")]
72+
pub mod legacy {
73+
pub use gitbutler_oplog::entry::{OperationKind, SnapshotDetails, Trailer};
74+
}
75+
6876
#[cfg(feature = "legacy")]
6977
mod oplog_snapshot {
7078
use crate::UnmaterializedOplogSnapshot;

crates/but-workspace/src/branch/apply.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ impl Outcome<'_> {
3232
}
3333
}
3434

35+
impl<'a> Outcome<'a> {
36+
/// Convert this instance into a fully-owned one.
37+
pub fn into_owned(self) -> Outcome<'static> {
38+
let Outcome {
39+
graph,
40+
applied_branches,
41+
workspace_ref_created,
42+
workspace_merge,
43+
conflicting_stack_ids,
44+
} = self;
45+
46+
Outcome {
47+
graph: Cow::Owned(graph.into_owned()),
48+
applied_branches,
49+
workspace_ref_created,
50+
workspace_merge,
51+
conflicting_stack_ids,
52+
}
53+
}
54+
}
55+
3556
impl std::fmt::Debug for Outcome<'_> {
3657
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3758
let Outcome {
@@ -137,6 +158,7 @@ pub(crate) mod function {
137158

138159
/// Apply `branch` to the given `workspace`, and possibly create the workspace reference in `repo`
139160
/// along with its `meta`-data if it doesn't exist yet.
161+
/// The changed workspace will be checked out.
140162
/// If `branch` is a remote tracking branch, we will instead apply the local tracking branch if it exists or fail otherwise.
141163
/// Otherwise, add it to the existing `workspace`, and update its metadata accordingly.
142164
/// **This means that the contents of `branch` is observable from the new state of `repo`**.

0 commit comments

Comments
 (0)