Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3 Uncommitted Files, CLI and Filewatching #5912

Merged
merged 2 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Cargo.lock

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

40 changes: 3 additions & 37 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,42 +1,7 @@
[workspace]
members = [
"crates/gitbutler-tauri",
"crates/gitbutler-git",
"crates/gitbutler-watcher",
"crates/gitbutler-watcher/vendor/debouncer",
"crates/gitbutler-testsupport",
"crates/gitbutler-cli",
"crates/gitbutler-branch-actions",
"crates/gitbutler-sync",
"crates/gitbutler-oplog",
"crates/gitbutler-repo",
"crates/gitbutler-repo-actions",
"crates/gitbutler-command-context",
"crates/gitbutler-feedback",
"crates/gitbutler-config",
"crates/gitbutler-project",
"crates/gitbutler-user",
"crates/gitbutler-branch",
"crates/gitbutler-reference",
"crates/gitbutler-error",
"crates/gitbutler-serde",
"crates/gitbutler-secret",
"crates/gitbutler-id",
"crates/gitbutler-storage",
"crates/gitbutler-fs",
"crates/gitbutler-time",
"crates/gitbutler-commit",
"crates/gitbutler-tagged-string",
"crates/gitbutler-url",
"crates/gitbutler-diff",
"crates/gitbutler-operating-modes",
"crates/gitbutler-edit-mode",
"crates/gitbutler-cherry-pick",
"crates/gitbutler-oxidize",
"crates/gitbutler-stack",
"crates/gitbutler-hunk-dependency",
"crates/gitbutler-settings",
"crates/gitbutler-workspace",
"crates/gitbutler-*",
"crates/but-*"
Comment on lines +3 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my days! This is so much better

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it to highlight the two-class society we are building :D.

]
resolver = "2"

Expand Down Expand Up @@ -96,6 +61,7 @@ gitbutler-forge = { path = "crates/gitbutler-forge" }
gitbutler-hunk-dependency = { path = "crates/gitbutler-hunk-dependency" }
gitbutler-settings = { path = "crates/gitbutler-settings" }
gitbutler-workspace = { path = "crates/gitbutler-workspace" }
but-core = { path = "crates/but-core" }

[profile.release]
codegen-units = 1 # Compile crates one after another so the compiler can optimize better
Expand Down
21 changes: 21 additions & 0 deletions crates/but-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "but-cli"
version = "0.0.0"
edition = "2021"
authors = ["GitButler <[email protected]>"]
publish = false
rust-version = "1.74"

[[bin]]
name = "but-cli"
path = "src/main.rs"
doctest = false

[dependencies]
but-core.workspace = true

clap = { version = "4.5.23", features = ["derive", "env"] }
anyhow = "1.0.95"
tracing-forest = { version = "0.1.6" }
tracing-subscriber.workspace = true
tracing.workspace = true
32 changes: 32 additions & 0 deletions crates/but-cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::path::PathBuf;

#[derive(Debug, clap::Parser)]
#[clap(name = "gitbutler-cli", about = "A CLI for GitButler", version = option_env!("GIX_VERSION"))]
pub struct Args {
/// Enable tracing for debug and performance information printed to stderr.
#[clap(short = 'd', long)]
pub trace: bool,
/// Run as if gitbutler-cli was started in PATH instead of the current working directory.
#[clap(short = 'C', long, default_value = ".", value_name = "PATH")]
pub current_dir: PathBuf,

#[clap(subcommand)]
pub cmd: Subcommands,
}

#[derive(Debug, clap::Subcommand)]
pub enum Subcommands {
/// Update the local workspace against an updated remote or target branch.
Status,
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn clap() {
use clap::CommandFactory;
Args::command().debug_assert();
}
}
12 changes: 12 additions & 0 deletions crates/but-cli/src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn debug_print(this: impl std::fmt::Debug) -> anyhow::Result<()> {
println!("{:#?}", this);
Ok(())
}

