wsb-daemon 0.275.7622

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
//! What each machine has, and which of it is shared.
//!
//! An inventory is a list of worktree IDENTITIES, never of paths. Two
//! machines keep the same worktree in different directories, and the whole
//! point of deriving the id from the repository is that neither has to be told
//! what the other calls it.

use std::collections::BTreeMap;

use wsb::peer::model::{SharedWorktreeId, WorktreePresence};
use wsb::peer::protocol::WorktreeSummary;

/// One worktree, as the two machines together see it.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SharedWorktree {
    pub id: SharedWorktreeId,
    /// What this machine calls it, or what the peer does when only the peer
    /// has it.
    pub display_name: String,
    pub presence: WorktreePresence,
    /// Whether the two sides agree about which repository this worktree is.
    ///
    /// Two worktrees can only collide here by holding the same superproject
    /// root commit, which means they ARE the same history — but a restored
    /// backup or a hand-edited database could produce a mismatch, and pairing
    /// two unrelated trees is the one thing worth checking twice.
    pub compatible: bool,
}

/// Compare two inventories.
pub fn compare(mine: &[WorktreeSummary], theirs: &[WorktreeSummary]) -> Vec<SharedWorktree> {
    let theirs_by_id: BTreeMap<&SharedWorktreeId, &WorktreeSummary> =
        theirs.iter().map(|summary| (&summary.worktree, summary)).collect();
    let mut out = Vec::new();

    for summary in mine {
        match theirs_by_id.get(&summary.worktree) {
            Some(peer) => out.push(SharedWorktree {
                id: summary.worktree.clone(),
                display_name: summary.display_name.clone(),
                presence: WorktreePresence::Shared,
                compatible: peer.root_commit == summary.root_commit,
            }),
            None => out.push(SharedWorktree {
                id: summary.worktree.clone(),
                display_name: summary.display_name.clone(),
                presence: WorktreePresence::LocalOnly,
                compatible: true,
            }),
        }
    }

    let mine_ids: std::collections::BTreeSet<&SharedWorktreeId> =
        mine.iter().map(|summary| &summary.worktree).collect();
    for summary in theirs {
        if !mine_ids.contains(&summary.worktree) {
            out.push(SharedWorktree {
                id: summary.worktree.clone(),
                display_name: summary.display_name.clone(),
                presence: WorktreePresence::PeerOnly,
                compatible: true,
            });
        }
    }

    out.sort_by(|a, b| a.display_name.cmp(&b.display_name).then(a.id.cmp(&b.id)));
    out
}

#[cfg(test)]
#[path = "inventory_tests.rs"]
mod tests;