| @@ -11,26 +11,29 @@ use git::{ · 10 unmodified lines |
| 11 | status::{GitSummary, TrackedSummary}, | 11 | status::{GitSummary, TrackedSummary}, |
| 12 | }; | 12 | }; |
| 13 | use gpui::{ | 13 | use gpui::{ |
| 14 | App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, | 14 | App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task, |
| 15 | Task, WeakEntity, | 15 | WeakEntity, |
| 16 | }; | 16 | }; |
| 17 | use language::{Buffer, LanguageRegistry}; | 17 | use language::{Buffer, LanguageRegistry}; |
| 18 | use rpc::proto::{git_reset, ToProto}; | 18 | use rpc::proto::{git_reset, ToProto}; |
| 19 | use rpc::{proto, AnyProtoClient, TypedEnvelope}; | 19 | use rpc::{proto, AnyProtoClient, TypedEnvelope}; |
| 20 | use settings::WorktreeId; | 20 | use settings::WorktreeId; |
| | 21 | use std::future::Future; |
| 21 | use std::path::{Path, PathBuf}; | 22 | use std::path::{Path, PathBuf}; |
| 22 | use std::sync::Arc; | 23 | use std::sync::Arc; |
| 23 | use text::BufferId; | 24 | use text::BufferId; |
| 24 | use util::{maybe, ResultExt}; | 25 | use util::{maybe, ResultExt}; |
| 25 | use worktree::{ProjectEntryId, RepositoryEntry, StatusEntry}; | 26 | use worktree::{ProjectEntryId, RepositoryEntry, StatusEntry}; |
| 26 | | 27 | |
| | 28 | type GitJob = Box<dyn FnOnce(&mut AsyncApp) -> Task<()>>; |
| | 29 | |
| 27 | pub struct GitStore { | 30 | pub struct GitStore { |
| 28 | buffer_store: Entity<BufferStore>, | 31 | buffer_store: Entity<BufferStore>, |
| 29 | pub(super) project_id: Option<ProjectId>, | 32 | pub(super) project_id: Option<ProjectId>, |
| 30 | pub(super) client: Option<AnyProtoClient>, | 33 | pub(super) client: Option<AnyProtoClient>, |
| 31 | repositories: Vec<Entity<Repository>>, | 34 | repositories: Vec<Entity<Repository>>, |
| 32 | active_index: Option<usize>, | 35 | active_index: Option<usize>, |
| 33 | update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)>, | 36 | update_sender: mpsc::UnboundedSender<GitJob>, |
| 34 | _subscription: Subscription, | 37 | _subscription: Subscription, |
| 35 | } | 38 | } |
| 36 | | 39 | |
| @@ -41,7 +44,7 @@ pub struct Repository { · 4 unmodified lines |
| 41 | pub repository_entry: RepositoryEntry, | 44 | pub repository_entry: RepositoryEntry, |
| 42 | pub git_repo: GitRepo, | 45 | pub git_repo: GitRepo, |
| 43 | pub merge_message: Option<String>, | 46 | pub merge_message: Option<String>, |
| 44 | update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)>, | 47 | job_sender: mpsc::UnboundedSender<GitJob>, |
| 45 | } | 48 | } |
| 46 | | 49 | |
| 47 | #[derive(Clone)] | 50 | #[derive(Clone)] |
| @@ -55,40 +58,6 @@ pub enum GitRepo { · 7 unmodified lines |
| 55 | }, | 58 | }, |
| 56 | } | 59 | } |
| 57 | | 60 | |
| 58 | pub enum Message { | | |
| 59 | Commit { | | |
| 60 | git_repo: GitRepo, | | |
| 61 | message: SharedString, | | |
| 62 | name_and_email: Option<(SharedString, SharedString)>, | | |
| 63 | }, | | |
| 64 | Reset { | | |
| 65 | repo: GitRepo, | | |
| 66 | commit: SharedString, | | |
| 67 | reset_mode: ResetMode, | | |
| 68 | }, | | |
| 69 | CheckoutFiles { | | |
| 70 | repo: GitRepo, | | |
| 71 | commit: SharedString, | | |
| 72 | paths: Vec<RepoPath>, | | |
| 73 | }, | | |
| 74 | Stage(GitRepo, Vec<RepoPath>), | | |
| 75 | Unstage(GitRepo, Vec<RepoPath>), | | |
| 76 | SetIndexText(GitRepo, RepoPath, Option<String>), | | |
| 77 | Push { | | |
| 78 | repo: GitRepo, | | |
| 79 | branch_name: SharedString, | | |
| 80 | remote_name: SharedString, | | |
| 81 | options: Option<PushOptions>, | | |
| 82 | }, | | |
| 83 | Pull { | | |
| 84 | repo: GitRepo, | | |
| 85 | branch_name: SharedString, | | |
| 86 | remote_name: SharedString, | | |
| 87 | }, | | |
| 88 | Fetch(GitRepo), | | |
| 89 | } | | |
| 90 | | | |
| 91 | #[derive(Debug)] | | |
| 92 | pub enum GitEvent { | 61 | pub enum GitEvent { |
| 93 | ActiveRepositoryChanged, | 62 | ActiveRepositoryChanged, |
| 94 | FileSystemUpdated, | 63 | FileSystemUpdated, |
| @@ -220,7 +189,7 @@ impl GitStore { · 125 unmodified lines |
| 220 | worktree_id, | 189 | worktree_id, |
| 221 | repository_entry: repo.clone(), | 190 | repository_entry: repo.clone(), |
| 222 | git_repo, | 191 | git_repo, |
| 223 | update_sender: self.update_sender.clone(), | 192 | job_sender: self.update_sender.clone(), |
| 224 | merge_message, | 193 | merge_message, |
| 225 | commit_message_buffer: None, | 194 | commit_message_buffer: None, |
| 226 | }) | 195 | }) |
| @@ -252,272 +221,15 @@ impl GitStore { · 25 unmodified lines |
| 252 | self.repositories.clone() | 221 | self.repositories.clone() |
| 253 | } | 222 | } |
| 254 | | 223 | |
| 255 | fn spawn_git_worker( | 224 | fn spawn_git_worker(cx: &mut Context<'_, GitStore>) -> mpsc::UnboundedSender<GitJob> { |
| 256 | cx: &mut Context<'_, GitStore>, | 225 | let (job_tx, mut job_rx) = mpsc::unbounded::<GitJob>(); |
| 257 | ) -> mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)> { | 226 | cx.spawn(|_, mut cx| async move { |
| 258 | let (update_sender, mut update_receiver) = | 227 | while let Some(job) = job_rx.next().await { |
| 259 | mpsc::unbounded::<(Message, oneshot::Sender<Result<()>>)>(); | 228 | job(&mut cx).await |
| 260 | cx.spawn(|_, cx| async move { | | |
| 261 | while let Some((msg, respond)) = update_receiver.next().await { | | |
| 262 | if !respond.is_canceled() { | | |
| 263 | let result = cx.background_spawn(Self::process_git_msg(msg)).await; | | |
| 264 | respond.send(result).ok(); | | |
| 265 | } | | |
| 266 | } | 229 | } |
| 267 | }) | 230 | }) |
| 268 | .detach(); | 231 | .detach(); |
| 269 | update_sender | 232 | job_tx |
| 270 | } | | |
| 271 | | | |
| 272 | async fn process_git_msg(msg: Message) -> Result<()> { | | |
| 273 | match msg { | | |
| 274 | Message::Fetch(repo) => { | | |
| 275 | match repo { | | |
| 276 | GitRepo::Local(git_repository) => git_repository.fetch()?, | | |
| 277 | GitRepo::Remote { | | |
| 278 | project_id, | | |
| 279 | client, | | |
| 280 | worktree_id, | | |
| 281 | work_directory_id, | | |
| 282 | } => { | | |
| 283 | client | | |
| 284 | .request(proto::Fetch { | | |
| 285 | project_id: project_id.0, | | |
| 286 | worktree_id: worktree_id.to_proto(), | | |
| 287 | work_directory_id: work_directory_id.to_proto(), | | |
| 288 | }) | | |
| 289 | .await | | |
| 290 | .context("sending fetch request")?; | | |
| 291 | } | | |
| 292 | } | | |
| 293 | Ok(()) | | |
| 294 | } | | |
| 295 | | | |
| 296 | Message::Pull { | | |
| 297 | repo, | | |
| 298 | branch_name, | | |
| 299 | remote_name, | | |
| 300 | } => { | | |
| 301 | match repo { | | |
| 302 | GitRepo::Local(git_repository) => { | | |
| 303 | git_repository.pull(&branch_name, &remote_name)? | | |
| 304 | } | | |
| 305 | GitRepo::Remote { | | |
| 306 | project_id, | | |
| 307 | client, | | |
| 308 | worktree_id, | | |
| 309 | work_directory_id, | | |
| 310 | } => { | | |
| 311 | client | | |
| 312 | .request(proto::Pull { | | |
| 313 | project_id: project_id.0, | | |
| 314 | worktree_id: worktree_id.to_proto(), | | |
| 315 | work_directory_id: work_directory_id.to_proto(), | | |
| 316 | branch_name: branch_name.to_string(), | | |
| 317 | remote_name: remote_name.to_string(), | | |
| 318 | }) | | |
| 319 | .await | | |
| 320 | .context("sending pull request")?; | | |
| 321 | } | | |
| 322 | } | | |
| 323 | Ok(()) | | |
| 324 | } | | |
| 325 | Message::Push { | | |
| 326 | repo, | | |
| 327 | branch_name, | | |
| 328 | remote_name, | | |
| 329 | options, | | |
| 330 | } => { | | |
| 331 | match repo { | | |
| 332 | GitRepo::Local(git_repository) => { | | |
| 333 | git_repository.push(&branch_name, &remote_name, options)? | | |
| 334 | } | | |
| 335 | GitRepo::Remote { | | |
| 336 | project_id, | | |
| 337 | client, | | |
| 338 | worktree_id, | | |
| 339 | work_directory_id, | | |
| 340 | } => { | | |
| 341 | client | | |
| 342 | .request(proto::Push { | | |
| 343 | project_id: project_id.0, | | |
| 344 | worktree_id: worktree_id.to_proto(), | | |
| 345 | work_directory_id: work_directory_id.to_proto(), | | |
| 346 | branch_name: branch_name.to_string(), | | |
| 347 | remote_name: remote_name.to_string(), | | |
| 348 | options: options.map(|options| match options { | | |
| 349 | PushOptions::Force => proto::push::PushOptions::Force, | | |
| 350 | PushOptions::SetUpstream => { | | |
| 351 | proto::push::PushOptions::SetUpstream | | |
| 352 | } | | |
| 353 | } | | |
| 354 | as i32), | | |
| 355 | }) | | |
| 356 | .await | | |
| 357 | .context("sending push request")?; | | |
| 358 | } | | |
| 359 | } | | |
| 360 | Ok(()) | | |
| 361 | } | | |
| 362 | Message::Stage(repo, paths) => { | | |
| 363 | match repo { | | |
| 364 | GitRepo::Local(repo) => repo.stage_paths(&paths)?, | | |
| 365 | GitRepo::Remote { | | |
| 366 | project_id, | | |
| 367 | client, | | |
| 368 | worktree_id, | | |
| 369 | work_directory_id, | | |
| 370 | } => { | | |
| 371 | client | | |
| 372 | .request(proto::Stage { | | |
| 373 | project_id: project_id.0, | | |
| 374 | worktree_id: worktree_id.to_proto(), | | |
| 375 | work_directory_id: work_directory_id.to_proto(), | | |
| 376 | paths: paths | | |
| 377 | .into_iter() | | |
| 378 | .map(|repo_path| repo_path.as_ref().to_proto()) | | |
| 379 | .collect(), | | |
| 380 | }) | | |
| 381 | .await | | |
| 382 | .context("sending stage request")?; | | |
| 383 | } | | |
| 384 | } | | |
| 385 | Ok(()) | | |
| 386 | } | | |
| 387 | Message::Reset { | | |
| 388 | repo, | | |
| 389 | commit, | | |
| 390 | reset_mode, | | |
| 391 | } => { | | |
| 392 | match repo { | | |
| 393 | GitRepo::Local(repo) => repo.reset(&commit, reset_mode)?, | | |
| 394 | GitRepo::Remote { | | |
| 395 | project_id, | | |
| 396 | client, | | |
| 397 | worktree_id, | | |
| 398 | work_directory_id, | | |
| 399 | } => { | | |
| 400 | client | | |
| 401 | .request(proto::GitReset { | | |
| 402 | project_id: project_id.0, | | |
| 403 | worktree_id: worktree_id.to_proto(), | | |
| 404 | work_directory_id: work_directory_id.to_proto(), | | |
| 405 | commit: commit.into(), | | |
| 406 | mode: match reset_mode { | | |
| 407 | ResetMode::Soft => git_reset::ResetMode::Soft.into(), | | |
| 408 | ResetMode::Mixed => git_reset::ResetMode::Mixed.into(), | | |
| 409 | }, | | |
| 410 | }) | | |
| 411 | .await?; | | |
| 412 | } | | |
| 413 | } | | |
| 414 | Ok(()) | | |
| 415 | } | | |
| 416 | | | |
| 417 | Message::CheckoutFiles { | | |
| 418 | repo, | | |
| 419 | commit, | | |
| 420 | paths, | | |
| 421 | } => { | | |
| 422 | match repo { | | |
| 423 | GitRepo::Local(repo) => repo.checkout_files(&commit, &paths)?, | | |
| 424 | GitRepo::Remote { | | |
| 425 | project_id, | | |
| 426 | client, | | |
| 427 | worktree_id, | | |
| 428 | work_directory_id, | | |
| 429 | } => { | | |
| 430 | client | | |
| 431 | .request(proto::GitCheckoutFiles { | | |
| 432 | project_id: project_id.0, | | |
| 433 | worktree_id: worktree_id.to_proto(), | | |
| 434 | work_directory_id: work_directory_id.to_proto(), | | |
| 435 | commit: commit.into(), | | |
| 436 | paths: paths | | |
| 437 | .into_iter() | | |
| 438 | .map(|p| p.to_string_lossy().to_string()) | | |
| 439 | .collect(), | | |
| 440 | }) | | |
| 441 | .await?; | | |
| 442 | } | | |
| 443 | } | | |
| 444 | Ok(()) | | |
| 445 | } | | |
| 446 | Message::Unstage(repo, paths) => { | | |
| 447 | match repo { | | |
| 448 | GitRepo::Local(repo) => repo.unstage_paths(&paths)?, | | |
| 449 | GitRepo::Remote { | | |
| 450 | project_id, | | |
| 451 | client, | | |
| 452 | worktree_id, | | |
| 453 | work_directory_id, | | |
| 454 | } => { | | |
| 455 | client | | |
| 456 | .request(proto::Unstage { | | |
| 457 | project_id: project_id.0, | | |
| 458 | worktree_id: worktree_id.to_proto(), | | |
| 459 | work_directory_id: work_directory_id.to_proto(), | | |
| 460 | paths: paths | | |
| 461 | .into_iter() | | |
| 462 | .map(|repo_path| repo_path.as_ref().to_proto()) | | |
| 463 | .collect(), | | |
| 464 | }) | | |
| 465 | .await | | |
| 466 | .context("sending unstage request")?; | | |
| 467 | } | | |
| 468 | } | | |
| 469 | Ok(()) | | |
| 470 | } | | |
| 471 | Message::Commit { | | |
| 472 | git_repo, | | |
| 473 | message, | | |
| 474 | name_and_email, | | |
| 475 | } => { | | |
| 476 | match git_repo { | | |
| 477 | GitRepo::Local(repo) => repo.commit( | | |
| 478 | message.as_ref(), | | |
| 479 | name_and_email | | |
| 480 | .as_ref() | | |
| 481 | .map(|(name, email)| (name.as_ref(), email.as_ref())), | | |
| 482 | )?, | | |
| 483 | GitRepo::Remote { | | |
| 484 | project_id, | | |
| 485 | client, | | |
| 486 | worktree_id, | | |
| 487 | work_directory_id, | | |
| 488 | } => { | | |
| 489 | let (name, email) = name_and_email.unzip(); | | |
| 490 | client | | |
| 491 | .request(proto::Commit { | | |
| 492 | project_id: project_id.0, | | |
| 493 | worktree_id: worktree_id.to_proto(), | | |
| 494 | work_directory_id: work_directory_id.to_proto(), | | |
| 495 | message: String::from(message), | | |
| 496 | name: name.map(String::from), | | |
| 497 | email: email.map(String::from), | | |
| 498 | }) | | |
| 499 | .await | | |
| 500 | .context("sending commit request")?; | | |
| 501 | } | | |
| 502 | } | | |
| 503 | Ok(()) | | |
| 504 | } | | |
| 505 | Message::SetIndexText(git_repo, path, text) => match git_repo { | | |
| 506 | GitRepo::Local(repo) => repo.set_index_text(&path, text), | | |
| 507 | GitRepo::Remote { | | |
| 508 | project_id, | | |
| 509 | client, | | |
| 510 | worktree_id, | | |
| 511 | work_directory_id, | | |
| 512 | } => client.send(proto::SetIndexText { | | |
| 513 | project_id: project_id.0, | | |
| 514 | worktree_id: worktree_id.to_proto(), | | |
| 515 | work_directory_id: work_directory_id.to_proto(), | | |
| 516 | path: path.as_ref().to_proto(), | | |
| 517 | text, | | |
| 518 | }), | | |
| 519 | }, | | |
| 520 | } | | |
| 521 | } | 233 | } |
| 522 | | 234 | |
| 523 | async fn handle_fetch( | 235 | async fn handle_fetch( |
| @@ -696,10 +408,10 @@ impl GitStore { · 172 unmodified lines |
| 696 | let branch_name = envelope.payload.branch_name; | 408 | let branch_name = envelope.payload.branch_name; |
| 697 | | 409 | |
| 698 | let remotes = repository_handle | 410 | let remotes = repository_handle |
| 699 | .update(&mut cx, |repository_handle, cx| { | 411 | .update(&mut cx, |repository_handle, _| { |
| 700 | repository_handle.get_remotes(branch_name, cx) | 412 | repository_handle.get_remotes(branch_name) |
| 701 | })? | 413 | })? |
| 702 | .await?; | 414 | .await??; |
| 703 | | 415 | |
| 704 | Ok(proto::GetRemotesResponse { | 416 | Ok(proto::GetRemotesResponse { |
| 705 | remotes: remotes | 417 | remotes: remotes |
| @@ -722,10 +434,10 @@ impl GitStore { · 16 unmodified lines |
| 722 | Self::repository_for_request(&this, worktree_id, work_directory_id, &mut cx)?; | 434 | Self::repository_for_request(&this, worktree_id, work_directory_id, &mut cx)?; |
| 723 | | 435 | |
| 724 | let commit = repository_handle | 436 | let commit = repository_handle |
| 725 | .update(&mut cx, |repository_handle, cx| { | 437 | .update(&mut cx, |repository_handle, _| { |
| 726 | repository_handle.show(&envelope.payload.commit, cx) | 438 | repository_handle.show(&envelope.payload.commit) |
| 727 | })? | 439 | })? |
| 728 | .await?; | 440 | .await??; |
| 729 | Ok(proto::GitCommitDetails { | 441 | Ok(proto::GitCommitDetails { |
| 730 | sha: commit.sha.into(), | 442 | sha: commit.sha.into(), |
| 731 | message: commit.message.into(), | 443 | message: commit.message.into(), |
| @@ -854,6 +566,26 @@ impl Repository { · 122 unmodified lines |
| 854 | self.repository_entry.branch() | 566 | self.repository_entry.branch() |
| 855 | } | 567 | } |
| 856 | | 568 | |
| | 569 | fn send_job<F, Fut, R>(&self, job: F) -> oneshot::Receiver<R> |
| | 570 | where |
| | 571 | F: FnOnce(GitRepo) -> Fut + 'static, |
| | 572 | Fut: Future<Output = R> + Send + 'static, |
| | 573 | R: Send + 'static, |
| | 574 | { |
| | 575 | let (result_tx, result_rx) = futures::channel::oneshot::channel(); |
| | 576 | let git_repo = self.git_repo.clone(); |
| | 577 | self.job_sender |
| | 578 | .unbounded_send(Box::new(|cx: &mut AsyncApp| { |
| | 579 | let job = job(git_repo); |
| | 580 | cx.background_spawn(async move { |
| | 581 | let result = job.await; |
| | 582 | result_tx.send(result).ok(); |
| | 583 | }) |
| | 584 | })) |
| | 585 | .ok(); |
| | 586 | result_rx |
| | 587 | } |
| | 588 | |
| 857 | pub fn display_name(&self, project: &Project, cx: &App) -> SharedString { | 589 | pub fn display_name(&self, project: &Project, cx: &App) -> SharedString { |
| 858 | maybe!({ | 590 | maybe!({ |
| 859 | let project_path = self.repo_path_to_project_path(&"".into())?; | 591 | let project_path = self.repo_path_to_project_path(&"".into())?; |
| @@ -1004,60 +736,106 @@ impl Repository { · 144 unmodified lines |
| 1004 | commit: &str, | 736 | commit: &str, |
| 1005 | paths: Vec<RepoPath>, | 737 | paths: Vec<RepoPath>, |
| 1006 | ) -> oneshot::Receiver<Result<()>> { | 738 | ) -> oneshot::Receiver<Result<()>> { |
| 1007 | self.send_message(Message::CheckoutFiles { | 739 | let commit = commit.to_string(); |
| 1008 | repo: self.git_repo.clone(), | 740 | self.send_job(|git_repo| async move { |
| 1009 | commit: commit.to_string().into(), | 741 | match git_repo { |
| 1010 | paths, | 742 | GitRepo::Local(repo) => repo.checkout_files(&commit, &paths), |
| | 743 | GitRepo::Remote { |
| | 744 | project_id, |
| | 745 | client, |
| | 746 | worktree_id, |
| | 747 | work_directory_id, |
| | 748 | } => { |
| | 749 | client |
| | 750 | .request(proto::GitCheckoutFiles { |
| | 751 | project_id: project_id.0, |
| | 752 | worktree_id: worktree_id.to_proto(), |
| | 753 | work_directory_id: work_directory_id.to_proto(), |
| | 754 | commit, |
| | 755 | paths: paths |
| | 756 | .into_iter() |
| | 757 | .map(|p| p.to_string_lossy().to_string()) |
| | 758 | .collect(), |
| | 759 | }) |
| | 760 | .await?; |
| | 761 | |
| | 762 | Ok(()) |
| | 763 | } |
| | 764 | } |
| 1011 | }) | 765 | }) |
| 1012 | } | 766 | } |
| 1013 | | 767 | |
| 1014 | pub fn reset(&self, commit: &str, reset_mode: ResetMode) -> oneshot::Receiver<Result<()>> { | 768 | pub fn reset(&self, commit: &str, reset_mode: ResetMode) -> oneshot::Receiver<Result<()>> { |
| 1015 | self.send_message(Message::Reset { | 769 | let commit = commit.to_string(); |
| 1016 | repo: self.git_repo.clone(), | 770 | self.send_job(|git_repo| async move { |
| 1017 | commit: commit.to_string().into(), | 771 | match git_repo { |
| 1018 | reset_mode, | 772 | GitRepo::Local(git_repo) => git_repo.reset(&commit, reset_mode), |
| | 773 | GitRepo::Remote { |
| | 774 | project_id, |
| | 775 | client, |
| | 776 | worktree_id, |
| | 777 | work_directory_id, |
| | 778 | } => { |
| | 779 | client |
| | 780 | .request(proto::GitReset { |
| | 781 | project_id: project_id.0, |
| | 782 | worktree_id: worktree_id.to_proto(), |
| | 783 | work_directory_id: work_directory_id.to_proto(), |
| | 784 | commit, |
| | 785 | mode: match reset_mode { |
| | 786 | ResetMode::Soft => git_reset::ResetMode::Soft.into(), |
| | 787 | ResetMode::Mixed => git_reset::ResetMode::Mixed.into(), |
| | 788 | }, |
| | 789 | }) |
| | 790 | .await?; |
| | 791 | |
| | 792 | Ok(()) |
| | 793 | } |
| | 794 | } |
| 1019 | }) | 795 | }) |
| 1020 | } | 796 | } |
| 1021 | | 797 | |
| 1022 | pub fn show(&self, commit: &str, cx: &Context<Self>) -> Task<Result<CommitDetails>> { | 798 | pub fn show(&self, commit: &str) -> oneshot::Receiver<Result<CommitDetails>> { |
| 1023 | let commit = commit.to_string(); | 799 | let commit = commit.to_string(); |
| 1024 | match self.git_repo.clone() { | 800 | self.send_job(|git_repo| async move { |
| 1025 | GitRepo::Local(git_repository) => { | 801 | match git_repo { |
| 1026 | let commit = commit.to_string(); | 802 | GitRepo::Local(git_repository) => git_repository.show(&commit), |
| 1027 | cx.background_spawn(async move { git_repository.show(&commit) }) | 803 | GitRepo::Remote { |
| 1028 | } | 804 | project_id, |
| 1029 | GitRepo::Remote { | 805 | client, |
| 1030 | project_id, | 806 | worktree_id, |
| 1031 | client, | 807 | work_directory_id, |
| 1032 | worktree_id, | 808 | } => { |
| 1033 | work_directory_id, | 809 | let resp = client |
| 1034 | } => cx.background_spawn(async move { | 810 | .request(proto::GitShow { |
| 1035 | let resp = client | 811 | project_id: project_id.0, |
| 1036 | .request(proto::GitShow { | 812 | worktree_id: worktree_id.to_proto(), |
| 1037 | project_id: project_id.0, | 813 | work_directory_id: work_directory_id.to_proto(), |
| 1038 | worktree_id: worktree_id.to_proto(), | 814 | commit, |
| 1039 | work_directory_id: work_directory_id.to_proto(), | 815 | }) |
| 1040 | commit, | 816 | .await?; |
| | 817 | |
| | 818 | Ok(CommitDetails { |
| | 819 | sha: resp.sha.into(), |
| | 820 | message: resp.message.into(), |
| | 821 | commit_timestamp: resp.commit_timestamp, |
| | 822 | committer_email: resp.committer_email.into(), |
| | 823 | committer_name: resp.committer_name.into(), |
| 1041 | }) | 824 | }) |
| 1042 | .await?; | 825 | } |
| 1043 | | 826 | } |
| 1044 | Ok(CommitDetails { | 827 | }) |
| 1045 | sha: resp.sha.into(), | | |
| 1046 | message: resp.message.into(), | | |
| 1047 | commit_timestamp: resp.commit_timestamp, | | |
| 1048 | committer_email: resp.committer_email.into(), | | |
| 1049 | committer_name: resp.committer_name.into(), | | |
| 1050 | }) | | |
| 1051 | }), | | |
| 1052 | } | | |
| 1053 | } | 828 | } |
| 1054 | | 829 | |
| 1055 | fn buffer_store(&self, cx: &App) -> Option<Entity<BufferStore>> { | 830 | fn buffer_store(&self, cx: &App) -> Option<Entity<BufferStore>> { |
| 1056 | Some(self.git_store.upgrade()?.read(cx).buffer_store.clone()) | 831 | Some(self.git_store.upgrade()?.read(cx).buffer_store.clone()) |
| 1057 | } | 832 | } |
| 1058 | | 833 | |
| 1059 | pub fn stage_entries(&self, entries: Vec<RepoPath>, cx: &mut App) -> Task<anyhow::Result<()>> { | 834 | pub fn stage_entries( |
| 1060 | let (result_tx, result_rx) = futures::channel::oneshot::channel(); | 835 | &self, |
| | 836 | entries: Vec<RepoPath>, |
| | 837 | cx: &mut Context<Self>, |
| | 838 | ) -> Task<anyhow::Result<()>> { |
| 1061 | if entries.is_empty() { | 839 | if entries.is_empty() { |
| 1062 | return Task::ready(Ok(())); | 840 | return Task::ready(Ok(())); |
| 1063 | } | 841 | } |
| @@ -1083,16 +861,41 @@ impl Repository { · 19 unmodified lines |
| 1083 | }) | 861 | }) |
| 1084 | } | 862 | } |
| 1085 | | 863 | |
| 1086 | let update_sender = self.update_sender.clone(); | 864 | cx.spawn(|this, mut cx| async move { |
| 1087 | let git_repo = self.git_repo.clone(); | | |
| 1088 | cx.spawn(|_| async move { | | |
| 1089 | for save_future in save_futures { | 865 | for save_future in save_futures { |
| 1090 | save_future.await?; | 866 | save_future.await?; |
| 1091 | } | 867 | } |
| 1092 | update_sender | 868 | |
| 1093 | .unbounded_send((Message::Stage(git_repo, entries), result_tx)) | 869 | this.update(&mut cx, |this, _| { |
| 1094 | .ok(); | 870 | this.send_job(|git_repo| async move { |
| 1095 | result_rx.await.anyhow()??; | 871 | match git_repo { |
| | 872 | GitRepo::Local(repo) => repo.stage_paths(&entries), |
| | 873 | GitRepo::Remote { |
| | 874 | project_id, |
| | 875 | client, |
| | 876 | worktree_id, |
| | 877 | work_directory_id, |
| | 878 | } => { |
| | 879 | client |
| | 880 | .request(proto::Stage { |
| | 881 | project_id: project_id.0, |
| | 882 | worktree_id: worktree_id.to_proto(), |
| | 883 | work_directory_id: work_directory_id.to_proto(), |
| | 884 | paths: entries |
| | 885 | .into_iter() |
| | 886 | .map(|repo_path| repo_path.as_ref().to_proto()) |
| | 887 | .collect(), |
| | 888 | }) |
| | 889 | .await |
| | 890 | .context("sending stage request")?; |
| | 891 | |
| | 892 | Ok(()) |
| | 893 | } |
| | 894 | } |
| | 895 | }) |
| | 896 | })? |
| | 897 | .await??; |
| | 898 | |
| 1096 | Ok(()) | 899 | Ok(()) |
| 1097 | }) | 900 | }) |
| 1098 | } | 901 | } |
| @@ -1100,9 +903,8 @@ impl Repository { · 1 unmodified line |
| 1100 | pub fn unstage_entries( | 903 | pub fn unstage_entries( |
| 1101 | &self, | 904 | &self, |
| 1102 | entries: Vec<RepoPath>, | 905 | entries: Vec<RepoPath>, |
| 1103 | cx: &mut App, | 906 | cx: &mut Context<Self>, |
| 1104 | ) -> Task<anyhow::Result<()>> { | 907 | ) -> Task<anyhow::Result<()>> { |
| 1105 | let (result_tx, result_rx) = futures::channel::oneshot::channel(); | | |
| 1106 | if entries.is_empty() { | 908 | if entries.is_empty() { |
| 1107 | return Task::ready(Ok(())); | 909 | return Task::ready(Ok(())); |
| 1108 | } | 910 | } |
| @@ -1128,21 +930,46 @@ impl Repository { · 19 unmodified lines |
| 1128 | }) | 930 | }) |
| 1129 | } | 931 | } |
| 1130 | | 932 | |
| 1131 | let update_sender = self.update_sender.clone(); | 933 | cx.spawn(move |this, mut cx| async move { |
| 1132 | let git_repo = self.git_repo.clone(); | | |
| 1133 | cx.spawn(|_| async move { | | |
| 1134 | for save_future in save_futures { | 934 | for save_future in save_futures { |
| 1135 | save_future.await?; | 935 | save_future.await?; |
| 1136 | } | 936 | } |
| 1137 | update_sender | 937 | |
| 1138 | .unbounded_send((Message::Unstage(git_repo, entries), result_tx)) | 938 | this.update(&mut cx, |this, _| { |
| 1139 | .ok(); | 939 | this.send_job(|git_repo| async move { |
| 1140 | result_rx.await.anyhow()??; | 940 | match git_repo { |
| | 941 | GitRepo::Local(repo) => repo.unstage_paths(&entries), |
| | 942 | GitRepo::Remote { |
| | 943 | project_id, |
| | 944 | client, |
| | 945 | worktree_id, |
| | 946 | work_directory_id, |
| | 947 | } => { |
| | 948 | client |
| | 949 | .request(proto::Unstage { |
| | 950 | project_id: project_id.0, |
| | 951 | worktree_id: worktree_id.to_proto(), |
| | 952 | work_directory_id: work_directory_id.to_proto(), |
| | 953 | paths: entries |
| | 954 | .into_iter() |
| | 955 | .map(|repo_path| repo_path.as_ref().to_proto()) |
| | 956 | .collect(), |
| | 957 | }) |
| | 958 | .await |
| | 959 | .context("sending unstage request")?; |
| | 960 | |
| | 961 | Ok(()) |
| | 962 | } |
| | 963 | } |
| | 964 | }) |
| | 965 | })? |
| | 966 | .await??; |
| | 967 | |
| 1141 | Ok(()) | 968 | Ok(()) |
| 1142 | }) | 969 | }) |
| 1143 | } | 970 | } |
| 1144 | | 971 | |
| 1145 | pub fn stage_all(&self, cx: &mut App) -> Task<anyhow::Result<()>> { | 972 | pub fn stage_all(&self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> { |
| 1146 | let to_stage = self | 973 | let to_stage = self |
| 1147 | .repository_entry | 974 | .repository_entry |
| 1148 | .status() | 975 | .status() |
| @@ -1152,7 +979,7 @@ impl Repository { · 3 unmodified lines |
| 1152 | self.stage_entries(to_stage, cx) | 979 | self.stage_entries(to_stage, cx) |
| 1153 | } | 980 | } |
| 1154 | | 981 | |
| 1155 | pub fn unstage_all(&self, cx: &mut App) -> Task<anyhow::Result<()>> { | 982 | pub fn unstage_all(&self, cx: &mut Context<Self>) -> Task<anyhow::Result<()>> { |
| 1156 | let to_unstage = self | 983 | let to_unstage = self |
| 1157 | .repository_entry | 984 | .repository_entry |
| 1158 | .status() | 985 | .status() |
| @@ -1185,15 +1012,62 @@ impl Repository { · 26 unmodified lines |
| 1185 | message: SharedString, | 1012 | message: SharedString, |
| 1186 | name_and_email: Option<(SharedString, SharedString)>, | 1013 | name_and_email: Option<(SharedString, SharedString)>, |
| 1187 | ) -> oneshot::Receiver<Result<()>> { | 1014 | ) -> oneshot::Receiver<Result<()>> { |
| 1188 | self.send_message(Message::Commit { | 1015 | self.send_job(|git_repo| async move { |
| 1189 | git_repo: self.git_repo.clone(), | 1016 | match git_repo { |
| 1190 | message, | 1017 | GitRepo::Local(repo) => repo.commit( |
| 1191 | name_and_email, | 1018 | message.as_ref(), |
| | 1019 | name_and_email |
| | 1020 | .as_ref() |
| | 1021 | .map(|(name, email)| (name.as_ref(), email.as_ref())), |
| | 1022 | ), |
| | 1023 | GitRepo::Remote { |
| | 1024 | project_id, |
| | 1025 | client, |
| | 1026 | worktree_id, |
| | 1027 | work_directory_id, |
| | 1028 | } => { |
| | 1029 | let (name, email) = name_and_email.unzip(); |
| | 1030 | client |
| | 1031 | .request(proto::Commit { |
| | 1032 | project_id: project_id.0, |
| | 1033 | worktree_id: worktree_id.to_proto(), |
| | 1034 | work_directory_id: work_directory_id.to_proto(), |
| | 1035 | message: String::from(message), |
| | 1036 | name: name.map(String::from), |
| | 1037 | email: email.map(String::from), |
| | 1038 | }) |
| | 1039 | .await |
| | 1040 | .context("sending commit request")?; |
| | 1041 | |
| | 1042 | Ok(()) |
| | 1043 | } |
| | 1044 | } |
| 1192 | }) | 1045 | }) |
| 1193 | } | 1046 | } |
| 1194 | | 1047 | |
| 1195 | pub fn fetch(&self) -> oneshot::Receiver<Result<()>> { | 1048 | pub fn fetch(&self) -> oneshot::Receiver<Result<()>> { |
| 1196 | self.send_message(Message::Fetch(self.git_repo.clone())) | 1049 | self.send_job(|git_repo| async move { |
| | 1050 | match git_repo { |
| | 1051 | GitRepo::Local(git_repository) => git_repository.fetch(), |
| | 1052 | GitRepo::Remote { |
| | 1053 | project_id, |
| | 1054 | client, |
| | 1055 | worktree_id, |
| | 1056 | work_directory_id, |
| | 1057 | } => { |
| | 1058 | client |
| | 1059 | .request(proto::Fetch { |
| | 1060 | project_id: project_id.0, |
| | 1061 | worktree_id: worktree_id.to_proto(), |
| | 1062 | work_directory_id: work_directory_id.to_proto(), |
| | 1063 | }) |
| | 1064 | .await |
| | 1065 | .context("sending fetch request")?; |
| | 1066 | |
| | 1067 | Ok(()) |
| | 1068 | } |
| | 1069 | } |
| | 1070 | }) |
| 1197 | } | 1071 | } |
| 1198 | | 1072 | |
| 1199 | pub fn push( | 1073 | pub fn push( |
| @@ -1202,11 +1076,33 @@ impl Repository { · 2 unmodified lines |
| 1202 | remote: SharedString, | 1076 | remote: SharedString, |
| 1203 | options: Option<PushOptions>, | 1077 | options: Option<PushOptions>, |
| 1204 | ) -> oneshot::Receiver<Result<()>> { | 1078 | ) -> oneshot::Receiver<Result<()>> { |
| 1205 | self.send_message(Message::Push { | 1079 | self.send_job(move |git_repo| async move { |
| 1206 | repo: self.git_repo.clone(), | 1080 | match git_repo { |
| 1207 | branch_name: branch, | 1081 | GitRepo::Local(git_repository) => git_repository.push(&branch, &remote, options), |
| 1208 | remote_name: remote, | 1082 | GitRepo::Remote { |
| 1209 | options, | 1083 | project_id, |
| | 1084 | client, |
| | 1085 | worktree_id, |
| | 1086 | work_directory_id, |
| | 1087 | } => { |
| | 1088 | client |
| | 1089 | .request(proto::Push { |
| | 1090 | project_id: project_id.0, |
| | 1091 | worktree_id: worktree_id.to_proto(), |
| | 1092 | work_directory_id: work_directory_id.to_proto(), |
| | 1093 | branch_name: branch.to_string(), |
| | 1094 | remote_name: remote.to_string(), |
| | 1095 | options: options.map(|options| match options { |
| | 1096 | PushOptions::Force => proto::push::PushOptions::Force, |
| | 1097 | PushOptions::SetUpstream => proto::push::PushOptions::SetUpstream, |
| | 1098 | } as i32), |
| | 1099 | }) |
| | 1100 | .await |
| | 1101 | .context("sending push request")?; |
| | 1102 | |
| | 1103 | Ok(()) |
| | 1104 | } |
| | 1105 | } |
| 1210 | }) | 1106 | }) |
| 1211 | } | 1107 | } |
| 1212 | | 1108 | |
| @@ -1215,10 +1111,30 @@ impl Repository { · 2 unmodified lines |
| 1215 | branch: SharedString, | 1111 | branch: SharedString, |
| 1216 | remote: SharedString, | 1112 | remote: SharedString, |
| 1217 | ) -> oneshot::Receiver<Result<()>> { | 1113 | ) -> oneshot::Receiver<Result<()>> { |
| 1218 | self.send_message(Message::Pull { | 1114 | self.send_job(|git_repo| async move { |
| 1219 | repo: self.git_repo.clone(), | 1115 | match git_repo { |
| 1220 | branch_name: branch, | 1116 | GitRepo::Local(git_repository) => git_repository.pull(&branch, &remote), |
| 1221 | remote_name: remote, | 1117 | GitRepo::Remote { |
| | 1118 | project_id, |
| | 1119 | client, |
| | 1120 | worktree_id, |
| | 1121 | work_directory_id, |
| | 1122 | } => { |
| | 1123 | client |
| | 1124 | .request(proto::Pull { |
| | 1125 | project_id: project_id.0, |
| | 1126 | worktree_id: worktree_id.to_proto(), |
| | 1127 | work_directory_id: work_directory_id.to_proto(), |
| | 1128 | branch_name: branch.to_string(), |
| | 1129 | remote_name: remote.to_string(), |
| | 1130 | }) |
| | 1131 | .await |
| | 1132 | .context("sending pull request")?; |
| | 1133 | |
| | 1134 | // TODO: wire through remote |
| | 1135 | Ok(()) |
| | 1136 | } |
| | 1137 | } |
| 1222 | }) | 1138 | }) |
| 1223 | } | 1139 | } |
| 1224 | | 1140 | |
| @@ -1227,49 +1143,66 @@ impl Repository { · 2 unmodified lines |
| 1227 | path: &RepoPath, | 1143 | path: &RepoPath, |
| 1228 | content: Option<String>, | 1144 | content: Option<String>, |
| 1229 | ) -> oneshot::Receiver<anyhow::Result<()>> { | 1145 | ) -> oneshot::Receiver<anyhow::Result<()>> { |
| 1230 | self.send_message(Message::SetIndexText( | 1146 | let path = path.clone(); |
| 1231 | self.git_repo.clone(), | 1147 | self.send_job(|git_repo| async move { |
| 1232 | path.clone(), | 1148 | match git_repo { |
| 1233 | content, | 1149 | GitRepo::Local(repo) => repo.set_index_text(&path, content), |
| 1234 | )) | 1150 | GitRepo::Remote { |
| 1235 | } | 1151 | project_id, |
| 1236 | | 1152 | client, |
| 1237 | pub fn get_remotes(&self, branch_name: Option<String>, cx: &App) -> Task<Result<Vec<Remote>>> { | 1153 | worktree_id, |
| 1238 | match self.git_repo.clone() { | 1154 | work_directory_id, |
| 1239 | GitRepo::Local(git_repository) => { | 1155 | } => { |
| 1240 | cx.background_spawn( | 1156 | client |
| 1241 | async move { git_repository.get_remotes(branch_name.as_deref()) }, | 1157 | .request(proto::SetIndexText { |
| 1242 | ) | 1158 | project_id: project_id.0, |
| | 1159 | worktree_id: worktree_id.to_proto(), |
| | 1160 | work_directory_id: work_directory_id.to_proto(), |
| | 1161 | path: path.as_ref().to_proto(), |
| | 1162 | text: content, |
| | 1163 | }) |
| | 1164 | .await?; |
| | 1165 | Ok(()) |
| | 1166 | } |
| 1243 | } | 1167 | } |
| 1244 | GitRepo::Remote { | 1168 | }) |
| 1245 | project_id, | | |
| 1246 | client, | | |
| 1247 | worktree_id, | | |
| 1248 | work_directory_id, | | |
| 1249 | } => cx.background_spawn(async move { | | |
| 1250 | let response = client | | |
| 1251 | .request(proto::GetRemotes { | | |
| 1252 | project_id: project_id.0, | | |
| 1253 | worktree_id: worktree_id.to_proto(), | | |
| 1254 | work_directory_id: work_directory_id.to_proto(), | | |
| 1255 | branch_name, | | |
| 1256 | }) | | |
| 1257 | .await?; | | |
| 1258 | | | |
| 1259 | Ok(response | | |
| 1260 | .remotes | | |
| 1261 | .into_iter() | | |
| 1262 | .map(|remotes| git::repository::Remote { | | |
| 1263 | name: remotes.name.into(), | | |
| 1264 | }) | | |
| 1265 | .collect()) | | |
| 1266 | }), | | |
| 1267 | } | | |
| 1268 | } | 1169 | } |
| 1269 | | 1170 | |
| 1270 | fn send_message(&self, message: Message) -> oneshot::Receiver<anyhow::Result<()>> { | 1171 | pub fn get_remotes( |
| 1271 | let (result_tx, result_rx) = futures::channel::oneshot::channel(); | 1172 | &self, |
| 1272 | self.update_sender.unbounded_send((message, result_tx)).ok(); | 1173 | branch_name: Option<String>, |
| 1273 | result_rx | 1174 | ) -> oneshot::Receiver<Result<Vec<Remote>>> { |
| | 1175 | self.send_job(|repo| async move { |
| | 1176 | match repo { |
| | 1177 | GitRepo::Local(git_repository) => { |
| | 1178 | git_repository.get_remotes(branch_name.as_deref()) |
| | 1179 | } |
| | 1180 | GitRepo::Remote { |
| | 1181 | project_id, |
| | 1182 | client, |
| | 1183 | worktree_id, |
| | 1184 | work_directory_id, |
| | 1185 | } => { |
| | 1186 | let response = client |
| | 1187 | .request(proto::GetRemotes { |
| | 1188 | project_id: project_id.0, |
| | 1189 | worktree_id: worktree_id.to_proto(), |
| | 1190 | work_directory_id: work_directory_id.to_proto(), |
| | 1191 | branch_name, |
| | 1192 | }) |
| | 1193 | .await?; |
| | 1194 | |
| | 1195 | let remotes = response |
| | 1196 | .remotes |
| | 1197 | .into_iter() |
| | 1198 | .map(|remotes| git::repository::Remote { |
| | 1199 | name: remotes.name.into(), |
| | 1200 | }) |
| | 1201 | .collect(); |
| | 1202 | |
| | 1203 | Ok(remotes) |
| | 1204 | } |
| | 1205 | } |
| | 1206 | }) |
| 1274 | } | 1207 | } |
| 1275 | } | 1208 | } |