use std::net::SocketAddr;
use eyre::{Context, Result};
const DEFAULT_ADMIN_ADDR: &str = "127.0.0.1:9091";
#[derive(Debug, clap::Parser)]
pub(crate) struct InspectArgs {
#[arg(long, default_value = DEFAULT_ADMIN_ADDR)]
pub(crate) admin: SocketAddr,
#[arg(long, value_name = "HEX")]
pub(crate) tree: Option<String>,
#[arg(long, value_name = "HEX")]
pub(crate) id: Option<String>,
#[arg(long, default_value_t = false)]
pub(crate) ids: bool,
#[arg(long, default_value_t = false)]
pub(crate) digests: bool,
}
pub(crate) async fn run(args: InspectArgs) -> Result<()> {
let url = build_url(&args);
let response = reqwest::get(&url).await.wrap_err_with(|| {
format!(
"request to {url} failed — is the server running with --admin-addr {}?",
args.admin
)
})?;
let status = response.status();
let body = response.text().await.wrap_err("read admin response")?;
print!("{body}");
if !status.is_success() {
eyre::bail!("admin endpoint returned {status}");
}
Ok(())
}
fn build_url(args: &InspectArgs) -> String {
let mut query: Vec<String> = Vec::new();
if args.digests && (args.ids || args.id.is_some()) {
query.push("digests=true".to_owned());
}
let path = if let Some(id) = &args.id {
if let Some(tree) = &args.tree {
query.push(format!("tree={tree}"));
}
format!("/inspect/find/{id}")
} else if args.ids {
args.tree.as_ref().map_or_else(
|| "/inspect/heads".to_owned(),
|tree| format!("/inspect/tree/{tree}/heads"),
)
} else if let Some(tree) = &args.tree {
format!("/inspect/tree/{tree}")
} else {
"/inspect".to_owned()
};
let query = if query.is_empty() {
String::new()
} else {
format!("?{}", query.join("&"))
};
format!("http://{}{path}{query}", args.admin)
}
#[cfg(test)]
#[allow(clippy::expect_used)]
mod tests {
use super::*;
fn args() -> InspectArgs {
InspectArgs {
admin: "127.0.0.1:9091".parse().expect("addr"),
tree: None,
id: None,
ids: false,
digests: false,
}
}
#[test]
fn url_maps_flags_to_routes() {
let base = "http://127.0.0.1:9091";
assert_eq!(build_url(&args()), format!("{base}/inspect"));
let mut a = args();
a.tree = Some("aa".into());
assert_eq!(build_url(&a), format!("{base}/inspect/tree/aa"));
a.ids = true;
assert_eq!(build_url(&a), format!("{base}/inspect/tree/aa/heads"));
a.digests = true;
assert_eq!(
build_url(&a),
format!("{base}/inspect/tree/aa/heads?digests=true")
);
let mut all = args();
all.ids = true;
assert_eq!(build_url(&all), format!("{base}/inspect/heads"));
let mut find = args();
find.id = Some("bb".into());
assert_eq!(build_url(&find), format!("{base}/inspect/find/bb"));
find.tree = Some("aa".into());
find.digests = true;
assert_eq!(
build_url(&find),
format!("{base}/inspect/find/bb?digests=true&tree=aa")
);
}
}