cli: Polish the `rad sync status` output

This commit is contained in:
cloudhead 2023-11-22 17:40:51 +01:00
parent b64fc22c18
commit dfe0cb4342
No known key found for this signature in database
4 changed files with 85 additions and 32 deletions

View File

@ -13,13 +13,13 @@ It isn't aware of the updates to the repo.
```
$ rad sync status
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● NID Address Status At Timestamp │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
│ ● z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk bob.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
│ ● z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z eve.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
╭──────────────────────────────────────────────────────────────────────────────────────────╮
│ ● NID Alias Address Status At Timestamp │
├──────────────────────────────────────────────────────────────────────────────────────────┤
│ ● z6MknSL…StBU8Vi alice alice.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
│ ● z6Mkt67…v4N1tRk bob bob.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
│ ● z6Mkux1…nVhib7Z eve eve.radicle.xyz:8776 out-of-sync f209c9f [ ... ] │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
```
Now let's run `rad sync`. This will announce the issue refs to the network and
@ -77,11 +77,11 @@ We can check the sync status again to make sure everything's in sync:
```
$ rad sync status
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● NID Address Status At Timestamp │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ ● z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi alice.radicle.xyz:8776 synced 9f615f9 [ ... ] │
│ ● z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk bob.radicle.xyz:8776 synced 9f615f9 [ ... ] │
│ ● z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z eve.radicle.xyz:8776 synced 9f615f9 [ ... ] │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────
╭─────────────────────────────────────────────────────────────────────────────────────╮
│ ● NID Alias Address Status At Timestamp │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ ● z6MknSL…StBU8Vi alice alice.radicle.xyz:8776 synced 9f615f9 [ ... ] │
│ ● z6Mkt67…v4N1tRk bob bob.radicle.xyz:8776 synced 9f615f9 [ ... ] │
│ ● z6Mkux1…nVhib7Z eve eve.radicle.xyz:8776 synced 9f615f9 [ ... ] │
╰─────────────────────────────────────────────────────────────────────────────────────╯
```

View File

@ -5,6 +5,7 @@ use std::time;
use anyhow::{anyhow, Context as _};
use radicle::node;
use radicle::node::AliasStore as _;
use radicle::node::{FetchResult, FetchResults, Handle as _, Node, SyncStatus};
use radicle::prelude::{Id, NodeId, Profile};
use radicle::storage::{ReadRepository, ReadStorage};
@ -243,7 +244,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
match options.op {
Operation::Status => {
sync_status(rid, &mut node)?;
sync_status(rid, &mut node, &profile, &options)?;
}
Operation::Synchronize(SyncMode::Repo { mode, direction }) => {
if [SyncDirection::Fetch, SyncDirection::Both].contains(&direction) {
@ -271,14 +272,21 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
Ok(())
}
fn sync_status(rid: Id, node: &mut Node) -> anyhow::Result<()> {
let mut table = Table::<6, term::Label>::new(TableOptions::bordered());
fn sync_status(
rid: Id,
node: &mut Node,
profile: &Profile,
options: &Options,
) -> anyhow::Result<()> {
let mut table = Table::<7, term::Label>::new(TableOptions::bordered());
let mut seeds: Vec<_> = node.seeds(rid)?.into();
let local = node.nid()?;
let aliases = profile.aliases();
table.push([
term::format::dim(String::from("")).into(),
term::format::bold(String::from("NID")).into(),
term::format::bold(String::from("Alias")).into(),
term::format::bold(String::from("Address")).into(),
term::format::bold(String::from("Status")).into(),
term::format::bold(String::from("At")).into(),
@ -287,34 +295,43 @@ fn sync_status(rid: Id, node: &mut Node) -> anyhow::Result<()> {
table.divider();
// Always show our local node first.
seeds.sort_by(|a, _| {
seeds.sort_by(|a, b| {
if a.nid == local {
Ordering::Less
} else if b.nid == local {
Ordering::Greater
} else {
Ordering::Equal
match (&a.sync, &b.sync) {
(Some(_), None) => Ordering::Less,
(None, Some(_)) => Ordering::Greater,
(Some(a), Some(b)) => a.cmp(b).reverse(),
(None, None) => Ordering::Equal,
}
.then(a.nid.cmp(&b.nid))
}
});
for seed in seeds {
let (icon, status, refs, time) = match seed.sync {
let (icon, status, head, time) = match seed.sync {
Some(SyncStatus::Synced { at }) => (
term::format::positive(""),
term::format::positive("synced"),
term::label(term::format::oid(at.oid)),
term::format::timestamp(at.timestamp).into(),
term::format::oid(at.oid),
term::format::timestamp(at.timestamp),
),
Some(SyncStatus::OutOfSync { remote, .. }) => (
term::format::negative(""),
term::format::negative("out-of-sync"),
term::label(term::format::oid(remote.oid)),
term::format::timestamp(remote.timestamp).into(),
term::format::oid(remote.oid),
term::format::timestamp(remote.timestamp),
),
None => (
term::format::yellow(""),
term::format::yellow("?"),
term::label("?"),
term::label("?"),
None if options.verbose => (
term::format::dim(""),
term::format::dim("unknown"),
term::paint(String::new()),
term::paint(String::new()),
),
None => continue,
};
let addr = seed
.addrs
@ -322,14 +339,19 @@ fn sync_status(rid: Id, node: &mut Node) -> anyhow::Result<()> {
.map(|a| a.addr.to_string())
.unwrap_or_default()
.into();
let alias = aliases
.alias(&seed.nid)
.map(|a| a.to_string())
.unwrap_or_default();
table.push([
icon.into(),
seed.nid.to_human().into(),
term::format::primary(term::format::node(&seed.nid)).into(),
term::format::primary(alias).dim().into(),
addr,
status.into(),
refs,
time,
term::format::secondary(head).into(),
time.dim().italic().into(),
]);
}
table.print();

View File

@ -147,6 +147,25 @@ pub enum SyncStatus {
},
}
impl Ord for SyncStatus {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(Self::Synced { at: left }, Self::Synced { at: right }) => left.cmp(right),
(Self::Synced { at }, Self::OutOfSync { remote, .. }) => at.cmp(remote),
(Self::OutOfSync { remote, .. }, Self::Synced { at }) => remote.cmp(at),
(Self::OutOfSync { remote: left, .. }, Self::OutOfSync { remote: right, .. }) => {
left.cmp(right)
}
}
}
}
impl PartialOrd for SyncStatus {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
/// Node alias.
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Alias(String);

View File

@ -213,6 +213,18 @@ impl SyncedAt {
}
}
impl Ord for SyncedAt {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.timestamp.cmp(&other.timestamp)
}
}
impl PartialOrd for SyncedAt {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
/// Seed of a specific repository.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]