Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
Add "rad status" command
Draft did:key:z6MkwcUR...q1kL opened 7 months ago

Does not much yet, but might be a nice idea. Tell me what you think!

4 files changed +179 -0 646d4360 ceb6c634
modified crates/radicle-cli/src/commands.rs
@@ -23,6 +23,7 @@ pub mod publish;
pub mod remote;
pub mod seed;
pub mod stats;
+
pub mod status;
pub mod sync;
pub mod unblock;
pub mod unfollow;
modified crates/radicle-cli/src/commands/help.rs
@@ -37,6 +37,7 @@ const COMMANDS: &[Help] = &[
    crate::commands::remote::HELP,
    crate::commands::stats::HELP,
    crate::commands::sync::HELP,
+
    crate::commands::status::HELP,
];

#[derive(Default)]
added crates/radicle-cli/src/commands/status.rs
@@ -0,0 +1,172 @@
+
use std::ffi::OsString;
+

+
use radicle::{
+
    issue::cache::Issues, node::Handle, patch::cache::Patches, prelude::Did, storage::ReadStorage,
+
};
+

+
pub const HELP: crate::terminal::args::Help = crate::terminal::args::Help {
+
    name: "status",
+
    description: "Displays the status of the node and the current repository",
+
    version: env!("RADICLE_VERSION"),
+
    usage: r#"
+
Usage
+

+
    rad status [<option>...]
+

+
Options
+

+
    --help       Print help
+
"#,
+
};
+

+
#[derive(Default, Debug, Eq, PartialEq)]
+
pub struct Options {}
+

+
impl crate::terminal::Args for Options {
+
    fn from_args(args: Vec<OsString>) -> anyhow::Result<(Self, Vec<OsString>)> {
+
        use lexopt::prelude::*;
+

+
        let mut parser = lexopt::Parser::from_args(args);
+

+
        #[allow(clippy::never_loop)]
+
        while let Some(arg) = parser.next()? {
+
            match arg {
+
                Long("help") | Short('h') => {
+
                    return Err(crate::terminal::args::Error::Help.into());
+
                }
+
                _ => anyhow::bail!(arg.unexpected()),
+
            }
+
        }
+

+
        Ok((Options {}, vec![]))
+
    }
+
}
+

+
pub fn run(_options: Options, ctx: impl crate::terminal::Context) -> anyhow::Result<()> {
+
    let profile = ctx.profile()?;
+
    let me = *profile.id();
+
    let rid = radicle::rad::cwd().map(|(_, rid)| rid)?;
+
    let node = radicle::Node::new(profile.socket());
+
    let repo = profile.storage.repository(rid)?;
+
    let issues = crate::terminal::cob::issues(&profile, &repo)?;
+
    let patches = crate::terminal::cob::patches(&profile, &repo)?;
+

+
    let me_did = Did::from(me);
+

+
    let issues_state = {
+
        let issues: Vec<_> = issues
+
            .list()?
+
            .filter_map(|res| {
+
                match res {
+
                    Ok((id, issue)) => Some((id, issue)),
+
                    Err(e) => {
+
                        // Skip issues that failed to load.
+
                        log::error!(target: "cli", "Issue load error: {e}");
+
                        None
+
                    }
+
                }
+
            })
+
            .filter(|(_, i)| i.author().id() == &me_did)
+
            .collect();
+

+
        let mut open = 0;
+
        let mut closed = 0;
+

+
        for i in issues.iter().map(|tpl| &tpl.1) {
+
            match i.state() {
+
                radicle::issue::State::Closed { .. } => closed += 1,
+
                radicle::issue::State::Open => open += 1,
+
            }
+
        }
+

+
        IssuesState { open, closed }
+
    };
+

+
    let patches_state = {
+
        let patches: Vec<_> = patches
+
            .list()?
+
            .filter_map(|res| {
+
                match res {
+
                    Ok((id, patch)) => Some((id, patch)),
+
                    Err(e) => {
+
                        // Skip patches that failed to load.
+
                        log::error!(target: "cli", "Patch load error: {e}");
+
                        None
+
                    }
+
                }
+
            })
+
            .filter(|(_, p)| p.author().id() == &me_did)
+
            .collect();
+

+
        let mut open = 0;
+
        let mut draft = 0;
+
        let mut archived = 0;
+
        let mut merged = 0;
+

+
        for p in patches.iter().map(|tpl| &tpl.1) {
+
            match p.state() {
+
                radicle::patch::State::Draft => draft += 1,
+
                radicle::patch::State::Open { .. } => open += 1,
+
                radicle::patch::State::Archived => archived += 1,
+
                radicle::patch::State::Merged { .. } => merged += 1,
+
            }
+
        }
+

+
        PatchesState {
+
            overall: patches.len(),
+
            open,
+
            draft,
+
            archived,
+
            merged,
+
        }
+
    };
+

+
    if node.is_running() {
+
        let listen = node
+
            .listen_addrs()?
+
            .into_iter()
+
            .map(|addr| addr.to_string())
+
            .collect::<Vec<_>>();
+

+
        if listen.is_empty() {
+
            crate::terminal::success!("Node is {}.", crate::terminal::format::positive("running"));
+
        } else {
+
            crate::terminal::success!(
+
                "Node is {} and listening on {}.",
+
                crate::terminal::format::positive("running"),
+
                listen.join(", ")
+
            );
+
        }
+
    } else {
+
        crate::terminal::info!("Node is {}.", crate::terminal::format::negative("stopped"));
+
        crate::terminal::info!(
+
            "To start it, run {}.",
+
            crate::terminal::format::command("rad node start")
+
        );
+
    }
+

+
    crate::terminal::info!(" Patches: {}", patches_state.overall);
+
    crate::terminal::info!("    Open: {}", patches_state.open);
+
    crate::terminal::info!("   Draft: {}", patches_state.draft);
+
    crate::terminal::info!("Archived: {}", patches_state.archived);
+
    crate::terminal::info!("  Merged: {}", patches_state.merged);
+
    crate::terminal::info!("");
+
    crate::terminal::info!("  Issues: {}", issues_state.open + issues_state.closed);
+
    crate::terminal::info!("    Open: {}", issues_state.open);
+
    crate::terminal::info!("  Closed: {}", issues_state.closed);
+

+
    Ok(())
+
}
+

+
struct IssuesState {
+
    open: usize,
+
    closed: usize,
+
}
+

+
struct PatchesState {
+
    overall: usize,
+
    open: usize,
+
    draft: usize,
+
    archived: usize,
+
    merged: usize,
+
}
modified crates/radicle-cli/src/main.rs
@@ -246,6 +246,11 @@ fn run_other(exe: &str, args: &[OsString]) -> Result<(), Option<anyhow::Error>>
        "remote" => {
            term::run_command_args::<remote::Options, _>(remote::HELP, remote::run, args.to_vec())
        }
+
        "status" => term::run_command_args::<status::Options, _>(
+
            radicle_cli::commands::status::HELP,
+
            radicle_cli::commands::status::run,
+
            args.to_vec(),
+
        ),
        "stats" => {
            term::run_command_args::<stats::Options, _>(stats::HELP, stats::run, args.to_vec())
        }