pub mod status {
use crate::command::debug_print;

pub fn doit() -> anyhow::Result<()> {
debug_print("call into but-core")
}
}
39 changes: 39 additions & 0 deletions crates/but-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! A debug-CLI for making `but`-crates functionality available in real-world repositories.
use anyhow::Result;

mod args;
use args::Args;

mod command;

fn main() -> Result<()> {
let args: Args = clap::Parser::parse();

if args.trace {
trace::init()?;
}
let _op_span = tracing::info_span!("cli-op").entered();

match args.cmd {
args::Subcommands::Status => command::status::doit(),
}
}

mod trace {
use tracing::metadata::LevelFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::Layer;

pub fn init() -> anyhow::Result<()> {
tracing_subscriber::registry()
.with(
tracing_forest::ForestLayer::from(
tracing_forest::printer::PrettyPrinter::new().writer(std::io::stderr),
)
.with_filter(LevelFilter::DEBUG),
)
.init();
Ok(())
}
}
17 changes: 17 additions & 0 deletions crates/but-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "but-core"
version = "0.0.0"
edition = "2021"
authors = ["GitButler <[email protected]>"]
publish = false

[lib]
doctest = false

[dependencies]
serde = { workspace = true, features = ["std"] }
bstr.workspace = true
anyhow = "1.0.95"
gix = { workspace = true, features = ["dirwalk", "credentials", "parallel"] }
walkdir = "2.5.0"
toml.workspace = true
29 changes: 29 additions & 0 deletions crates/but-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![deny(missing_docs, rust_2018_idioms)]
//! The basic primitives that GitButler is built around.
//!
//! It also is a catch-all for code until it's worth putting it into its own crate.
//!
//! ### House-~~Rules~~ Guidance
//!
//! * Try hard to do write all the 'right' tests
//! - Tests should challenge the implementation, try hard to break it.
//! - capture *all* business requirements
//! - Try to avoid doing read-only filesystem fixtures with `tempdir`, instead use `gitbutler-testtools::readonly`.
//! * minimal dependencies
//! - both for the crate and for parameters of functions as well.
//! - i.e. try to avoid 'God' structures so the function only has access to what it needs to.
//! * The filesystem is `Sync` but we don't have atomic operations
//! - Let's be very careful about changes to the filesystem, must at least be on the level of Git which means `.lock` files instead of direct writes.
//! - If only one part of the application is supposed to change the worktree, let's protect the Application from itself by using `gitbutler::access` just like we do now.
//! * Make it work, make it work right, and if time and profiler permits, make it work fast.
//! * All of the above can and should be scrutinized and is there is no hard rules.

/// Functions related to a Git worktree, i.e. the files checked out from a repository.
pub mod worktree {
use std::path::Path;

/// Return a list of items that live underneath `worktree_root` that changed and thus can become part of a commit.
pub fn committable_entries(_worktree_root: &Path) -> anyhow::Result<()> {
todo!()
}
}
2 changes: 2 additions & 0 deletions crates/but-core/tests/core/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[test]
fn itworks() {}
2 changes: 1 addition & 1 deletion crates/gitbutler-command-context/src/repository_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl RepositoryExtLite for git2::Repository {
let path = worktree_dir.join(gix::path::from_bstr(item.entry.rela_path.as_bstr()));
let file_is_too_large = path
.metadata()
.map_or(false, |md| md.is_file() && md.len() > limit_in_bytes);
.is_ok_and(|md| md.is_file() && md.len() > limit_in_bytes);
file_is_too_large
.then(|| Vec::from(item.entry.rela_path).into_string().ok())
.flatten()
Expand Down
5 changes: 2 additions & 3 deletions crates/gitbutler-commit/src/commit_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ impl CommitExt for gix::Commit<'_> {
}

fn is_signed(&self) -> bool {
self.decode().map_or(false, |decoded| {
decoded.extra_headers().pgp_signature().is_some()
})
self.decode()
.is_ok_and(|decoded| decoded.extra_headers().pgp_signature().is_some())
}

