cli: Add `rad cob log` format options
Add `--format json` and `--format pretty`.
This commit is contained in:
parent
72dad241e2
commit
6147a8a2fb
|
|
@ -5,9 +5,11 @@ use anyhow::anyhow;
|
|||
use chrono::prelude::*;
|
||||
use nonempty::NonEmpty;
|
||||
use radicle::cob;
|
||||
use radicle::cob::Op;
|
||||
use radicle::prelude::RepoId;
|
||||
use radicle::storage::ReadStorage;
|
||||
use radicle_cob::object::collaboration::list;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::git::Rev;
|
||||
use crate::terminal as term;
|
||||
|
|
@ -21,20 +23,25 @@ pub const HELP: Help = Help {
|
|||
Usage
|
||||
|
||||
rad cob <command> [<option>...]
|
||||
rad cob list --repo <rid> --type <typename>
|
||||
rad cob log --repo <rid> --type <typename> --object <oid>
|
||||
rad cob list --repo <rid> --type <typename>
|
||||
rad cob log --repo <rid> --type <typename> --object <oid> [<option>..]
|
||||
|
||||
Commands
|
||||
|
||||
list List all COBs of a given type (--object is not needed)
|
||||
log Print a log of all raw operations on a COB
|
||||
list List all COBs of a given type (--object is not needed)
|
||||
log Print a log of all raw operations on a COB
|
||||
|
||||
Options
|
||||
Log options
|
||||
|
||||
--help Print help
|
||||
--format (pretty | json) Desired output format (default: pretty)
|
||||
|
||||
Other options
|
||||
|
||||
--help Print help
|
||||
"#,
|
||||
};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum OperationName {
|
||||
List,
|
||||
Log,
|
||||
|
|
@ -45,10 +52,16 @@ enum Operation {
|
|||
Log(Rev),
|
||||
}
|
||||
|
||||
enum Format {
|
||||
Json,
|
||||
Pretty,
|
||||
}
|
||||
|
||||
pub struct Options {
|
||||
rid: RepoId,
|
||||
op: Operation,
|
||||
type_name: cob::TypeName,
|
||||
format: Format,
|
||||
}
|
||||
|
||||
impl Args for Options {
|
||||
|
|
@ -60,6 +73,7 @@ impl Args for Options {
|
|||
let mut type_name: Option<cob::TypeName> = None;
|
||||
let mut oid: Option<Rev> = None;
|
||||
let mut rid: Option<RepoId> = None;
|
||||
let mut format: Option<Format> = None;
|
||||
|
||||
while let Some(arg) = parser.next()? {
|
||||
match arg {
|
||||
|
|
@ -90,6 +104,14 @@ impl Args for Options {
|
|||
Long("help") | Short('h') => {
|
||||
return Err(Error::Help.into());
|
||||
}
|
||||
Long("format") if op == Some(OperationName::Log) => {
|
||||
let v: String = term::args::string(&parser.value()?);
|
||||
match v.as_ref() {
|
||||
"pretty" => format = Some(Format::Pretty),
|
||||
"json" => format = Some(Format::Json),
|
||||
unknown => anyhow::bail!("unknown format '{unknown}'"),
|
||||
}
|
||||
}
|
||||
_ => return Err(anyhow::anyhow!(arg.unexpected())),
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +130,7 @@ impl Args for Options {
|
|||
.ok_or_else(|| anyhow!("a repository id must be specified with `--repo`"))?,
|
||||
type_name: type_name
|
||||
.ok_or_else(|| anyhow!("an object type must be specified with `--type`"))?,
|
||||
format: format.unwrap_or(Format::Pretty),
|
||||
},
|
||||
vec![],
|
||||
))
|
||||
|
|
@ -131,33 +154,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
let ops = cob::store::ops(&oid, &options.type_name, &repo)?;
|
||||
|
||||
for op in ops.into_iter().rev() {
|
||||
let time = DateTime::<Utc>::from(
|
||||
std::time::UNIX_EPOCH + std::time::Duration::from_secs(op.timestamp.as_secs()),
|
||||
)
|
||||
.to_rfc2822();
|
||||
|
||||
term::print(term::format::yellow(format!("commit {}", op.id)));
|
||||
if let Some(oid) = op.identity {
|
||||
term::print(term::format::tertiary(format!("resource {oid}")));
|
||||
}
|
||||
for parent in op.parents {
|
||||
term::print(format!("parent {}", parent));
|
||||
}
|
||||
for parent in op.related {
|
||||
term::print(format!("rel {}", parent));
|
||||
}
|
||||
term::print(format!("author {}", op.author));
|
||||
term::print(format!("date {}", time));
|
||||
term::blank();
|
||||
|
||||
for action in op.actions {
|
||||
let obj: serde_json::Value = serde_json::from_slice(&action)?;
|
||||
let val = serde_json::to_string_pretty(&obj)?;
|
||||
|
||||
for line in val.lines() {
|
||||
term::indented(term::format::dim(line));
|
||||
}
|
||||
term::blank();
|
||||
match options.format {
|
||||
Format::Json => print_op_json(op)?,
|
||||
Format::Pretty => print_op_pretty(op)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -165,3 +164,48 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_op_pretty(op: Op<Vec<u8>>) -> anyhow::Result<()> {
|
||||
let time = DateTime::<Utc>::from(
|
||||
std::time::UNIX_EPOCH + std::time::Duration::from_secs(op.timestamp.as_secs()),
|
||||
)
|
||||
.to_rfc2822();
|
||||
term::print(term::format::yellow(format!("commit {}", op.id)));
|
||||
if let Some(oid) = op.identity {
|
||||
term::print(term::format::tertiary(format!("resource {oid}")));
|
||||
}
|
||||
for parent in op.parents {
|
||||
term::print(format!("parent {}", parent));
|
||||
}
|
||||
for parent in op.related {
|
||||
term::print(format!("rel {}", parent));
|
||||
}
|
||||
term::print(format!("author {}", op.author));
|
||||
term::print(format!("date {}", time));
|
||||
term::blank();
|
||||
for action in op.actions {
|
||||
let obj: serde_json::Value = serde_json::from_slice(&action)?;
|
||||
let val = serde_json::to_string_pretty(&obj)?;
|
||||
for line in val.lines() {
|
||||
term::indented(term::format::dim(line));
|
||||
}
|
||||
term::blank();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_op_json(op: Op<Vec<u8>>) -> anyhow::Result<()> {
|
||||
let mut ser = json!(op);
|
||||
ser.as_object_mut().unwrap().insert(
|
||||
"actions".to_string(),
|
||||
json!(op
|
||||
.actions
|
||||
.iter()
|
||||
.map(|action: &Vec<u8>| -> Result<serde_json::Value, _> {
|
||||
serde_json::from_slice(action)
|
||||
})
|
||||
.collect::<Result<Vec<serde_json::Value>, _>>()?),
|
||||
);
|
||||
term::print(ser);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use nonempty::NonEmpty;
|
||||
use radicle_cob::Manifest;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
use radicle_cob::history::{Entry, EntryId};
|
||||
|
|
@ -26,7 +27,7 @@ pub enum OpEncodingError {
|
|||
///
|
||||
/// Everything that can be done in the system is represented by an `Op`.
|
||||
/// Operations are applied to an accumulator to yield a final state.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct Op<A> {
|
||||
/// Id of the entry under which this operation lives.
|
||||
pub id: EntryId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue