| @@ -11,26 +11,29 @@ use git::{ · 10 unmodified lines |
| 11 | 11 | status::{GitSummary, TrackedSummary}, |
| 12 | 12 | }; |
| 13 | 13 | use gpui::{ |
| 14 | | − App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, |
| 15 | | − Task, WeakEntity, |
| 14 | + App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Subscription, Task, |
| 15 | + WeakEntity, |
| 16 | 16 | }; |
| 17 | 17 | use language::{Buffer, LanguageRegistry}; |
| 18 | 18 | use rpc::proto::{git_reset, ToProto}; |
| 19 | 19 | use rpc::{proto, AnyProtoClient, TypedEnvelope}; |
| 20 | 20 | use settings::WorktreeId; |
| 21 | +use std::future::Future; |
| 21 | 22 | use std::path::{Path, PathBuf}; |
| 22 | 23 | use std::sync::Arc; |
| 23 | 24 | use text::BufferId; |
| 24 | 25 | use util::{maybe, ResultExt}; |
| 25 | 26 | use worktree::{ProjectEntryId, RepositoryEntry, StatusEntry}; |
| 26 | 27 | |
| 28 | +type GitJob = Box<dyn FnOnce(&mut AsyncApp) -> Task<()>>; |
| 29 | + |
| 27 | 30 | pub struct GitStore { |
| 28 | 31 | buffer_store: Entity<BufferStore>, |
| 29 | 32 | pub(super) project_id: Option<ProjectId>, |
| 30 | 33 | pub(super) client: Option<AnyProtoClient>, |
| 31 | 34 | repositories: Vec<Entity<Repository>>, |
| 32 | 35 | active_index: Option<usize>, |
| 33 | | − update_sender: mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)>, |
| 36 | + update_sender: mpsc::UnboundedSender<GitJob>, |
| 34 | 37 | _subscription: Subscription, |
| 35 | 38 | } |
| 36 | 39 | |
| @@ -41,7 +44,7 @@ pub struct Repository { · 4 unmodified lines |
| 41 | 44 | pub repository_entry: RepositoryEntry, |
| 42 | 45 | pub git_repo: GitRepo, |
| 43 | 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 | 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 | 61 | pub enum GitEvent { |
| 93 | 62 | ActiveRepositoryChanged, |
| 94 | 63 | FileSystemUpdated, |
| @@ -220,7 +189,7 @@ impl GitStore { · 125 unmodified lines |
| 220 | 189 | worktree_id, |
| 221 | 190 | repository_entry: repo.clone(), |
| 222 | 191 | git_repo, |
| 223 | | − update_sender: self.update_sender.clone(), |
| 192 | + job_sender: self.update_sender.clone(), |
| 224 | 193 | merge_message, |
| 225 | 194 | commit_message_buffer: None, |
| 226 | 195 | }) |
| @@ -252,272 +221,15 @@ impl GitStore { · 25 unmodified lines |
| 252 | 221 | self.repositories.clone() |
| 253 | 222 | } |
| 254 | 223 | |
| 255 | | − fn spawn_git_worker( |
| 256 | | − cx: &mut Context<'_, GitStore>, |
| 257 | | − ) -> mpsc::UnboundedSender<(Message, oneshot::Sender<Result<()>>)> { |
| 258 | | − let (update_sender, mut update_receiver) = |
| 259 | | − mpsc::unbounded::<(Message, oneshot::Sender<Result<()>>)>(); |
| 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 | | − } |
| 224 | + fn spawn_git_worker(cx: &mut Context<'_, GitStore>) -> mpsc::UnboundedSender<GitJob> { |
| 225 | + let (job_tx, mut job_rx) = mpsc::unbounded::<GitJob>(); |
| 226 | + cx.spawn(|_, mut cx| async move { |
| 227 | + while let Some(job) = job_rx.next().await { |
| 228 | + job(&mut cx).await |
| 266 | 229 | } |
| 267 | 230 | }) |
| 268 | 231 | .detach(); |
| 269 | | − update_sender |
| 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 | | − } |
| 232 | + job_tx |
| 521 | 233 | } |
| 522 | 234 | |
| 523 | 235 | async fn handle_fetch( |
| @@ -696,10 +408,10 @@ impl GitStore { · 172 unmodified lines |
| 696 | 408 | let branch_name = envelope.payload.branch_name; |
| 697 | 409 | |
| 698 | 410 | let remotes = repository_handle |
| 699 | | − .update(&mut cx, |repository_handle, cx| { |
| 700 | | − repository_handle.get_remotes(branch_name, cx) |
| 411 | + .update(&mut cx, |repository_handle, _| { |
| 412 | + repository_handle.get_remotes(branch_name) |
| 701 | 413 | })? |
| 702 | | − .await?; |
| 414 | + .await??; |
| 703 | 415 | |
| 704 | 416 | Ok(proto::GetRemotesResponse { |
| 705 | 417 | remotes: remotes |
| @@ -722,10 +434,10 @@ impl GitStore { · 16 unmodified lines |
| 722 | 434 | Self::repository_for_request(&this, worktree_id, work_directory_id, &mut cx)?; |
| 723 | 435 | |
| 724 | 436 | let commit = repository_handle |
| 725 | | − .update(&mut cx, |repository_handle, cx| { |
| 726 | | − repository_handle.show(&envelope.payload.commit, cx) |
| 437 | + .update(&mut cx, |repository_handle, _| { |
| 438 | + repository_handle.show(&envelope.payload.commit) |
| 727 | 439 | })? |
| 728 | | − .await?; |
| 440 | + .await??; |
| 729 | 441 | Ok(proto::GitCommitDetails { |
| 730 | 442 | sha: commit.sha.into(), |
| 731 | 443 | message: commit.message.into(), |
| @@ -854,6 +566,26 @@ impl Repository { · 122 unmodified lines |
| 854 | 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 | 589 | pub fn display_name(&self, project: &Project, cx: &App) -> SharedString { |
| 858 | 590 | maybe!({ |
| 859 | 591 | let project_path = self.repo_path_to_project_path(&"".into())?; |
| @@ -1004,60 +736,106 @@ impl Repository { · 144 unmodified lines |
| 1004 | 736 | commit: &str, |
| 1005 | 737 | paths: Vec<RepoPath>, |
| 1006 | 738 | ) -> oneshot::Receiver<Result<()>> { |
| 1007 | | − self.send_message(Message::CheckoutFiles { |
| 1008 | | − repo: self.git_repo.clone(), |
| 1009 | | − commit: commit.to_string().into(), |
| 1010 | | − paths, |
| 739 | + let commit = commit.to_string(); |
| 740 | + self.send_job(|git_repo| async move { |
| 741 | + match git_repo { |
| 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 | 768 | pub fn reset(&self, commit: &str, reset_mode: ResetMode) -> oneshot::Receiver<Result<()>> { |
| 1015 | | − self.send_message(Message::Reset { |
| 1016 | | − repo: self.git_repo.clone(), |
| 1017 | | − commit: commit.to_string().into(), |
| 1018 | | − reset_mode, |
| 769 | + let commit = commit.to_string(); |
| 770 | + self.send_job(|git_repo| async move { |
| 771 | + match git_repo { |
| 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 | 799 | let commit = commit.to_string(); |
| 1024 | | − match self.git_repo.clone() { |
| 1025 | | − GitRepo::Local(git_repository) => { |
| 1026 | | − let commit = commit.to_string(); |
| 1027 | | − cx.background_spawn(async move { git_repository.show(&commit) }) |
| 1028 | | − } |
| 1029 | | − GitRepo::Remote { |
| 1030 | | − project_id, |
| 1031 | | − client, |
| 1032 | | − worktree_id, |
| 1033 | | − work_directory_id, |
| 1034 | | − } => cx.background_spawn(async move { |
| 1035 | | − let resp = client |
| 1036 | | − .request(proto::GitShow { |
| 1037 | | − project_id: project_id.0, |
| 1038 | | − worktree_id: worktree_id.to_proto(), |
| 1039 | | − work_directory_id: work_directory_id.to_proto(), |
| 1040 | | − commit, |
| 800 | + self.send_job(|git_repo| async move { |
| 801 | + match git_repo { |
| 802 | + GitRepo::Local(git_repository) => git_repository.show(&commit), |
| 803 | + GitRepo::Remote { |
| 804 | + project_id, |
| 805 | + client, |
| 806 | + worktree_id, |
| 807 | + work_directory_id, |
| 808 | + } => { |
| 809 | + let resp = client |
| 810 | + .request(proto::GitShow { |
| 811 | + project_id: project_id.0, |
| 812 | + worktree_id: worktree_id.to_proto(), |
| 813 | + work_directory_id: work_directory_id.to_proto(), |
| 814 | + commit, |
| 815 | + }) |
| 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?; |
| 1043 | | − |
| 1044 | | − Ok(CommitDetails { |
| 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 | | − } |
| 825 | + } |
| 826 | + } |
| 827 | + }) |
| 1053 | 828 | } |
| 1054 | 829 | |
| 1055 | 830 | fn buffer_store(&self, cx: &App) -> Option<Entity<BufferStore>> { |
| 1056 | 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<()>> { |
| 1060 | | − let (result_tx, result_rx) = futures::channel::oneshot::channel(); |
| 834 | + pub fn stage_entries( |
| 835 | + &self, |
| 836 | + entries: Vec<RepoPath>, |
| 837 | + cx: &mut Context<Self>, |
| 838 | + ) -> Task<anyhow::Result<()>> { |
| 1061 | 839 | if entries.is_empty() { |
| 1062 | 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(); |
| 1087 | | − let git_repo = self.git_repo.clone(); |
| 1088 | | − cx.spawn(|_| async move { |
| 864 | + cx.spawn(|this, mut cx| async move { |
| 1089 | 865 | for save_future in save_futures { |
| 1090 | 866 | save_future.await?; |
| 1091 | 867 | } |
| 1092 | | − update_sender |
| 1093 | | − .unbounded_send((Message::Stage(git_repo, entries), result_tx)) |
| 1094 | | − .ok(); |
| 1095 | | − result_rx.await.anyhow()??; |
| 868 | + |
| 869 | + this.update(&mut cx, |this, _| { |
| 870 | + this.send_job(|git_repo| async move { |
| 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 | 899 | Ok(()) |
| 1097 | 900 | }) |
| 1098 | 901 | } |
| @@ -1100,9 +903,8 @@ impl Repository { · 1 unmodified line |
| 1100 | 903 | pub fn unstage_entries( |
| 1101 | 904 | &self, |
| 1102 | 905 | entries: Vec<RepoPath>, |
| 1103 | | − cx: &mut App, |
| 906 | + cx: &mut Context<Self>, |
| 1104 | 907 | ) -> Task<anyhow::Result<()>> { |
| 1105 | | − let (result_tx, result_rx) = futures::channel::oneshot::channel(); |
| 1106 | 908 | if entries.is_empty() { |
| 1107 | 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(); |
| 1132 | | − let git_repo = self.git_repo.clone(); |
| 1133 | | − cx.spawn(|_| async move { |
| 933 | + cx.spawn(move |this, mut cx| async move { |
| 1134 | 934 | for save_future in save_futures { |
| 1135 | 935 | save_future.await?; |
| 1136 | 936 | } |
| 1137 | | − update_sender |
| 1138 | | − .unbounded_send((Message::Unstage(git_repo, entries), result_tx)) |
| 1139 | | − .ok(); |
| 1140 | | − result_rx.await.anyhow()??; |
| 937 | + |
| 938 | + this.update(&mut cx, |this, _| { |
| 939 | + this.send_job(|git_repo| async move { |
| 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 | 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 | 973 | let to_stage = self |
| 1147 | 974 | .repository_entry |
| 1148 | 975 | .status() |
| @@ -1152,7 +979,7 @@ impl Repository { · 3 unmodified lines |
| 1152 | 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 | 983 | let to_unstage = self |
| 1157 | 984 | .repository_entry |
| 1158 | 985 | .status() |
| @@ -1185,15 +1012,62 @@ impl Repository { · 26 unmodified lines |
| 1185 | 1012 | message: SharedString, |
| 1186 | 1013 | name_and_email: Option<(SharedString, SharedString)>, |
| 1187 | 1014 | ) -> oneshot::Receiver<Result<()>> { |
| 1188 | | − self.send_message(Message::Commit { |
| 1189 | | − git_repo: self.git_repo.clone(), |
| 1190 | | − message, |
| 1191 | | − name_and_email, |
| 1015 | + self.send_job(|git_repo| async move { |
| 1016 | + match git_repo { |
| 1017 | + GitRepo::Local(repo) => repo.commit( |
| 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 | 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 | 1073 | pub fn push( |
| @@ -1202,11 +1076,33 @@ impl Repository { · 2 unmodified lines |
| 1202 | 1076 | remote: SharedString, |
| 1203 | 1077 | options: Option<PushOptions>, |
| 1204 | 1078 | ) -> oneshot::Receiver<Result<()>> { |
| 1205 | | − self.send_message(Message::Push { |
| 1206 | | − repo: self.git_repo.clone(), |
| 1207 | | − branch_name: branch, |
| 1208 | | − remote_name: remote, |
| 1209 | | − options, |
| 1079 | + self.send_job(move |git_repo| async move { |
| 1080 | + match git_repo { |
| 1081 | + GitRepo::Local(git_repository) => git_repository.push(&branch, &remote, options), |
| 1082 | + GitRepo::Remote { |
| 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 | 1111 | branch: SharedString, |
| 1216 | 1112 | remote: SharedString, |
| 1217 | 1113 | ) -> oneshot::Receiver<Result<()>> { |
| 1218 | | − self.send_message(Message::Pull { |
| 1219 | | − repo: self.git_repo.clone(), |
| 1220 | | − branch_name: branch, |
| 1221 | | − remote_name: remote, |
| 1114 | + self.send_job(|git_repo| async move { |
| 1115 | + match git_repo { |
| 1116 | + GitRepo::Local(git_repository) => git_repository.pull(&branch, &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 | 1143 | path: &RepoPath, |
| 1228 | 1144 | content: Option<String>, |
| 1229 | 1145 | ) -> oneshot::Receiver<anyhow::Result<()>> { |
| 1230 | | − self.send_message(Message::SetIndexText( |
| 1231 | | − self.git_repo.clone(), |
| 1232 | | − path.clone(), |
| 1233 | | − content, |
| 1234 | | − )) |
| 1235 | | − } |
| 1236 | | − |
| 1237 | | − pub fn get_remotes(&self, branch_name: Option<String>, cx: &App) -> Task<Result<Vec<Remote>>> { |
| 1238 | | − match self.git_repo.clone() { |
| 1239 | | − GitRepo::Local(git_repository) => { |
| 1240 | | − cx.background_spawn( |
| 1241 | | − async move { git_repository.get_remotes(branch_name.as_deref()) }, |
| 1242 | | − ) |
| 1146 | + let path = path.clone(); |
| 1147 | + self.send_job(|git_repo| async move { |
| 1148 | + match git_repo { |
| 1149 | + GitRepo::Local(repo) => repo.set_index_text(&path, content), |
| 1150 | + GitRepo::Remote { |
| 1151 | + project_id, |
| 1152 | + client, |
| 1153 | + worktree_id, |
| 1154 | + work_directory_id, |
| 1155 | + } => { |
| 1156 | + client |
| 1157 | + .request(proto::SetIndexText { |
| 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 { |
| 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 | | − } |
| 1168 | + }) |
| 1268 | 1169 | } |
| 1269 | 1170 | |
| 1270 | | − fn send_message(&self, message: Message) -> oneshot::Receiver<anyhow::Result<()>> { |
| 1271 | | − let (result_tx, result_rx) = futures::channel::oneshot::channel(); |
| 1272 | | − self.update_sender.unbounded_send((message, result_tx)).ok(); |
| 1273 | | − result_rx |
| 1171 | + pub fn get_remotes( |
| 1172 | + &self, |
| 1173 | + branch_name: Option<String>, |
| 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 | } |