Skip to main content

outpost_core/ops/
list.rs

1use std::path::PathBuf;
2
3use crate::outpost_id::{OutpostId, shortest_unique_prefixes};
4use crate::{AheadBehind, BranchName, OutpostError, OutpostResult, SourceRepo};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct OutpostSummary {
8    pub display_id: String,
9    pub path: PathBuf,
10    pub current_branch: Option<BranchName>,
11    pub state: OutpostState,
12    pub ahead_behind: Option<AheadBehind>,
13    pub locked: bool,
14    pub lock_reason: Option<String>,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum OutpostState {
19    Clean,
20    Dirty,
21    Missing,
22    NotManaged,
23}
24
25pub fn run(source: &SourceRepo) -> OutpostResult<Vec<OutpostSummary>> {
26    let registry = source.registry()?;
27    let ids = registry
28        .entries()
29        .iter()
30        .map(|entry| OutpostId::derive(source.work_tree(), &entry.path))
31        .collect::<Vec<_>>();
32    let prefixes = shortest_unique_prefixes(ids.iter());
33    registry
34        .entries()
35        .iter()
36        .zip(prefixes)
37        .map(|(entry, display_id)| summarize_entry(source, entry, display_id))
38        .collect()
39}
40
41fn summarize_entry(
42    source: &SourceRepo,
43    entry: &crate::RegistryEntry,
44    display_id: String,
45) -> OutpostResult<OutpostSummary> {
46    let mut summary = OutpostSummary {
47        display_id,
48        path: entry.path.clone(),
49        current_branch: None,
50        state: OutpostState::Missing,
51        ahead_behind: None,
52        locked: entry.locked,
53        lock_reason: entry.lock_reason.clone(),
54    };
55
56    if !entry.path.exists() {
57        return Ok(summary);
58    }
59
60    let outpost = match crate::safety::check_entry_is_managed_outpost_of(source, entry) {
61        Ok(outpost) => outpost,
62        Err(OutpostError::RegistryEntryNotManaged(_)) => {
63            summary.state = OutpostState::NotManaged;
64            return Ok(summary);
65        }
66        Err(err) => return Err(err),
67    };
68
69    summary.current_branch = outpost.current_branch().ok();
70    summary.ahead_behind = outpost.ahead_behind_source().ok();
71    summary.state = if outpost.is_dirty()? {
72        OutpostState::Dirty
73    } else {
74        OutpostState::Clean
75    };
76
77    Ok(summary)
78}