use anyhow::{Context, Result};
use serde_json::Value;
pub fn parse_tree_spec(input: &str) -> Result<(String, String)> {
let (tree, spec) = input
.split_once('/')
.context("identifier must be <tree>/<spec>, e.g. keaton/graphs")?;
if tree.is_empty() || spec.is_empty() {
anyhow::bail!("identifier must be <tree>/<spec>, e.g. keaton/graphs");
}
Ok((tree.to_string(), spec.to_string()))
}
pub fn today() -> String {
use time::macros::format_description;
let fmt = format_description!("[year]-[month]-[day]");
time::OffsetDateTime::now_local()
.unwrap_or_else(|_| time::OffsetDateTime::now_utc())
.format(&fmt)
.unwrap_or_else(|_| "1970-01-01".into())
}
pub fn json_out(v: &Value) -> Result<()> {
println!("{}", serde_json::to_string(v).context("serialize output")?);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_tree_spec_ok() {
let (t, s) = parse_tree_spec("keaton/graphs").unwrap();
assert_eq!(t, "keaton");
assert_eq!(s, "graphs");
}
#[test]
fn parse_tree_spec_errors_on_missing_slash() {
assert!(parse_tree_spec("keaton").is_err());
}
#[test]
fn parse_tree_spec_errors_on_empty_halves() {
assert!(parse_tree_spec("/graphs").is_err());
assert!(parse_tree_spec("keaton/").is_err());
}
#[test]
fn today_shape_is_yyyy_mm_dd() {
let s = today();
assert_eq!(s.len(), 10);
assert_eq!(s.chars().nth(4), Some('-'));
assert_eq!(s.chars().nth(7), Some('-'));
}
}