telemetry_snapshot.rs

  1use git::repository::DiffType;
  2use gpui::{App, Entity, Task};
  3use serde::{Deserialize, Serialize};
  4use worktree::Worktree;
  5
  6use crate::{
  7    Project,
  8    git_store::{GitStore, LocalRepositoryState, RepositoryState},
  9};
 10
 11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 12pub struct TelemetrySnapshot {
 13    pub worktree_snapshots: Vec<TelemetryWorktreeSnapshot>,
 14}
 15
 16impl TelemetrySnapshot {
 17    pub fn new(project: &Entity<Project>, cx: &mut App) -> Task<TelemetrySnapshot> {
 18        let git_store = project.read(cx).git_store().clone();
 19        let worktree_snapshots: Vec<_> = project
 20            .read(cx)
 21            .visible_worktrees(cx)
 22            .map(|worktree| TelemetryWorktreeSnapshot::new(worktree, git_store.clone(), cx))
 23            .collect();
 24
 25        cx.spawn(async move |_| {
 26            let worktree_snapshots = futures::future::join_all(worktree_snapshots).await;
 27
 28            Self { worktree_snapshots }
 29        })
 30    }
 31}
 32
 33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 34pub struct TelemetryWorktreeSnapshot {
 35    pub worktree_path: String,
 36    pub git_state: Option<GitState>,
 37}
 38
 39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 40pub struct GitState {
 41    pub remote_url: Option<String>,
 42    pub head_sha: Option<String>,
 43    pub current_branch: Option<String>,
 44    pub diff: Option<String>,
 45}
 46
 47impl TelemetryWorktreeSnapshot {
 48    fn new(
 49        worktree: Entity<Worktree>,
 50        git_store: Entity<GitStore>,
 51        cx: &App,
 52    ) -> Task<TelemetryWorktreeSnapshot> {
 53        cx.spawn(async move |cx| {
 54            // Get worktree path and snapshot
 55            let worktree_info = cx.update(|app_cx| {
 56                let worktree = worktree.read(app_cx);
 57                let path = worktree.abs_path().to_string_lossy().into_owned();
 58                let snapshot = worktree.snapshot();
 59                (path, snapshot)
 60            });
 61
 62            let (worktree_path, _snapshot) = worktree_info;
 63
 64            let git_state = git_store
 65                .update(cx, |git_store, cx| {
 66                    git_store
 67                        .repositories()
 68                        .values()
 69                        .find(|repo| {
 70                            repo.read(cx)
 71                                .abs_path_to_repo_path(&worktree.read(cx).abs_path())
 72                                .is_some()
 73                        })
 74                        .cloned()
 75                })
 76                .map(|repo| {
 77                    repo.update(cx, |repo, _| {
 78                        let current_branch =
 79                            repo.branch.as_ref().map(|branch| branch.name().to_owned());
 80                        repo.send_job(None, |state, _| async move {
 81                            let RepositoryState::Local(LocalRepositoryState { backend, .. }) =
 82                                state
 83                            else {
 84                                return GitState {
 85                                    remote_url: None,
 86                                    head_sha: None,
 87                                    current_branch,
 88                                    diff: None,
 89                                };
 90                            };
 91
 92                            let remote_url = backend.remote_url("origin").await;
 93                            let head_sha = backend.head_sha().await;
 94                            let diff = backend.diff(DiffType::HeadToWorktree).await.ok();
 95
 96                            GitState {
 97                                remote_url,
 98                                head_sha,
 99                                current_branch,
100                                diff,
101                            }
102                        })
103                    })
104                });
105
106            let git_state = match git_state {
107                Some(receiver) => receiver.await.ok(),
108                None => None,
109            };
110
111            TelemetryWorktreeSnapshot {
112                worktree_path,
113                git_state,
114            }
115        })
116    }
117}