noosphere_cli/native/commands/sphere/
status.rs

1use std::collections::BTreeMap;
2
3use crate::native::{content::Content, Workspace};
4use anyhow::Result;
5use noosphere_core::context::{HasSphereContext, SphereCursor};
6use noosphere_core::data::ContentType;
7
8fn status_section(
9    name: &str,
10    entries: &BTreeMap<String, Option<ContentType>>,
11    section: &mut Vec<(String, String, String)>,
12    max_name_length: &mut usize,
13    max_content_type_length: &mut usize,
14) {
15    for (slug, content_type) in entries {
16        let content_type = content_type
17            .as_ref()
18            .map(|content_type| content_type.to_string())
19            .unwrap_or_else(|| "Unknown".into());
20
21        *max_name_length = *max_name_length.max(&mut slug.len());
22        *max_content_type_length = *max_content_type_length.max(&mut content_type.len());
23
24        section.push((slug.to_string(), content_type, String::from(name)));
25    }
26}
27
28/// Get the current status of the workspace, reporting the content that has
29/// changed in some way (if any)
30pub async fn status(only_id: bool, workspace: &Workspace) -> Result<()> {
31    workspace.ensure_sphere_initialized()?;
32
33    let identity = workspace.sphere_identity().await?;
34
35    if only_id {
36        info!("{identity}");
37        return Ok(());
38    }
39
40    info!("This sphere's identity is {identity}");
41
42    let sphere_context = workspace.sphere_context().await?;
43    let cid = SphereCursor::latest(sphere_context).version().await?;
44    info!("The latest (saved) version of your sphere is {cid}\n");
45
46    // TODO(#556): No need to pack new blocks into a memory store at this step;
47    // maybe [Content::read_changes] can be optimized for this path
48    let (_, content_changes, _) = match Content::read_changes(workspace).await? {
49        Some(changes) => changes,
50        None => {
51            info!("No new changes to sphere content!");
52            return Ok(());
53        }
54    };
55
56    info!("Here is a summary of the current changes to sphere content:\n");
57
58    let mut content = Vec::new();
59
60    let mut max_name_length = 7usize;
61    let mut max_content_type_length = 16usize;
62
63    status_section(
64        "Updated",
65        &content_changes.updated,
66        &mut content,
67        &mut max_name_length,
68        &mut max_content_type_length,
69    );
70
71    status_section(
72        "New",
73        &content_changes.new,
74        &mut content,
75        &mut max_name_length,
76        &mut max_content_type_length,
77    );
78
79    status_section(
80        "Removed",
81        &content_changes.removed,
82        &mut content,
83        &mut max_name_length,
84        &mut max_content_type_length,
85    );
86
87    if !content.is_empty() {
88        info!(
89            "{:max_name_length$}  {:max_content_type_length$}  STATUS",
90            "NAME", "CONTENT-TYPE"
91        );
92
93        for (slug, content_type, status) in content {
94            info!("{slug:max_name_length$}  {content_type:max_content_type_length$}  {status}");
95        }
96    } else {
97        info!("No content has changed since the last save!")
98    }
99
100    Ok(())
101}