mirror of
https://github.com/nix-community/nurl.git
synced 2024-09-11 10:10:39 +03:00
add --overwrite and --overwrite-str
This commit is contained in:
parent
834bb2cedc
commit
6dc540c192
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -172,12 +172,6 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indoc"
|
|
||||||
version = "1.0.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -242,9 +236,9 @@ dependencies = [
|
|||||||
"clap_complete",
|
"clap_complete",
|
||||||
"clap_mangen",
|
"clap_mangen",
|
||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"indoc",
|
|
||||||
"itertools",
|
"itertools",
|
||||||
"owo-colors",
|
"owo-colors",
|
||||||
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url",
|
"url",
|
||||||
@ -325,6 +319,12 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.36.6"
|
version = "0.36.6"
|
||||||
|
@ -14,9 +14,9 @@ categories = ["command-line-utilities"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.68"
|
anyhow = "1.0.68"
|
||||||
enum_dispatch = "0.3.9"
|
enum_dispatch = "0.3.9"
|
||||||
indoc = "1.0.8"
|
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
owo-colors = { version = "3.5.0", features = ["supports-colors"] }
|
owo-colors = { version = "3.5.0", features = ["supports-colors"] }
|
||||||
|
rustc-hash = "1.1.0"
|
||||||
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"
|
||||||
|
21
src/cli.rs
21
src/cli.rs
@ -38,6 +38,27 @@ pub struct Opts {
|
|||||||
#[arg(short, long = "arg", num_args = 2, value_names = ["KEY", "VALUE"])]
|
#[arg(short, long = "arg", num_args = 2, value_names = ["KEY", "VALUE"])]
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
|
|
||||||
|
/// overwrite arguments in the final output,
|
||||||
|
/// not taken into consideration when fetching the hash
|
||||||
|
///
|
||||||
|
/// Note that nurl does not verify any of the overwrites,
|
||||||
|
/// for the final output to be valid,
|
||||||
|
/// the user should not overwrite anything that would change the hash
|
||||||
|
///
|
||||||
|
/// examples:
|
||||||
|
/// {n} --overwrite repo pname
|
||||||
|
/// {n} --overwrite rev version
|
||||||
|
#[arg(short, long = "overwrite", num_args = 2, value_names = ["NAME", "EXPR"])]
|
||||||
|
pub overwrites: Vec<String>,
|
||||||
|
|
||||||
|
/// same as --overwrite, but accepts strings instead Nix expressions
|
||||||
|
///
|
||||||
|
/// examples:
|
||||||
|
/// {n} --overwrite-str rev 'v${version}'
|
||||||
|
/// {n} --overwrite-str meta.homepage https://example.org
|
||||||
|
#[arg(short = 'O', long = "overwrite-str", num_args = 2, value_names = ["NAME", "STRING"])]
|
||||||
|
pub overwrites_str: 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,
|
||||||
|
@ -20,6 +20,7 @@ pub use sourcehut::FetchFromSourcehut;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -32,6 +33,7 @@ pub trait Fetcher {
|
|||||||
url: &Url,
|
url: &Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
fn fetch_json(
|
fn fetch_json(
|
||||||
@ -40,6 +42,8 @@ pub trait Fetcher {
|
|||||||
url: &Url,
|
url: &Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,9 +70,10 @@ macro_rules! impl_fetcher {
|
|||||||
url: &::url::Url,
|
url: &::url::Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: ::rustc_hash::FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> ::anyhow::Result<()> {
|
) -> ::anyhow::Result<()> {
|
||||||
self.fetch_nix_impl(out, url, rev, args, indent)
|
self.fetch_nix_impl(out, url, rev, args, overwrites, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json(
|
fn fetch_json(
|
||||||
@ -77,8 +82,10 @@ macro_rules! impl_fetcher {
|
|||||||
url: &::url::Url,
|
url: &::url::Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> ::anyhow::Result<()> {
|
) -> ::anyhow::Result<()> {
|
||||||
self.fetch_json_impl(out, url, rev, args)
|
self.fetch_json_impl(out, url, rev, args, overwrites, overwrites_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
25
src/main.rs
25
src/main.rs
@ -8,6 +8,7 @@ mod simple;
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{FetcherFunction, Opts},
|
cli::{FetcherFunction, Opts},
|
||||||
@ -100,9 +101,29 @@ fn main() -> Result<()> {
|
|||||||
let out = &mut stdout().lock();
|
let out = &mut stdout().lock();
|
||||||
let args = opts.args.into_iter().tuples().collect();
|
let args = opts.args.into_iter().tuples().collect();
|
||||||
if opts.json {
|
if opts.json {
|
||||||
fetcher.fetch_json(out, &opts.url, opts.rev, args)
|
fetcher.fetch_json(
|
||||||
|
out,
|
||||||
|
&opts.url,
|
||||||
|
opts.rev,
|
||||||
|
args,
|
||||||
|
opts.overwrites.into_iter().tuples().collect(),
|
||||||
|
opts.overwrites_str.into_iter().tuples().collect(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
fetcher.fetch_nix(out, &opts.url, opts.rev, args, " ".repeat(opts.indent))
|
let mut overwrites: FxHashMap<_, _> = opts.overwrites.into_iter().tuples().collect();
|
||||||
|
|
||||||
|
for (key, value) in opts.overwrites_str.into_iter().tuples() {
|
||||||
|
overwrites.insert(key, format!(r#""{value}""#));
|
||||||
|
}
|
||||||
|
|
||||||
|
fetcher.fetch_nix(
|
||||||
|
out,
|
||||||
|
&opts.url,
|
||||||
|
opts.rev,
|
||||||
|
args,
|
||||||
|
overwrites,
|
||||||
|
" ".repeat(opts.indent),
|
||||||
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use indoc::writedoc;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -73,27 +73,43 @@ pub trait SimpleFetcher<'a, const N: usize = 2> {
|
|||||||
rev: String,
|
rev: String,
|
||||||
hash: String,
|
hash: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let mut overwrites = overwrites;
|
||||||
|
|
||||||
writeln!(out, "{} {{", Self::NAME)?;
|
writeln!(out, "{} {{", Self::NAME)?;
|
||||||
|
|
||||||
if let Some(host) = self.host() {
|
if let Some(host) = overwrites.remove(Self::HOST_KEY) {
|
||||||
|
writeln!(out, r#"{indent} {} = {host};"#, Self::HOST_KEY)?;
|
||||||
|
} else if let Some(host) = self.host() {
|
||||||
writeln!(out, r#"{indent} {} = "{host}";"#, Self::HOST_KEY)?;
|
writeln!(out, r#"{indent} {} = "{host}";"#, Self::HOST_KEY)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in Self::KEYS.iter().zip(values) {
|
for (key, value) in Self::KEYS.iter().zip(values) {
|
||||||
writeln!(out, r#"{indent} {key} = "{value}";"#)?;
|
if let Some(value) = overwrites.remove(*key) {
|
||||||
|
writeln!(out, r#"{indent} {key} = {value};"#)?;
|
||||||
|
} else {
|
||||||
|
writeln!(out, r#"{indent} {key} = "{value}";"#)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writedoc!(
|
if let Some(rev) = overwrites.remove("rev") {
|
||||||
out,
|
writeln!(out, "{indent} rev = {rev};")?;
|
||||||
r#"
|
} else {
|
||||||
{indent} rev = "{rev}";
|
writeln!(out, r#"{indent} rev = "{rev}";"#)?;
|
||||||
{indent} hash = "{hash}";
|
}
|
||||||
"#
|
if let Some(hash) = overwrites.remove("hash") {
|
||||||
)?;
|
writeln!(out, "{indent} hash = {hash};")?;
|
||||||
|
} else {
|
||||||
|
writeln!(out, r#"{indent} hash = "{hash}";"#)?;
|
||||||
|
}
|
||||||
|
|
||||||
for (key, value) in args {
|
for (key, value) in args {
|
||||||
|
let value = overwrites.remove(&key).unwrap_or(value);
|
||||||
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
|
}
|
||||||
|
for (key, value) in overwrites {
|
||||||
writeln!(out, "{indent} {key} = {value};")?;
|
writeln!(out, "{indent} {key} = {value};")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +125,8 @@ pub trait SimpleFetcher<'a, const N: usize = 2> {
|
|||||||
rev: String,
|
rev: String,
|
||||||
hash: String,
|
hash: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut fetcher_args = json! ({
|
let mut fetcher_args = json! ({
|
||||||
"rev": rev,
|
"rev": rev,
|
||||||
@ -130,6 +148,16 @@ pub trait SimpleFetcher<'a, const N: usize = 2> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (key, value) in overwrites {
|
||||||
|
fetcher_args[key] = json!({
|
||||||
|
"type": "nix",
|
||||||
|
"value": value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (key, value) in overwrites_str {
|
||||||
|
fetcher_args[key] = json!(value);
|
||||||
|
}
|
||||||
|
|
||||||
serde_json::to_writer(
|
serde_json::to_writer(
|
||||||
out,
|
out,
|
||||||
&json!({
|
&json!({
|
||||||
@ -149,10 +177,11 @@ pub trait SimpleFodFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = self.fetch_fod(url, &rev, &args)?;
|
let (values, hash) = self.fetch_fod(url, &rev, &args)?;
|
||||||
self.write_nix(out, values, rev, hash, args, indent)
|
self.write_nix(out, values, rev, hash, args, overwrites, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json_impl(
|
fn fetch_json_impl(
|
||||||
@ -161,9 +190,11 @@ pub trait SimpleFodFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = self.fetch_fod(url, &rev, &args)?;
|
let (values, hash) = self.fetch_fod(url, &rev, &args)?;
|
||||||
self.write_json(out, values, rev, hash, args)
|
self.write_json(out, values, rev, hash, args, overwrites, overwrites_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +229,7 @@ pub trait SimpleFlakeFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = if args.is_empty() {
|
let (values, hash) = if args.is_empty() {
|
||||||
@ -206,7 +238,7 @@ pub trait SimpleFlakeFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
self.fetch_fod(url, &rev, &args)?
|
self.fetch_fod(url, &rev, &args)?
|
||||||
};
|
};
|
||||||
|
|
||||||
self.write_nix(out, values, rev, hash, args, indent)
|
self.write_nix(out, values, rev, hash, args, overwrites, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json_impl(
|
fn fetch_json_impl(
|
||||||
@ -215,13 +247,15 @@ pub trait SimpleFlakeFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = if args.is_empty() {
|
let (values, hash) = if args.is_empty() {
|
||||||
self.fetch(url, &rev)?
|
self.fetch(url, &rev)?
|
||||||
} else {
|
} else {
|
||||||
self.fetch_fod(url, &rev, &args)?
|
self.fetch_fod(url, &rev, &args)?
|
||||||
};
|
};
|
||||||
self.write_json(out, values, rev, hash, args)
|
self.write_json(out, values, rev, hash, args, overwrites, overwrites_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +276,7 @@ pub trait SimpleUrlFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: FxHashMap<String, String>,
|
||||||
indent: String,
|
indent: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = if args.is_empty() {
|
let (values, hash) = if args.is_empty() {
|
||||||
@ -250,7 +285,7 @@ pub trait SimpleUrlFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
self.fetch_fod(url, &rev, &args)?
|
self.fetch_fod(url, &rev, &args)?
|
||||||
};
|
};
|
||||||
|
|
||||||
self.write_nix(out, values, rev, hash, args, indent)
|
self.write_nix(out, values, rev, hash, args, overwrites, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_json_impl(
|
fn fetch_json_impl(
|
||||||
@ -259,12 +294,14 @@ pub trait SimpleUrlFetcher<'a, const N: usize = 2>: SimpleFetcher<'a, N> {
|
|||||||
url: &'a Url,
|
url: &'a Url,
|
||||||
rev: String,
|
rev: String,
|
||||||
args: Vec<(String, String)>,
|
args: Vec<(String, String)>,
|
||||||
|
overwrites: Vec<(String, String)>,
|
||||||
|
overwrites_str: Vec<(String, String)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (values, hash) = if args.is_empty() {
|
let (values, hash) = if args.is_empty() {
|
||||||
self.fetch(url, &rev)?
|
self.fetch(url, &rev)?
|
||||||
} else {
|
} else {
|
||||||
self.fetch_fod(url, &rev, &args)?
|
self.fetch_fod(url, &rev, &args)?
|
||||||
};
|
};
|
||||||
self.write_json(out, values, rev, hash, args)
|
self.write_json(out, values, rev, hash, args, overwrites, overwrites_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user