mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 14:31:30 +03:00
Merge pull request #3687 from gitbutlerapp/snapshot-on-file-changes
snapshot on file changes
This commit is contained in:
commit
81bc5b327c
@ -29,6 +29,7 @@ pub mod path;
|
||||
pub mod project_repository;
|
||||
pub mod projects;
|
||||
pub mod reader;
|
||||
pub mod repo;
|
||||
pub mod sessions;
|
||||
pub mod snapshots;
|
||||
pub mod ssh;
|
||||
|
@ -84,6 +84,13 @@ pub struct Project {
|
||||
pub omit_certificate_check: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub enable_snapshots: Option<bool>,
|
||||
// The number of changed lines that will trigger a snapshot
|
||||
#[serde(default = "default_snapshot_lines_threshold")]
|
||||
pub snapshot_lines_threshold: usize,
|
||||
}
|
||||
|
||||
fn default_snapshot_lines_threshold() -> usize {
|
||||
20
|
||||
}
|
||||
|
||||
impl AsRef<Project> for Project {
|
||||
|
18
crates/gitbutler-core/src/repo.rs
Normal file
18
crates/gitbutler-core/src/repo.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use anyhow::Result;
|
||||
|
||||
/// The GbRepository trait provides methods which are building blocks for Gitbutler functionality.
|
||||
pub trait GbRepository {
|
||||
/// Returns the number of uncommitted lines of code (added plus removed) in the repository. Included untracked files.
|
||||
fn changed_lines_count(&self) -> Result<usize>;
|
||||
}
|
||||
|
||||
impl GbRepository for git2::Repository {
|
||||
fn changed_lines_count(&self) -> Result<usize> {
|
||||
let head_tree = self.head()?.peel_to_commit()?.tree()?;
|
||||
let mut opts = git2::DiffOptions::new();
|
||||
opts.include_untracked(true);
|
||||
let diff = self.diff_tree_to_workdir_with_index(Some(&head_tree), Some(&mut opts));
|
||||
let stats = diff?.stats()?;
|
||||
Ok(stats.deletions() + stats.insertions())
|
||||
}
|
||||
}
|
@ -152,6 +152,7 @@ pub enum OperationType {
|
||||
ReorderCommit,
|
||||
InsertBlankCommit,
|
||||
MoveCommitFile,
|
||||
FileChanges,
|
||||
#[default]
|
||||
Unknown,
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ futures = "0.3.30"
|
||||
tokio = { workspace = true, features = [ "macros" ] }
|
||||
tokio-util = "0.7.10"
|
||||
tracing = "0.1.40"
|
||||
git2.workspace = true
|
||||
|
||||
backoff = "0.4.0"
|
||||
notify = { version = "6.0.1" }
|
||||
|
@ -8,12 +8,16 @@ use std::{path, time};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use gitbutler_core::projects::ProjectId;
|
||||
use gitbutler_core::repo::GbRepository;
|
||||
use gitbutler_core::sessions::SessionId;
|
||||
use gitbutler_core::snapshots::entry::{OperationType, SnapshotDetails, Trailer};
|
||||
use gitbutler_core::snapshots::snapshot;
|
||||
use gitbutler_core::virtual_branches::VirtualBranches;
|
||||
use gitbutler_core::{
|
||||
assets, deltas, gb_repository, git, project_repository, projects, reader, sessions, users,
|
||||
virtual_branches,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{events, Change};
|
||||
@ -39,6 +43,9 @@ pub struct Handler {
|
||||
/// A function to send events - decoupled from app-handle for testing purposes.
|
||||
#[allow(clippy::type_complexity)]
|
||||
send_event: Arc<dyn Fn(Change) -> Result<()> + Send + Sync + 'static>,
|
||||
|
||||
// The number of changed lines since the value was last reset
|
||||
changed_lines_count: Arc<Mutex<usize>>,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
@ -63,6 +70,7 @@ impl Handler {
|
||||
sessions_db,
|
||||
deltas_db,
|
||||
send_event: Arc::new(send_event),
|
||||
changed_lines_count: Arc::new(Mutex::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,15 +286,57 @@ impl Handler {
|
||||
paths: Vec<PathBuf>,
|
||||
project_id: ProjectId,
|
||||
) -> Result<()> {
|
||||
let paths_string = paths
|
||||
.iter()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
let calc_deltas = tokio::task::spawn_blocking({
|
||||
let this = self.clone();
|
||||
move || this.calculate_deltas(paths, project_id)
|
||||
});
|
||||
let changed_lines_before = *self.changed_lines_count.lock().await;
|
||||
// Create a snapshot every time there are more than 20 new lines of code
|
||||
let handle_snapshots = tokio::task::spawn_blocking({
|
||||
let this = self.clone();
|
||||
move || this.maybe_create_snapshot(project_id, changed_lines_before, paths_string)
|
||||
});
|
||||
// Set changed lines count to the newly observed value
|
||||
*self.changed_lines_count.lock().await = handle_snapshots.await??;
|
||||
self.calculate_virtual_branches(project_id).await?;
|
||||
calc_deltas.await??;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn maybe_create_snapshot(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
changed_lines_before: usize,
|
||||
paths: String,
|
||||
) -> anyhow::Result<usize> {
|
||||
let project = self
|
||||
.projects
|
||||
.get(&project_id)
|
||||
.context("failed to get project")?;
|
||||
let repo_path = project.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
let changed_lines = repo.changed_lines_count()? - changed_lines_before;
|
||||
if changed_lines > project.snapshot_lines_threshold {
|
||||
let details = SnapshotDetails {
|
||||
version: Default::default(),
|
||||
operation: OperationType::FileChanges,
|
||||
title: OperationType::FileChanges.to_string(),
|
||||
body: None,
|
||||
trailers: vec![Trailer {
|
||||
key: "files".to_string(),
|
||||
value: paths,
|
||||
}],
|
||||
};
|
||||
snapshot::create(&project, details)?;
|
||||
}
|
||||
Ok(changed_lines)
|
||||
}
|
||||
|
||||
pub async fn git_file_change(
|
||||
&self,
|
||||
path: impl Into<PathBuf>,
|
||||
|
Loading…
Reference in New Issue
Block a user