From ebb431350c1471bc4ba4ef654e14f6cda3dcb0b7 Mon Sep 17 00:00:00 2001 From: figsoda Date: Fri, 30 Dec 2022 13:12:38 -0500 Subject: [PATCH] add --json --- src/cli.rs | 4 +++ src/fetcher/mod.rs | 85 +++++++++++++++++++++++++++++++++++++++------- src/main.rs | 8 +++-- 3 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 5b003a2..cfbc9f7 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -19,6 +19,10 @@ pub struct Opts { /// extra indentation (in number of spaces) #[arg(short, long, default_value_t = 0)] pub indent: usize, + + /// output in json format + #[arg(short, long)] + pub json: bool, } #[derive(Clone, Debug, ValueEnum)] diff --git a/src/fetcher/mod.rs b/src/fetcher/mod.rs index d6456b4..24e6298 100644 --- a/src/fetcher/mod.rs +++ b/src/fetcher/mod.rs @@ -10,6 +10,7 @@ pub use github::FetchFromGitHub; pub use gitlab::FetchFromGitLab; pub use hg::Fetchhg; use indoc::writedoc; +use serde_json::json; pub use sourcehut::FetchFromSourcehut; use anyhow::{bail, Context, Result}; @@ -24,6 +25,7 @@ use std::{ #[enum_dispatch] pub trait Fetcher { fn fetch_nix(&self, out: &mut impl Write, url: Url, rev: String, indent: String) -> Result<()>; + fn fetch_json(&self, out: &mut impl Write, url: Url, rev: String) -> Result<()>; } #[enum_dispatch(Fetcher)] @@ -48,6 +50,10 @@ macro_rules! impl_fetcher { ) -> ::anyhow::Result<()> { self.fetch_nix_imp(out, url, rev, indent) } + + fn fetch_json(&self, out: &mut impl ::std::io::Write, url: ::url::Url, rev: String) -> ::anyhow::Result<()> { + self.fetch_json_imp(out, url, rev) + } } }; } @@ -68,15 +74,9 @@ pub trait SimpleFlakeFetcher<'a> { )) } - fn fetch_nix_imp( - &'a self, - out: &mut impl Write, - url: Url, - rev: String, - indent: String, - ) -> Result<()> { + fn fetch(&'a self, url: &Url, rev: &str) -> Result<(String, String, String)> { let (owner, repo) = self - .get_repo(&url) + .get_repo(url) .with_context(|| format!("failed to parse {url} as a {} url", Self::FLAKE_TYPE))?; let hash = flake_prefetch(if let Some(host) = self.host() { @@ -85,6 +85,18 @@ pub trait SimpleFlakeFetcher<'a> { format!("{}:{owner}/{repo}/{rev}", Self::FLAKE_TYPE) })?; + Ok((owner, repo, hash)) + } + + fn fetch_nix_imp( + &'a self, + out: &mut impl Write, + url: Url, + rev: String, + indent: String, + ) -> Result<()> { + let (owner, repo, hash) = self.fetch(&url, &rev)?; + writeln!(out, "{} {{", Self::NAME)?; if let Some(domain) = self.host() { @@ -103,12 +115,45 @@ pub trait SimpleFlakeFetcher<'a> { Ok(()) } + + fn fetch_json_imp(&'a self, out: &mut impl Write, url: Url, rev: String) -> Result<()> { + let (owner, repo, hash) = self.fetch(&url, &rev)?; + + let mut args = json! ({ + "owner": owner, + "repo": repo, + "rev": rev, + "hash": hash, + }); + + if let Some(host) = self.host() { + args["host"] = json!(host); + } + + serde_json::to_writer( + out, + &json!({ + "fetcher": Self::NAME, + "args": args, + }), + )?; + + Ok(()) + } } pub trait UrlFlakeFetcher { const FLAKE_TYPE: &'static str; const NAME: &'static str; + fn fetch(&self, url: &Url, rev: &str) -> Result { + flake_prefetch(format!( + "{}+{url}?{}={rev}", + Self::FLAKE_TYPE, + if rev.len() == 40 { "rev" } else { "ref" }, + )) + } + fn fetch_nix_imp( &self, out: &mut impl Write, @@ -116,11 +161,7 @@ pub trait UrlFlakeFetcher { rev: String, indent: String, ) -> Result<()> { - let hash = flake_prefetch(format!( - "{}+{url}?{}={rev}", - Self::FLAKE_TYPE, - if rev.len() == 40 { "rev" } else { "ref" }, - ))?; + let hash = self.fetch(&url, &rev)?; writedoc!( out, @@ -135,6 +176,24 @@ pub trait UrlFlakeFetcher { Ok(()) } + + fn fetch_json_imp(&self, out: &mut impl Write, url: Url, rev: String) -> Result<()> { + let hash = self.fetch(&url, &rev)?; + + serde_json::to_writer( + out, + &json!({ + "fetcher": Self::NAME, + "args": { + "url": url.to_string(), + "rev": rev, + "hash": hash, + }, + }), + )?; + + Ok(()) + } } trait GetStdout { diff --git a/src/main.rs b/src/main.rs index 03cd71b..94c27ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,9 +60,11 @@ fn main() -> Result<()> { }; let out = &mut stdout().lock(); - let indent = " ".repeat(opts.indent); - - fetcher.fetch_nix(out, opts.url, opts.rev, indent)?; + if opts.json { + fetcher.fetch_json(out, opts.url, opts.rev) + } else { + fetcher.fetch_nix(out, opts.url, opts.rev, " ".repeat(opts.indent)) + }?; Ok(()) }