remove unused push_gb_data

This commit is contained in:
Kiril Videlov 2024-05-12 02:05:07 +02:00
parent ff3cf9bca7
commit bca8e13dfb
No known key found for this signature in database
7 changed files with 1 additions and 653 deletions

View File

@ -20,7 +20,6 @@ pub trait Watchers {
/// Stop watching filesystem changes.
async fn stop(&self, id: ProjectId);
async fn fetch_gb_data(&self, id: ProjectId) -> anyhow::Result<()>;
async fn push_gb_data(&self, id: ProjectId) -> anyhow::Result<()>;
}
#[derive(Clone)]
@ -180,14 +179,6 @@ impl Controller {
);
}
}
if let Err(error) = watchers.push_gb_data(project.id).await {
tracing::error!(
project_id = %project.id,
?error,
"failed to post push project event"
);
}
}
}

View File

@ -196,9 +196,4 @@ impl gitbutler_core::projects::Watchers for Watchers {
self.post(gitbutler_watcher::Action::FetchGitbutlerData(id))
.await
}
async fn push_gb_data(&self, id: ProjectId) -> Result<()> {
self.post(gitbutler_watcher::Action::PushGitbutlerData(id))
.await
}
}

View File

@ -11,7 +11,6 @@ pub(super) enum InternalEvent {
Flush(ProjectId, sessions::Session),
CalculateVirtualBranches(ProjectId),
FetchGitbutlerData(ProjectId),
PushGitbutlerData(ProjectId),
// From file monitor
GitFilesChange(ProjectId, Vec<PathBuf>),
@ -27,7 +26,6 @@ pub enum Action {
Flush(ProjectId, sessions::Session),
CalculateVirtualBranches(ProjectId),
FetchGitbutlerData(ProjectId),
PushGitbutlerData(ProjectId),
}
impl Action {
@ -36,8 +34,7 @@ impl Action {
match self {
Action::FetchGitbutlerData(project_id)
| Action::Flush(project_id, _)
| Action::CalculateVirtualBranches(project_id)
| Action::PushGitbutlerData(project_id) => *project_id,
| Action::CalculateVirtualBranches(project_id) => *project_id,
}
}
}
@ -48,7 +45,6 @@ impl From<Action> for InternalEvent {
Action::Flush(a, b) => InternalEvent::Flush(a, b),
Action::CalculateVirtualBranches(v) => InternalEvent::CalculateVirtualBranches(v),
Action::FetchGitbutlerData(v) => InternalEvent::FetchGitbutlerData(v),
Action::PushGitbutlerData(v) => InternalEvent::PushGitbutlerData(v),
}
}
}
@ -79,7 +75,6 @@ impl Display for InternalEvent {
)
}
InternalEvent::CalculateVirtualBranches(pid) => write!(f, "VirtualBranch({})", pid),
InternalEvent::PushGitbutlerData(pid) => write!(f, "PushGitbutlerData({})", pid),
}
}
}

View File

