Skip to content

Commit

Permalink
Merge branch 'master' into ndom91/macos-e2e-docker-image
Browse files Browse the repository at this point in the history
  • Loading branch information
ndom91 authored Aug 13, 2024
2 parents 310aaf8 + 796f8fe commit 4f6748b
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Setup rust-toolchain stable
id: rust-toolchain
uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
Expand Down
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ resolver = "2"
[workspace.dependencies]
bstr = "1.10.0"
# Add the `tracing` or `tracing-detail` features to see more of gitoxide in the logs. Useful to see which programs it invokes.
gix = { git = "https://github.com/Byron/gitoxide", rev = "d51f330e9d364c6f7b068116b59bf5c0160e47af", default-features = false, features = [] }
gix = { git = "https://github.com/Byron/gitoxide", rev = "d51f330e9d364c6f7b068116b59bf5c0160e47af", default-features = false, features = [
] }
git2 = { version = "0.18.3", features = [
"vendored-openssl",
"vendored-libgit2",
Expand All @@ -49,6 +50,7 @@ anyhow = "1.0.86"
fslock = "0.2.1"
parking_lot = "0.12.3"
futures = "0.3.30"
toml = "0.8.13"

gitbutler-id = { path = "crates/gitbutler-id" }
gitbutler-git = { path = "crates/gitbutler-git" }
Expand Down
2 changes: 1 addition & 1 deletion crates/gitbutler-branch/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ gitbutler-error.workspace = true
gitbutler-fs.workspace = true
gitbutler-diff.workspace = true
itertools = "0.13"
toml = "0.8.15"
toml.workspace = true
serde = { workspace = true, features = ["std"] }
bstr.workspace = true
md5 = "0.7.0"
Expand Down
4 changes: 2 additions & 2 deletions crates/gitbutler-fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ authors = ["GitButler <gitbutler@gitbutler.com>"]
publish = false

[dependencies]
serde = { workspace = true, features = ["std"]}
serde = { workspace = true, features = ["std"] }
bstr.workspace = true
anyhow = "1.0.86"
gix = { workspace = true, features = ["dirwalk", "credentials", "parallel"] }
walkdir = "2.5.0"
toml = "0.8.15"
toml.workspace = true
5 changes: 5 additions & 0 deletions crates/gitbutler-operating-modes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ publish = false

[dependencies]
serde = { workspace = true, features = ["std"] }
tracing = "0.1.40"
git2.workspace = true
anyhow.workspace = true
toml.workspace = true
gitbutler-command-context.workspace = true
gitbutler-serde.workspace = true
gitbutler-fs.workspace = true
gitbutler-reference.workspace = true

[dev-dependencies]
gitbutler-testsupport.workspace = true
119 changes: 102 additions & 17 deletions crates/gitbutler-operating-modes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,123 @@
use std::{fs, path::PathBuf};

use anyhow::{bail, Context, Result};
use gitbutler_command_context::CommandContext;
use gitbutler_reference::ReferenceName;
use serde::{Deserialize, Serialize};

/// The reference the app will checkout when the workspace is open
pub const INTEGRATION_BRANCH_REF: &str = "refs/heads/gitbutler/integration";
/// The reference the app will checkout when in edit mode
pub const EDIT_BRANCH_REF: &str = "refs/heads/gitbutler/edit";

fn edit_mode_metadata_path(ctx: &CommandContext) -> PathBuf {
ctx.project().gb_dir().join("edit_mode_metadata.toml")
}

#[doc(hidden)]
pub fn read_edit_mode_metadata(ctx: &CommandContext) -> Result<EditModeMetadata> {
let edit_mode_metadata = fs::read_to_string(edit_mode_metadata_path(ctx).as_path())
.context("Failed to read edit mode metadata")?;

toml::from_str(&edit_mode_metadata).context("Failed to parse edit mode metadata")
}

/// Operating Modes:
/// Gitbutler currently has two main operating modes:
/// - `in workspace mode`: When the app is on the gitbutler/integration branch.
/// This is when normal operations can be performed.
/// - `outside workspace mode`: When the user has left the gitbutler/integration
/// branch to perform regular git commands.
#[doc(hidden)]
pub fn write_edit_mode_metadata(
ctx: &CommandContext,
edit_mode_metadata: &EditModeMetadata,
) -> Result<()> {
let serialized_edit_mode_metadata =
toml::to_string(edit_mode_metadata).context("Failed to serialize edit mode metadata")?;
gitbutler_fs::write(
edit_mode_metadata_path(ctx).as_path(),
serialized_edit_mode_metadata,
)
.context("Failed to write edit mode metadata")?;

const INTEGRATION_BRANCH_REF: &str = "refs/heads/gitbutler/integration";
Ok(())
}

pub fn in_open_workspace_mode(ctx: &CommandContext) -> Result<bool> {
let head_ref = ctx.repository().head().context("failed to get head")?;
let head_ref_name = head_ref.name().context("failed to get head name")?;
/// Holds relevant state required to switch to and from edit mode
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct EditModeMetadata {
/// The sha of the commit getting edited.
#[serde(with = "gitbutler_serde::oid")]
pub editee_commit_sha: git2::Oid,
/// The ref of the vbranch which owns this commit.
pub editee_branch: ReferenceName,
}

Ok(head_ref_name == INTEGRATION_BRANCH_REF)
#[derive(PartialEq)]
pub enum OperatingMode {
/// The typical app state when its on the gitbutler/integration branch
OpenWorkspace,
/// When the user has chosen to leave the gitbutler/integration branch
OutsideWorkspace,
/// When the app is off of gitbutler/integration and in edit mode
Edit(EditModeMetadata),
}

pub fn operating_mode(ctx: &CommandContext) -> OperatingMode {
let Ok(head_ref) = ctx.repository().head() else {
return OperatingMode::OutsideWorkspace;
};

let Some(head_ref_name) = head_ref.name() else {
return OperatingMode::OutsideWorkspace;
};

if head_ref_name == INTEGRATION_BRANCH_REF {
OperatingMode::OpenWorkspace
} else if head_ref_name == EDIT_BRANCH_REF {
let edit_mode_metadata = read_edit_mode_metadata(ctx);

match edit_mode_metadata {
Ok(edit_mode_metadata) => OperatingMode::Edit(edit_mode_metadata),
Err(error) => {
tracing::warn!(
"Failed to open in edit mode, falling back to outside workspace {}",
error
);
OperatingMode::OutsideWorkspace
}
}
} else {
OperatingMode::OutsideWorkspace
}
}

pub fn in_open_workspace_mode(ctx: &CommandContext) -> bool {
operating_mode(ctx) == OperatingMode::OpenWorkspace
}

pub fn assure_open_workspace_mode(ctx: &CommandContext) -> Result<()> {
if in_open_workspace_mode(ctx)? {
if in_open_workspace_mode(ctx) {
Ok(())
} else {
bail!("Unexpected state: cannot perform operation on non-integration branch")
bail!("Expected to be in open workspace mode")
}
}

pub fn in_edit_mode(ctx: &CommandContext) -> bool {
matches!(operating_mode(ctx), OperatingMode::Edit(_))
}

pub fn assure_edit_mode(ctx: &CommandContext) -> Result<EditModeMetadata> {
match operating_mode(ctx) {
OperatingMode::Edit(edit_mode_metadata) => Ok(edit_mode_metadata),
_ => bail!("Expected to be in edit mode"),
}
}

pub fn in_outside_workspace_mode(ctx: &CommandContext) -> Result<bool> {
in_open_workspace_mode(ctx).map(|open_mode| !open_mode)
pub fn in_outside_workspace_mode(ctx: &CommandContext) -> bool {
operating_mode(ctx) == OperatingMode::OutsideWorkspace
}

pub fn assure_outside_workspace_mode(ctx: &CommandContext) -> Result<()> {
if in_outside_workspace_mode(ctx)? {
if in_outside_workspace_mode(ctx) {
Ok(())
} else {
bail!("Unexpected state: cannot perform operation on integration branch")
bail!("Expected to be in outside workspace mode")
}
}
Loading

0 comments on commit 4f6748b

Please sign in to comment.