fn is_conflicted(&self) -> bool {
Expand Down
1 change: 0 additions & 1 deletion crates/gitbutler-diff/src/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,6 @@ pub fn diff_files_into_hunks(
}

#[cfg(test)]

mod test {
use super::*;

Expand Down
6 changes: 3 additions & 3 deletions crates/gitbutler-diff/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ where
let full_path_exists = full_path.exists();
let discard_hunk = (hunks.len() == 1).then(|| &hunks[0]);
if full_path_exists || allow_new_file {
if discard_hunk.map_or(false, |hunk| hunk.change_type == crate::ChangeType::Deleted) {
if discard_hunk.is_some_and(|hunk| hunk.change_type == crate::ChangeType::Deleted) {
// File was created but now that hunk is being discarded with an inversed hunk
builder.remove(rel_path);
fs::remove_file(full_path.clone()).or_else(|err| {
Expand Down Expand Up @@ -131,7 +131,7 @@ where
)?;
builder.upsert(rel_path, blob_oid, filemode);
} else if let Ok(tree_entry) = base_tree.get_path(rel_path) {
if discard_hunk.map_or(false, |hunk| hunk.binary) {
if discard_hunk.is_some_and(|hunk| hunk.binary) {
let new_blob_oid = &hunks[0].diff_lines;
// convert string to Oid
let new_blob_oid = new_blob_oid
Expand Down Expand Up @@ -195,7 +195,7 @@ where
// upsert into the builder
builder.upsert(rel_path, new_blob_oid, filemode);
} else if !full_path_exists
&& discard_hunk.map_or(false, |hunk| {
&& discard_hunk.is_some_and(|hunk| {
hunk.change_type == crate::ChangeType::Added
|| hunk.change_type == crate::ChangeType::Untracked
})
Expand Down
2 changes: 1 addition & 1 deletion crates/gitbutler-project/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl Controller {
Ok(repo) if repo.is_bare() => {
bail!("bare repositories are unsupported");
}
Ok(repo) if repo.worktree().map_or(false, |wt| !wt.is_main()) => {
Ok(repo) if repo.worktree().is_some_and(|wt| !wt.is_main()) => {
if path.join(".git").is_file() {
bail!("can only work in main worktrees");
};
Expand Down
2 changes: 1 addition & 1 deletion crates/gitbutler-reference/src/refname/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,6 @@ impl PartialEq<FullNameRef> for Refname {
shortname
.strip_prefix(self.remote.as_bytes())
.and_then(|rest| rest.strip_suffix(self.branch.as_bytes()))
.map_or(false, |rest| rest == b"/")
.is_some_and(|rest| rest == b"/")
}
}
2 changes: 1 addition & 1 deletion crates/gitbutler-url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Url {
pub fn is_github(&self) -> bool {
self.host
.as_ref()
.map_or(false, |host| host.contains("github.com"))
.is_some_and(|host| host.contains("github.com"))
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/gitbutler-watcher/vendor/debouncer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ struct Queue {

impl Queue {
fn was_created(&self) -> bool {
self.events.front().map_or(false, |event| {
self.events.front().is_some_and(|event| {
matches!(
event.kind,
EventKind::Create(_) | EventKind::Modify(ModifyKind::Name(RenameMode::To))
Expand All @@ -134,7 +134,7 @@ impl Queue {
}

fn was_removed(&self) -> bool {
self.events.front().map_or(false, |event| {
self.events.front().is_some_and(|event| {
matches!(
event.kind,
EventKind::Remove(_) | EventKind::Modify(ModifyKind::Name(RenameMode::From))
Expand Down Expand Up @@ -592,7 +592,7 @@ pub fn new_debouncer_opt<F: DebounceEventHandler, T: Watcher, C: FileIdCache + S
prev_queue_count = queue_count
}

if flush_after.map_or(false, |threshold| idle_count >= threshold) {
if flush_after.is_some_and(|threshold| idle_count >= threshold) {
idle_count = 0;
prev_queue_count = 0;
should_flush = true;
Expand Down
Loading