@ -1,6 +1,5 @@
mod calculate_deltas;
mod index;
mod push_project_to_gitbutler;
use std::path::{Path, PathBuf};
use std::sync::Arc;
@ -85,10 +84,6 @@ impl Handler {
.await
.context("failed to handle git file change event"),
events::InternalEvent::PushGitbutlerData(project_id) => self
.push_gb_data(project_id)
.context("failed to push gitbutler data"),
events::InternalEvent::FetchGitbutlerData(project_id) => self
.fetch_gb_data(project_id, now)
.await
@ -152,12 +147,6 @@ impl Handler {
self.index_session(project_id, session)?;
let push_gb_data = tokio::task::spawn_blocking({
let this = self.clone();
move || this.push_gb_data(project_id)
});
self.push_project_to_gitbutler(project_id, 1000).await?;
push_gb_data.await??;
Ok(())
}
@ -183,25 +172,6 @@ impl Handler {
}
}
/// NOTE: this is an honest non-async function, and it should stay that way to avoid
/// dealing with git2 repositories across await points, which aren't `Send`.
fn push_gb_data(&self, project_id: ProjectId) -> Result<()> {
let user = self.users.get_user()?;
let project = self.projects.get(&project_id)?;
let project_repository =
project_repository::Repository::open(&project).context("failed to open repository")?;
let gb_repo = gb_repository::Repository::open(
&self.local_data_dir,
&project_repository,
user.as_ref(),
)
.context("failed to open repository")?;
gb_repo
.push(user.as_ref())
.context("failed to push gb repo")
}
pub async fn fetch_gb_data(&self, project_id: ProjectId, now: time::SystemTime) -> Result<()> {
let user = self.users.get_user()?;
let project = self

View File

@ -1,219 +0,0 @@
use std::time;
use anyhow::{Context, Result};
use gitbutler_core::id::Id;
use gitbutler_core::{
gb_repository,
git::{self, Oid, Repository},
project_repository,
projects::{self, CodePushState, ProjectId},
users,
};
use itertools::Itertools;
impl super::Handler {
pub async fn push_project_to_gitbutler(
&self,
project_id: ProjectId,
batch_size: usize,
) -> Result<()> {
let project = self
.projects
.get(&project_id)
.context("failed to get project")?;
if !project.is_sync_enabled() || !project.has_code_url() {
return Ok(());
}
let user = self.users.get_user()?;
let project_repository =
project_repository::Repository::open(&project).context("failed to open repository")?;
let gb_code_last_commit = project
.gitbutler_code_push_state
.as_ref()
.map(|state| &state.id)
.copied();
let gb_repository = gb_repository::Repository::open(
&self.local_data_dir,
&project_repository,
user.as_ref(),
)?;
let default_target = gb_repository
.default_target()
.context("failed to open gb repo")?
.context("failed to get default target")?;
let target_changed = gb_code_last_commit.map_or(true, |id| id != default_target.sha);
if target_changed {
match self
.push_target(
&project_repository,
&default_target,
gb_code_last_commit,
project_id,
user.as_ref(),
batch_size,
)
.await
{
Ok(()) => {}
Err(project_repository::RemoteError::Network) => return Ok(()),
Err(err) => return Err(err).context("failed to push"),
};
}
tokio::task::spawn_blocking(move || -> Result<()> {
match push_all_refs(&project_repository, user.as_ref(), project_id) {
Ok(()) => Ok(()),
Err(project_repository::RemoteError::Network) => Ok(()),
Err(err) => Err(err).context("failed to push"),
}
})
.await??;
// make sure last push time is updated
self.update_project(project_id, default_target.sha).await?;
Ok(())
}
}
/// Currently required to make functionality testable without requiring a `Handler` with all of its state.
impl super::Handler {
async fn update_project(
&self,
project_id: Id<projects::Project>,
id: Oid,
) -> Result<(), project_repository::RemoteError> {
self.projects
.update(&projects::UpdateRequest {
id: project_id,
gitbutler_code_push_state: Some(CodePushState {
id,
timestamp: time::SystemTime::now(),
}),
..Default::default()
})
.await
.context("failed to update last push")?;
Ok(())
}
async fn push_target(
&self,
project_repository: &project_repository::Repository,
default_target: &gitbutler_core::virtual_branches::target::Target,
gb_code_last_commit: Option<Oid>,
project_id: Id<projects::Project>,
user: Option<&users::User>,
batch_size: usize,
) -> Result<(), project_repository::RemoteError> {
let ids = batch_rev_walk(
&project_repository.git_repository,
batch_size,
default_target.sha,
gb_code_last_commit,
)?;
tracing::info!(
%project_id,
batches=%ids.len(),
"batches left to push",
);
let id_count = ids.len();
for (idx, id) in ids.iter().enumerate().rev() {
let refspec = format!("+{}:refs/push-tmp/{}", id, project_id);
project_repository.push_to_gitbutler_server(user, &[&refspec])?;
self.update_project(project_id, *id).await?;
tracing::info!(
%project_id,
i = id_count.saturating_sub(idx),
total = id_count,
"project batch pushed",
);
}
project_repository.push_to_gitbutler_server(
user,
&[&format!("+{}:refs/{}", default_target.sha, project_id)],
)?;
//TODO: remove push-tmp ref
tracing::info!(
%project_id,
"project target ref fully pushed",
);
Ok(())
}
}
fn push_all_refs(
project_repository: &project_repository::Repository,
user: Option<&users::User>,
project_id: Id<projects::Project>,
) -> Result<(), project_repository::RemoteError> {
let gb_references = collect_refs(project_repository)?;
let all_refs: Vec<_> = gb_references
.iter()
.filter(|r| {
matches!(
r,
git::Refname::Remote(_) | git::Refname::Virtual(_) | git::Refname::Local(_)
)
})
.map(|r| format!("+{}:{}", r, r))
.collect();
let all_refs: Vec<_> = all_refs.iter().map(String::as_str).collect();
let anything_pushed = project_repository.push_to_gitbutler_server(user, &all_refs)?;
if anything_pushed {
tracing::info!(
%project_id,
"refs pushed",
);
}
Ok(())
}
fn collect_refs(
project_repository: &project_repository::Repository,
) -> anyhow::Result<Vec<git::Refname>> {
Ok(project_repository
.git_repository
.references_glob("refs/*")?
.flatten()
.filter_map(|r| r.name())
.collect::<Vec<_>>())
}
fn batch_rev_walk(
repo: &Repository,
batch_size: usize,
from: Oid,
until: Option<Oid>,
) -> Result<Vec<Oid>> {
let mut revwalk = repo.revwalk().context("failed to create revwalk")?;
revwalk
.push(from.into())
.context(format!("failed to push {}", from))?;
if let Some(oid) = until {
revwalk
.hide(oid.into())
.context(format!("failed to hide {}", oid))?;
}
let mut oids = Vec::new();
oids.push(from);
let from = from.into();
for batch in &revwalk.chunks(batch_size) {
let Some(oid) = batch.last() else { continue };
let oid = oid.context("failed to get oid")?;
if oid != from {
oids.push(oid.into());
}
}
Ok(oids)
}

View File

@ -98,4 +98,3 @@ fn test_remote_repository() -> anyhow::Result<(git2::Repository, TempDir)> {
mod calculate_delta;
mod fetch_gitbutler_data;
mod git_file_change;
mod push_project_to_gitbutler;

View File

@ -1,383 +0,0 @@
use std::{collections::HashMap, path::PathBuf};
use anyhow::Result;
use gitbutler_core::{git, project_repository::LogUntil, projects};
use crate::handler::support::Fixture;
use crate::handler::test_remote_repository;
use gitbutler_testsupport::{virtual_branches::set_test_target, Case};
fn log_walk(repo: &git2::Repository, head: git::Oid) -> Vec<git::Oid> {
let mut walker = repo.revwalk().unwrap();
walker.push(head.into()).unwrap();
walker.map(|oid| oid.unwrap().into()).collect::<Vec<_>>()
}
#[tokio::test]
async fn push_error() -> Result<()> {
let mut fixture = Fixture::default();
let handler = fixture.new_handler();
let Case { project, .. } = &fixture.new_case();
let api_project = projects::ApiProject {
name: "test-sync".to_string(),
description: None,
repository_id: "123".to_string(),
git_url: String::new(),
code_git_url: Some(String::new()),
created_at: 0_i32.to_string(),
updated_at: 0_i32.to_string(),
sync: true,
};
fixture
.projects
.update(&projects::UpdateRequest {
id: project.id,
api: Some(api_project.clone()),
..Default::default()
})
.await?;
let res = handler.push_project_to_gitbutler(project.id, 100).await;
let err = res.unwrap_err();
assert_eq!(err.to_string(), "failed to get default target");
Ok(())
}
#[tokio::test]
async fn push_simple() -> Result<()> {
let mut fixture = Fixture::default();
let handler = fixture.new_handler();
let Case {
project,
gb_repository,
project_repository,
..
} = &fixture.new_case_with_files(HashMap::from([(PathBuf::from("test.txt"), "test")]));
fixture.sign_in();
set_test_target(project_repository).unwrap();
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
let (cloud_code, _tmp) = test_remote_repository()?;
let api_project = projects::ApiProject {
name: "test-sync".to_string(),
description: None,
repository_id: "123".to_string(),
git_url: String::new(),
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
created_at: 0_i32.to_string(),
updated_at: 0_i32.to_string(),
sync: true,
};
fixture
.projects
.update(&projects::UpdateRequest {
id: project.id,
api: Some(api_project.clone()),
..Default::default()
})
.await?;
cloud_code.find_commit(target_id.into()).unwrap_err();
{
handler
.push_project_to_gitbutler(project.id, 10)
.await
.unwrap();
}
cloud_code.find_commit(target_id.into()).unwrap();
let pushed = log_walk(&cloud_code, target_id);
assert_eq!(reference.len(), pushed.len());
assert_eq!(reference, pushed);
assert_eq!(
fixture
.projects
.get(&project.id)
.unwrap()
.gitbutler_code_push_state
.unwrap()
.id,
target_id
);
Ok(())
}
#[tokio::test]
async fn push_remote_ref() -> Result<()> {
let mut fixture = Fixture::default();
let handler = fixture.new_handler();
let Case {
project,
project_repository,
..
} = &fixture.new_case();
fixture.sign_in();
set_test_target(project_repository).unwrap();
let (cloud_code, _tmp) = test_remote_repository()?;
let cloud_code: git::Repository = cloud_code.into();
let (remote_repo, _tmp) = test_remote_repository()?;
let remote_repo: git::Repository = remote_repo.into();
let last_commit = create_initial_commit(&remote_repo);
remote_repo
.reference(
&git::Refname::Local(git::LocalRefname::new("refs/heads/testbranch", None)),
last_commit,
false,
"",
)
.unwrap();
let mut remote = project_repository
.git_repository
.remote("tr", &remote_repo.path().to_str().unwrap().parse().unwrap())
.unwrap();
remote
.fetch(&["+refs/heads/*:refs/remotes/tr/*"], None)
.unwrap();
project_repository
.git_repository
.find_commit(last_commit)
.unwrap();
let api_project = projects::ApiProject {
name: "test-sync".to_string(),
description: None,
repository_id: "123".to_string(),
git_url: String::new(),
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
created_at: 0_i32.to_string(),
updated_at: 0_i32.to_string(),
sync: true,
};
fixture
.projects
.update(&projects::UpdateRequest {
id: project.id,
api: Some(api_project.clone()),
..Default::default()
})
.await?;
{
handler
.push_project_to_gitbutler(project.id, 10)
.await
.unwrap();
}
cloud_code.find_commit(last_commit).unwrap();
Ok(())
}
fn create_initial_commit(repo: &git::Repository) -> git::Oid {
let signature = git::Signature::now("test", "test@email.com").unwrap();
let mut index = repo.index().unwrap();
let oid = index.write_tree().unwrap();
repo.commit(
None,
&signature,
&signature,
"initial commit",
&repo.find_tree(oid).unwrap(),
&[],
)
.unwrap()
}
fn create_test_commits(repo: &git::Repository, commits: usize) -> git::Oid {
let signature = git::Signature::now("test", "test@email.com").unwrap();
let mut last = None;
for i in 0..commits {
let mut index = repo.index().unwrap();
let oid = index.write_tree().unwrap();
let head = repo.head().unwrap();
last = Some(
repo.commit(
Some(&head.name().unwrap()),
&signature,
&signature,
format!("commit {i}").as_str(),
&repo.find_tree(oid).unwrap(),
&[&repo
.find_commit(repo.refname_to_id("HEAD").unwrap())
.unwrap()],
)
.unwrap(),
);
}
last.unwrap()
}
#[tokio::test]
async fn push_batches() -> Result<()> {
let mut fixture = Fixture::default();
let handler = fixture.new_handler();
let Case {
project,
gb_repository,
project_repository,
..
} = &fixture.new_case();
fixture.sign_in();
{
let head: git::Oid = project_repository
.get_head()
.unwrap()
.peel_to_commit()
.unwrap()
.id();
let reference = project_repository.l(head, LogUntil::End).unwrap();
assert_eq!(reference.len(), 2);
let head = create_test_commits(&project_repository.git_repository, 10);
let reference = project_repository.l(head, LogUntil::End).unwrap();
assert_eq!(reference.len(), 12);
}
set_test_target(project_repository).unwrap();
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
let (cloud_code, _tmp) = test_remote_repository()?;
let api_project = projects::ApiProject {
name: "test-sync".to_string(),
description: None,
repository_id: "123".to_string(),
git_url: String::new(),
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
created_at: 0_i32.to_string(),
updated_at: 0_i32.to_string(),
sync: true,
};
fixture
.projects
.update(&projects::UpdateRequest {
id: project.id,
api: Some(api_project.clone()),
..Default::default()
})
.await?;
{
handler
.push_project_to_gitbutler(project.id, 2)
.await
.unwrap();
}
cloud_code.find_commit(target_id.into()).unwrap();
let pushed = log_walk(&cloud_code, target_id);
assert_eq!(reference.len(), pushed.len());
assert_eq!(reference, pushed);
assert_eq!(
fixture
.projects
.get(&project.id)
.unwrap()
.gitbutler_code_push_state
.unwrap()
.id,
target_id
);
Ok(())
}
#[tokio::test]
async fn push_again_no_change() -> Result<()> {
let mut fixture = Fixture::default();
let handler = fixture.new_handler();
let Case {
project,
gb_repository,
project_repository,
..
} = &fixture.new_case_with_files(HashMap::from([(PathBuf::from("test.txt"), "test")]));
fixture.sign_in();
set_test_target(project_repository).unwrap();
let target_id = gb_repository.default_target().unwrap().unwrap().sha;
let reference = project_repository.l(target_id, LogUntil::End).unwrap();
let (cloud_code, _tmp) = test_remote_repository()?;
let api_project = projects::ApiProject {
name: "test-sync".to_string(),
description: None,
repository_id: "123".to_string(),
git_url: String::new(),
code_git_url: Some(cloud_code.path().to_str().unwrap().to_string()),
created_at: 0_i32.to_string(),
updated_at: 0_i32.to_string(),
sync: true,
};
fixture
.projects
.update(&projects::UpdateRequest {
id: project.id,
api: Some(api_project.clone()),
..Default::default()
})
.await?;
cloud_code.find_commit(target_id.into()).unwrap_err();
{
handler
.push_project_to_gitbutler(project.id, 10)
.await
.unwrap();
}
cloud_code.find_commit(target_id.into()).unwrap();
let pushed = log_walk(&cloud_code, target_id);
assert_eq!(reference.len(), pushed.len());
assert_eq!(reference, pushed);
assert_eq!(
fixture
.projects
.get(&project.id)
.unwrap()
.gitbutler_code_push_state
.unwrap()
.id,
target_id
);
Ok(())
}