cli: Remove rad-inspect `tree' dependency
Hard code output similar to the 'tree' command in rust to avoid having to shell out.
This commit is contained in:
parent
f91ef2963e
commit
67a8ee9e86
|
|
@ -31,28 +31,27 @@ Let's check that we have all the namespaces in storage:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect --refs
|
$ rad inspect --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
| `-- refs
|
├── heads
|
||||||
| |-- heads
|
│ └── master
|
||||||
| | `-- master
|
└── rad
|
||||||
| `-- rad
|
├── id
|
||||||
| |-- id
|
└── sigrefs
|
||||||
| `-- sigrefs
|
z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
|-- z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
└── refs
|
||||||
| `-- refs
|
├── heads
|
||||||
| |-- heads
|
│ └── master
|
||||||
| | `-- master
|
└── rad
|
||||||
| `-- rad
|
├── id
|
||||||
| |-- id
|
└── sigrefs
|
||||||
| `-- sigrefs
|
z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z
|
||||||
`-- z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z
|
└── refs
|
||||||
`-- refs
|
├── heads
|
||||||
|-- heads
|
│ └── master
|
||||||
| `-- master
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
We can then setup a git remote for `bob`:
|
We can then setup a git remote for `bob`:
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@ NID. This is demonstrated below where our NID is
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --refs
|
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
`-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
`-- refs
|
├── heads
|
||||||
|-- heads
|
│ └── master
|
||||||
| `-- master
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To remedy this, we can use the `rad fork` command for the project we
|
To remedy this, we can use the `rad fork` command for the project we
|
||||||
|
|
@ -28,21 +27,20 @@ have a copy of the main set of refs:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --refs
|
$ rad inspect rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
| `-- refs
|
├── heads
|
||||||
| |-- heads
|
│ └── master
|
||||||
| | `-- master
|
└── rad
|
||||||
| `-- rad
|
├── id
|
||||||
| |-- id
|
└── sigrefs
|
||||||
| `-- sigrefs
|
z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
||||||
`-- z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk
|
└── refs
|
||||||
`-- refs
|
├── heads
|
||||||
|-- heads
|
│ └── master
|
||||||
| `-- master
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
We are now able to setup a remote in our own working copy of the
|
We are now able to setup a remote in our own working copy of the
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,13 @@ It's also possible to display all of the repository's git references:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect --refs
|
$ rad inspect --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
`-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
`-- refs
|
├── heads
|
||||||
|-- heads
|
│ └── master
|
||||||
| `-- master
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or display the repository identity's payload:
|
Or display the repository identity's payload:
|
||||||
|
|
|
||||||
|
|
@ -30,21 +30,20 @@ And some remote refs:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect --refs
|
$ rad inspect --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
`-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
`-- refs
|
├── cobs
|
||||||
|-- cobs
|
│ └── xyz.radicle.patch
|
||||||
| `-- xyz.radicle.patch
|
│ ├── 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
||||||
| |-- 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
│ └── 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
||||||
| `-- 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
├── heads
|
||||||
|-- heads
|
│ ├── master
|
||||||
| |-- master
|
│ └── patches
|
||||||
| `-- patches
|
│ ├── 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
||||||
| |-- 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
│ └── 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
||||||
| `-- 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then let's merge the changes into `master`.
|
Then let's merge the changes into `master`.
|
||||||
|
|
@ -86,16 +85,15 @@ And so were the remote branches:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ rad inspect --refs
|
$ rad inspect --refs
|
||||||
.
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
`-- z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
└── refs
|
||||||
`-- refs
|
├── cobs
|
||||||
|-- cobs
|
│ └── xyz.radicle.patch
|
||||||
| `-- xyz.radicle.patch
|
│ ├── 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
||||||
| |-- 0ec956c94256fa101db4c32956ce195a1aa0edf2
|
│ └── 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
||||||
| `-- 928d76e22ef98a8406f2e4e4bcc8878533bbdfe0
|
├── heads
|
||||||
|-- heads
|
│ └── master
|
||||||
| `-- master
|
└── rad
|
||||||
`-- rad
|
├── id
|
||||||
|-- id
|
└── sigrefs
|
||||||
`-- sigrefs
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::or_fun_call)]
|
#![allow(clippy::or_fun_call)]
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
|
|
@ -11,6 +11,7 @@ use json_color::{Color, Colorizer};
|
||||||
use radicle::crypto::{Unverified, Verified};
|
use radicle::crypto::{Unverified, Verified};
|
||||||
use radicle::identity::Untrusted;
|
use radicle::identity::Untrusted;
|
||||||
use radicle::identity::{Doc, Id};
|
use radicle::identity::{Doc, Id};
|
||||||
|
use radicle::storage::git::Storage;
|
||||||
use radicle::storage::{ReadRepository, ReadStorage};
|
use radicle::storage::{ReadRepository, ReadStorage};
|
||||||
|
|
||||||
use crate::terminal as term;
|
use crate::terminal as term;
|
||||||
|
|
@ -34,7 +35,7 @@ Options
|
||||||
|
|
||||||
--id Return the repository identifier (RID)
|
--id Return the repository identifier (RID)
|
||||||
--payload Inspect the repository's identity payload
|
--payload Inspect the repository's identity payload
|
||||||
--refs Inspect the repository's refs on the local device (requires `tree`)
|
--refs Inspect the repository's refs on the local device
|
||||||
--history Show the history of the repository identity document
|
--history Show the history of the repository identity document
|
||||||
--help Print help
|
--help Print help
|
||||||
"#,
|
"#,
|
||||||
|
|
@ -127,15 +128,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
|
|
||||||
match options.target {
|
match options.target {
|
||||||
Target::Refs => {
|
Target::Refs => {
|
||||||
let path = storage.path_of(&id).join("refs").join("namespaces");
|
refs(storage, id)?;
|
||||||
|
|
||||||
Command::new("tree")
|
|
||||||
.current_dir(path)
|
|
||||||
.args(["--noreport", "--prune"])
|
|
||||||
.stdout(Stdio::inherit())
|
|
||||||
.stderr(Stdio::inherit())
|
|
||||||
.spawn()?
|
|
||||||
.wait()?;
|
|
||||||
}
|
}
|
||||||
Target::Payload => {
|
Target::Payload => {
|
||||||
println!(
|
println!(
|
||||||
|
|
@ -216,3 +209,116 @@ fn colorizer() -> Colorizer {
|
||||||
.key(Color::Blue)
|
.key(Color::Blue)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refs(storage: &Storage, id: Id) -> anyhow::Result<()> {
|
||||||
|
let repo = storage.repository(id)?;
|
||||||
|
let mut refs = Vec::new();
|
||||||
|
for r in repo.references()? {
|
||||||
|
let r = r?;
|
||||||
|
if let Some(namespace) = r.namespace {
|
||||||
|
refs.push(format!("{}/{}", namespace, r.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("{}", tree(refs));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the list of given git references as a newline terminated tree `String` similar to the tree command.
|
||||||
|
fn tree(mut refs: Vec<String>) -> String {
|
||||||
|
refs.sort();
|
||||||
|
|
||||||
|
// List of references with additional unique entries for each 'directory'.
|
||||||
|
//
|
||||||
|
// i.e. "refs/heads/master" becomes ["refs"], ["refs", "heads"], and ["refs", "heads",
|
||||||
|
// "master"].
|
||||||
|
let mut refs_expanded: Vec<Vec<String>> = Vec::new();
|
||||||
|
// Number of entries per Git 'directory'.
|
||||||
|
let mut ref_entries: HashMap<Vec<String>, usize> = HashMap::new();
|
||||||
|
let mut last: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
for r in refs {
|
||||||
|
let r: Vec<String> = r.split('/').map(|s| s.to_string()).collect();
|
||||||
|
|
||||||
|
for (i, v) in r.iter().enumerate() {
|
||||||
|
let last_v = last.get(i);
|
||||||
|
if Some(v) != last_v {
|
||||||
|
last = r.clone().iter().take(i + 1).map(String::from).collect();
|
||||||
|
|
||||||
|
refs_expanded.push(last.clone());
|
||||||
|
|
||||||
|
let mut dir = last.clone();
|
||||||
|
dir.pop();
|
||||||
|
if dir.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(num) = ref_entries.get_mut(&dir) {
|
||||||
|
*num += 1;
|
||||||
|
} else {
|
||||||
|
ref_entries.insert(dir, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut tree = String::default();
|
||||||
|
|
||||||
|
for mut ref_components in refs_expanded {
|
||||||
|
// Better to explode when things do not go as expected.
|
||||||
|
let name = ref_components.pop().expect("non-empty vector");
|
||||||
|
if ref_components.is_empty() {
|
||||||
|
tree.push_str(&format!("{name}\n"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 1..ref_components.len() {
|
||||||
|
let parent: Vec<String> = ref_components.iter().take(i).cloned().collect();
|
||||||
|
|
||||||
|
let num = ref_entries.get(&parent).unwrap_or(&0);
|
||||||
|
if *num == 0 {
|
||||||
|
tree.push_str(" ");
|
||||||
|
} else {
|
||||||
|
tree.push_str("│ ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(num) = ref_entries.get_mut(&ref_components) {
|
||||||
|
if *num == 1 {
|
||||||
|
tree.push_str(&format!("└── {name}\n"));
|
||||||
|
} else {
|
||||||
|
tree.push_str(&format!("├── {name}\n"));
|
||||||
|
}
|
||||||
|
*num -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tree
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree() {
|
||||||
|
let arg = vec![
|
||||||
|
String::from("z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/refs/heads/master"),
|
||||||
|
String::from("z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/refs/rad/id"),
|
||||||
|
String::from("z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/refs/rad/sigrefs"),
|
||||||
|
];
|
||||||
|
let exp = r#"
|
||||||
|
z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi
|
||||||
|
└── refs
|
||||||
|
├── heads
|
||||||
|
│ └── master
|
||||||
|
└── rad
|
||||||
|
├── id
|
||||||
|
└── sigrefs
|
||||||
|
"#
|
||||||
|
.trim_start();
|
||||||
|
|
||||||
|
assert_eq!(tree(arg), exp);
|
||||||
|
assert_eq!(tree(vec![String::new()]), "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue