mirror of
https://github.com/nix-community/nurl.git
synced 2024-09-11 18:39:19 +03:00
add --arg to pass additional arguments to the fetcher
This commit is contained in:
parent
1f3b38eeb7
commit
7952a1ede5
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -79,6 +79,12 @@ dependencies = [
|
|||||||
"roff",
|
"roff",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enum_dispatch"
|
name = "enum_dispatch"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@ -174,6 +180,15 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -202,6 +217,7 @@ dependencies = [
|
|||||||
"clap_mangen",
|
"clap_mangen",
|
||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
"itertools",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url",
|
"url",
|
||||||
|
@ -15,6 +15,7 @@ categories = ["command-line-utilities"]
|
|||||||
anyhow = "1.0.68"
|
anyhow = "1.0.68"
|
||||||
enum_dispatch = "0.3.9"
|
enum_dispatch = "0.3.9"
|
||||||
indoc = "1.0.8"
|
indoc = "1.0.8"
|
||||||
|
itertools = "0.10.5"
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0.91"
|
serde_json = "1.0.91"
|
||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
|
@ -34,6 +34,10 @@ pub struct Opts {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pub json: bool,
|
pub json: bool,
|
||||||
|
|
||||||
|
// additional arguments to pass to the fetcher
|
||||||
|
#[arg(short, long = "arg", num_args = 2, value_names = ["KEY", "VALUE"])]
|
||||||
|
pub args: Vec<String>,
|
||||||
|
|
||||||
/// List all available fetchers
|
/// List all available fetchers
|
||||||
#[arg(short, long, group = "command")]
|
#[arg(short, long, group = "command")]
|
||||||
pub list_fetchers: bool,
|
pub list_fetchers: bool,
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
use crate::{fetcher::UrlFlakeFetcher, impl_fetcher};
|
use crate::{
|
||||||
|
fetcher::{UrlFetcher, UrlFlakeFetcher},
|
||||||
|
impl_fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Fetchgit;
|
pub struct Fetchgit;
|
||||||
impl_fetcher!(Fetchgit);
|
impl_fetcher!(Fetchgit);
|
||||||
|
|
||||||
impl UrlFlakeFetcher for Fetchgit {
|
impl UrlFetcher for Fetchgit {
|
||||||
const FLAKE_TYPE: &'static str = "git";
|
|
||||||
const NAME: &'static str = "fetchgit";
|
const NAME: &'static str = "fetchgit";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UrlFlakeFetcher for Fetchgit {
|
||||||
|
const FLAKE_TYPE: &'static str = "git";
|
||||||
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
use crate::{fetcher::SimpleFlakeFetcher, impl_fetcher};
|
use crate::{
|
||||||
|
fetcher::{SimpleFetcher, SimpleFlakeFetcher},
|
||||||
|
impl_fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct FetchFromGitHub(pub Option<String>);
|
pub struct FetchFromGitHub(pub Option<String>);
|
||||||
impl_fetcher!(FetchFromGitHub);
|
impl_fetcher!(FetchFromGitHub);
|
||||||
|
|
||||||
impl<'a> SimpleFlakeFetcher<'a> for FetchFromGitHub {
|
impl<'a> SimpleFetcher<'a> for FetchFromGitHub {
|
||||||
const FLAKE_TYPE: &'static str = "github";
|
|
||||||
const NAME: &'static str = "fetchFromGitHub";
|
const NAME: &'static str = "fetchFromGitHub";
|
||||||
|
|
||||||
fn host(&'a self) -> &'a Option<String> {
|
fn host(&'a self) -> &'a Option<String> {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> SimpleFlakeFetcher<'a> for FetchFromGitHub {
|
||||||
|
const FLAKE_TYPE: &'static str = "github";
|
||||||
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
use crate::{fetcher::SimpleFlakeFetcher, impl_fetcher};
|
use crate::{
|
||||||
|
fetcher::{SimpleFetcher, SimpleFlakeFetcher},
|
||||||
|
impl_fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct FetchFromGitLab(pub Option<String>);
|
pub struct FetchFromGitLab(pub Option<String>);
|
||||||
impl_fetcher!(FetchFromGitLab);
|
impl_fetcher!(FetchFromGitLab);
|
||||||
|
|
||||||
impl<'a> SimpleFlakeFetcher<'a> for FetchFromGitLab {
|
impl<'a> SimpleFetcher<'a> for FetchFromGitLab {
|
||||||
const FLAKE_TYPE: &'static str = "gitlab";
|
|
||||||
const NAME: &'static str = "fetchFromGitLab";
|
const NAME: &'static str = "fetchFromGitLab";
|
||||||
|
|
||||||
fn host(&'a self) -> &'a Option<String> {
|
fn host(&'a self) -> &'a Option<String> {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> SimpleFlakeFetcher<'a> for FetchFromGitLab {
|
||||||
|
const FLAKE_TYPE: &'static str = "gitlab";
|
||||||
|
}
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
use crate::{fetcher::UrlFlakeFetcher, impl_fetcher};
|
use crate::{
|
||||||
|
fetcher::{UrlFetcher, UrlFlakeFetcher},
|
||||||
|
impl_fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Fetchhg;
|
pub struct Fetchhg;
|
||||||
impl_fetcher!(Fetchhg);
|
impl_fetcher!(Fetchhg);
|
||||||
|
|
||||||
impl UrlFlakeFetcher for Fetchhg {
|
impl UrlFetcher for Fetchhg {
|
||||||
const FLAKE_TYPE: &'static str = "hg";
|
|
||||||
const NAME: &'static str = "fetchhg";
|
const NAME: &'static str = "fetchhg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UrlFlakeFetcher for Fetchhg {
|
||||||
|
const FLAKE_TYPE: &'static str = "hg";
|
||||||
|
}
|
||||||
|
@ -4,28 +4,43 @@ mod gitlab;
|
|||||||
mod hg;
|
mod hg;
|
||||||
mod sourcehut;
|
mod sourcehut;
|
||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
|
||||||
pub use git::Fetchgit;
|
pub use git::Fetchgit;
|
||||||
pub use github::FetchFromGitHub;
|
pub use github::FetchFromGitHub;
|
||||||
pub use gitlab::FetchFromGitLab;
|
pub use gitlab::FetchFromGitLab;
|
||||||
pub use hg::Fetchhg;
|
pub use hg::Fetchhg;
|
||||||
use indoc::writedoc;
|
|
||||||
use serde_json::json;
|
|
||||||
pub use sourcehut::FetchFromSourcehut;
|
pub use sourcehut::FetchFromSourcehut;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use indoc::writedoc;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
fmt::Write as _,
|
||||||
|
io::{BufRead, Write},
|
||||||
process::{Command, Output, Stdio},
|
process::{Command, Output, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait Fetcher {
|
pub trait Fetcher {
|
||||||
fn fetch_nix(&self, out: &mut impl Write, url: Url, rev: String, indent: String) -> Result<()>;
|
fn fetch_nix(
|
||||||
fn fetch_json(&self, out: &mut impl Write, url: Url, rev: String) -> Result<()>;
|
&self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
indent: String,
|
||||||
|
) -> Result<()>;
|
||||||
|
fn fetch_json(
|
||||||
|
&self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(Fetcher)]
|
#[enum_dispatch(Fetcher)]
|
||||||
@ -46,9 +61,10 @@ macro_rules! impl_fetcher {
|
|||||||
out: &mut impl ::std::io::Write,
|
out: &mut impl ::std::io::Write,
|
||||||
url: ::url::Url,
|
url: ::url::Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> ::anyhow::Result<()> {
|
) -> ::anyhow::Result<()> {
|
||||||
self.fetch_nix_impl(out, url, rev, indent)
|
self.fetch_nix_impl(out, url, rev, args, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json(
|
fn fetch_json(
|
||||||
@ -56,15 +72,15 @@ macro_rules! impl_fetcher {
|
|||||||
out: &mut impl ::std::io::Write,
|
out: &mut impl ::std::io::Write,
|
||||||
url: ::url::Url,
|
url: ::url::Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
) -> ::anyhow::Result<()> {
|
) -> ::anyhow::Result<()> {
|
||||||
self.fetch_json_impl(out, url, rev)
|
self.fetch_json_impl(out, url, rev, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SimpleFlakeFetcher<'a> {
|
pub trait SimpleFetcher<'a> {
|
||||||
const FLAKE_TYPE: &'static str;
|
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
|
|
||||||
fn host(&'a self) -> &'a Option<String>;
|
fn host(&'a self) -> &'a Option<String>;
|
||||||
@ -79,6 +95,109 @@ pub trait SimpleFlakeFetcher<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_fod(
|
||||||
|
&'a self,
|
||||||
|
url: &Url,
|
||||||
|
rev: &str,
|
||||||
|
args: &[(String, String)],
|
||||||
|
) -> Result<(String, String, String)> {
|
||||||
|
let (owner, repo) = self
|
||||||
|
.get_repo(url)
|
||||||
|
.with_context(|| format!("failed to parse {url}"))?;
|
||||||
|
|
||||||
|
let mut expr = format!(
|
||||||
|
r#"(import <nixpkgs> {{}}).{}{{owner="{owner}";repo="{repo}";rev="{rev}";hash="sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";"#,
|
||||||
|
Self::NAME
|
||||||
|
);
|
||||||
|
if let Some(host) = self.host() {
|
||||||
|
write!(expr, r#"domain="{host}""#)?;
|
||||||
|
}
|
||||||
|
for (key, value) in args {
|
||||||
|
write!(expr, "{key}={value};")?;
|
||||||
|
}
|
||||||
|
expr.push('}');
|
||||||
|
|
||||||
|
let hash = fod_prefetch(expr)?;
|
||||||
|
|
||||||
|
Ok((owner, repo, hash))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SimpleFodFetcher<'a>: SimpleFetcher<'a> {
|
||||||
|
fn fetch_nix_impl(
|
||||||
|
&'a self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
indent: String,
|
||||||
|
) -> Result<()> {
|
||||||
|
let (owner, repo, hash) = self.fetch_fod(&url, &rev, &args)?;
|
||||||
|
|
||||||
|
writeln!(out, "{} {{", Self::NAME)?;
|
||||||
|
|
||||||
|
if let Some(domain) = self.host() {
|
||||||
|
writeln!(out, r#"{indent} domain = "{domain}";"#)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writedoc!(
|
||||||
|
out,
|
||||||
|
r#"
|
||||||
|
{indent} owner = "{owner}";
|
||||||
|
{indent} repo = "{repo}";
|
||||||
|
{indent} rev = "{rev}";
|
||||||
|
{indent} hash = "{hash}";
|
||||||
|
"#
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(out, "{indent}}}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_json_impl(
|
||||||
|
&'a self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let (owner, repo, hash) = self.fetch_fod(&url, &rev, &args)?;
|
||||||
|
|
||||||
|
let mut fetcher_args = json! ({
|
||||||
|
"owner": owner,
|
||||||
|
"repo": repo,
|
||||||
|
"rev": rev,
|
||||||
|
"hash": hash,
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(host) = self.host() {
|
||||||
|
fetcher_args["host"] = json!(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
fetcher_args[key] = json!(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::to_writer(
|
||||||
|
out,
|
||||||
|
&json!({
|
||||||
|
"fetcher": Self::NAME,
|
||||||
|
"args": fetcher_args,
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SimpleFlakeFetcher<'a>: SimpleFetcher<'a> {
|
||||||
|
const FLAKE_TYPE: &'static str;
|
||||||
|
|
||||||
fn fetch(&'a self, url: &Url, rev: &str) -> Result<(String, String, String)> {
|
fn fetch(&'a self, url: &Url, rev: &str) -> Result<(String, String, String)> {
|
||||||
let (owner, repo) = self
|
let (owner, repo) = self
|
||||||
.get_repo(url)
|
.get_repo(url)
|
||||||
@ -98,9 +217,14 @@ pub trait SimpleFlakeFetcher<'a> {
|
|||||||
out: &mut impl Write,
|
out: &mut impl Write,
|
||||||
url: Url,
|
url: Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (owner, repo, hash) = self.fetch(&url, &rev)?;
|
let (owner, repo, hash) = if args.is_empty() {
|
||||||
|
self.fetch(&url, &rev)?
|
||||||
|
} else {
|
||||||
|
self.fetch_fod(&url, &rev, &args)?
|
||||||
|
};
|
||||||
|
|
||||||
writeln!(out, "{} {{", Self::NAME)?;
|
writeln!(out, "{} {{", Self::NAME)?;
|
||||||
|
|
||||||
@ -115,16 +239,32 @@ pub trait SimpleFlakeFetcher<'a> {
|
|||||||
{indent} repo = "{repo}";
|
{indent} repo = "{repo}";
|
||||||
{indent} rev = "{rev}";
|
{indent} rev = "{rev}";
|
||||||
{indent} hash = "{hash}";
|
{indent} hash = "{hash}";
|
||||||
{indent}}}"#,
|
"#
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(out, "{indent}}}")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json_impl(&'a self, out: &mut impl Write, url: Url, rev: String) -> Result<()> {
|
fn fetch_json_impl(
|
||||||
let (owner, repo, hash) = self.fetch(&url, &rev)?;
|
&'a self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let (owner, repo, hash) = if args.is_empty() {
|
||||||
|
self.fetch(&url, &rev)?
|
||||||
|
} else {
|
||||||
|
self.fetch_fod(&url, &rev, &args)?
|
||||||
|
};
|
||||||
|
|
||||||
let mut args = json! ({
|
let mut fetcher_args = json! ({
|
||||||
"owner": owner,
|
"owner": owner,
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
"rev": rev,
|
"rev": rev,
|
||||||
@ -132,14 +272,18 @@ pub trait SimpleFlakeFetcher<'a> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(host) = self.host() {
|
if let Some(host) = self.host() {
|
||||||
args["host"] = json!(host);
|
fetcher_args["host"] = json!(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
fetcher_args[key] = json!(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_json::to_writer(
|
serde_json::to_writer(
|
||||||
out,
|
out,
|
||||||
&json!({
|
&json!({
|
||||||
"fetcher": Self::NAME,
|
"fetcher": Self::NAME,
|
||||||
"args": args,
|
"args": fetcher_args,
|
||||||
}),
|
}),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -147,10 +291,57 @@ pub trait SimpleFlakeFetcher<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UrlFlakeFetcher {
|
pub trait UrlFetcher {
|
||||||
const FLAKE_TYPE: &'static str;
|
|
||||||
const NAME: &'static str;
|
const NAME: &'static str;
|
||||||
|
|
||||||
|
fn fetch_fod(&self, url: &Url, rev: &str, args: &[(String, String)]) -> Result<String> {
|
||||||
|
let mut expr = format!(
|
||||||
|
r#"(import <nixpkgs> {{}}).{}{{url="{url}";rev="{rev}";hash="sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";"#,
|
||||||
|
Self::NAME
|
||||||
|
);
|
||||||
|
for (key, value) in args {
|
||||||
|
write!(expr, "{key}={value};")?;
|
||||||
|
}
|
||||||
|
expr.push('}');
|
||||||
|
fod_prefetch(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UrlFodFetcher: UrlFetcher {
|
||||||
|
fn fetch_nix_impl(
|
||||||
|
&self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
indent: String,
|
||||||
|
) -> Result<()> {
|
||||||
|
let hash = self.fetch_fod(&url, &rev, &args)?;
|
||||||
|
|
||||||
|
writedoc!(
|
||||||
|
out,
|
||||||
|
r#"
|
||||||
|
{} {{
|
||||||
|
{indent} url = "{url}";
|
||||||
|
{indent} rev = "{rev}";
|
||||||
|
{indent} hash = "{hash}";
|
||||||
|
"#,
|
||||||
|
Self::NAME
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(out, "{indent}}}")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UrlFlakeFetcher: UrlFetcher {
|
||||||
|
const FLAKE_TYPE: &'static str;
|
||||||
|
|
||||||
fn fetch(&self, url: &Url, rev: &str) -> Result<String> {
|
fn fetch(&self, url: &Url, rev: &str) -> Result<String> {
|
||||||
flake_prefetch(format!(
|
flake_prefetch(format!(
|
||||||
"{}+{url}?{}={rev}",
|
"{}+{url}?{}={rev}",
|
||||||
@ -164,9 +355,14 @@ pub trait UrlFlakeFetcher {
|
|||||||
out: &mut impl Write,
|
out: &mut impl Write,
|
||||||
url: Url,
|
url: Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let hash = self.fetch(&url, &rev)?;
|
let hash = if args.is_empty() {
|
||||||
|
self.fetch(&url, &rev)?
|
||||||
|
} else {
|
||||||
|
self.fetch_fod(&url, &rev, &args)?
|
||||||
|
};
|
||||||
|
|
||||||
writedoc!(
|
writedoc!(
|
||||||
out,
|
out,
|
||||||
@ -175,15 +371,41 @@ pub trait UrlFlakeFetcher {
|
|||||||
{indent} url = "{url}";
|
{indent} url = "{url}";
|
||||||
{indent} rev = "{rev}";
|
{indent} rev = "{rev}";
|
||||||
{indent} hash = "{hash}";
|
{indent} hash = "{hash}";
|
||||||
{indent}}}"#,
|
"#,
|
||||||
Self::NAME,
|
Self::NAME
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(out, "{indent}}}")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json_impl(&self, out: &mut impl Write, url: Url, rev: String) -> Result<()> {
|
fn fetch_json_impl(
|
||||||
let hash = self.fetch(&url, &rev)?;
|
&self,
|
||||||
|
out: &mut impl Write,
|
||||||
|
url: Url,
|
||||||
|
rev: String,
|
||||||
|
args: Vec<(String, String)>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let hash = if args.is_empty() {
|
||||||
|
self.fetch(&url, &rev)?
|
||||||
|
} else {
|
||||||
|
self.fetch_fod(&url, &rev, &args)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut fetcher_args = json!({
|
||||||
|
"url": url.to_string(),
|
||||||
|
"rev": rev,
|
||||||
|
"hash": hash,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (key, value) in args {
|
||||||
|
fetcher_args[key] = json!(value);
|
||||||
|
}
|
||||||
|
|
||||||
serde_json::to_writer(
|
serde_json::to_writer(
|
||||||
out,
|
out,
|
||||||
@ -232,3 +454,44 @@ pub fn flake_prefetch(flake_ref: String) -> Result<String> {
|
|||||||
)?
|
)?
|
||||||
.hash)
|
.hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fod_prefetch(expr: String) -> Result<String> {
|
||||||
|
eprintln!("$ nix build --impure --no-link --expr '{expr}'");
|
||||||
|
|
||||||
|
let Output {
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
status,
|
||||||
|
} = Command::new("nix")
|
||||||
|
.arg("build")
|
||||||
|
.arg("--impure")
|
||||||
|
.arg("--no-link")
|
||||||
|
.arg("--expr")
|
||||||
|
.arg(expr)
|
||||||
|
.output()?;
|
||||||
|
|
||||||
|
if status.success() {
|
||||||
|
bail!(
|
||||||
|
"command succeeded unexpectedly\nstdout:\n{}",
|
||||||
|
String::from_utf8_lossy(&stdout),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lines = stderr.lines();
|
||||||
|
while let Some(line) = lines.next() {
|
||||||
|
if !matches!(line, Ok(line) if line.trim_start().starts_with("specified:")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(line) = lines.next() else { break; };
|
||||||
|
if let Ok(line) = line {
|
||||||
|
let Some(hash) = line.trim_start().strip_prefix("got:") else { continue; };
|
||||||
|
return Ok(hash.trim().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow!(
|
||||||
|
"failed to find the hash from error messages\nstdout: {}\nstderr:\n{}",
|
||||||
|
String::from_utf8_lossy(&stdout),
|
||||||
|
String::from_utf8_lossy(&stderr),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
use crate::{fetcher::SimpleFlakeFetcher, impl_fetcher};
|
use crate::{
|
||||||
|
fetcher::{SimpleFetcher, SimpleFlakeFetcher},
|
||||||
|
impl_fetcher,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct FetchFromSourcehut(pub Option<String>);
|
pub struct FetchFromSourcehut(pub Option<String>);
|
||||||
impl_fetcher!(FetchFromSourcehut);
|
impl_fetcher!(FetchFromSourcehut);
|
||||||
|
|
||||||
impl<'a> SimpleFlakeFetcher<'a> for FetchFromSourcehut {
|
impl<'a> SimpleFetcher<'a> for FetchFromSourcehut {
|
||||||
const FLAKE_TYPE: &'static str = "sourcehut";
|
|
||||||
const NAME: &'static str = "fetchFromSourcehut";
|
const NAME: &'static str = "fetchFromSourcehut";
|
||||||
|
|
||||||
fn host(&'a self) -> &'a Option<String> {
|
fn host(&'a self) -> &'a Option<String> {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> SimpleFlakeFetcher<'a> for FetchFromSourcehut {
|
||||||
|
const FLAKE_TYPE: &'static str = "sourcehut";
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ mod fetcher;
|
|||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
|
use itertools::Itertools;
|
||||||
use url::Host;
|
use url::Host;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -73,10 +74,11 @@ fn main() -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let out = &mut stdout().lock();
|
let out = &mut stdout().lock();
|
||||||
|
let args = opts.args.into_iter().tuples().collect();
|
||||||
if opts.json {
|
if opts.json {
|
||||||
fetcher.fetch_json(out, opts.url, opts.rev)
|
fetcher.fetch_json(out, opts.url, opts.rev, args)
|
||||||
} else {
|
} else {
|
||||||
fetcher.fetch_nix(out, opts.url, opts.rev, " ".repeat(opts.indent))
|
fetcher.fetch_nix(out, opts.url, opts.rev, args, " ".repeat(opts.indent))
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user