From 7cfa450a23a33eea1e658a39f27fc95c1ff72338 Mon Sep 17 00:00:00 2001 From: figsoda Date: Sun, 15 Jan 2023 11:37:05 -0500 Subject: [PATCH] support builtins.fetchGit --- src/cli.rs | 2 + src/fetcher/builtin_git.rs | 139 +++++++++++++++++++++++++++ src/fetcher/mod.rs | 3 + src/main.rs | 9 +- tests/cmd/fetcher/builtin_git.stdout | 4 + tests/cmd/fetcher/builtin_git.toml | 6 ++ tests/integration.rs | 13 ++- 7 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 src/fetcher/builtin_git.rs create mode 100644 tests/cmd/fetcher/builtin_git.stdout create mode 100644 tests/cmd/fetcher/builtin_git.toml diff --git a/src/cli.rs b/src/cli.rs index 3e05ef3..1b31986 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -90,6 +90,8 @@ pub struct Opts { #[derive(Clone, Debug, ValueEnum)] #[clap(rename_all = "camelCase")] pub enum FetcherFunction { + #[clap(name = "builtins.fetchGit")] + BuiltinsFetchGit, FetchCrate, FetchFromBitbucket, FetchFromGitHub, diff --git a/src/fetcher/builtin_git.rs b/src/fetcher/builtin_git.rs new file mode 100644 index 0000000..b113ea9 --- /dev/null +++ b/src/fetcher/builtin_git.rs @@ -0,0 +1,139 @@ +use anyhow::{bail, Context, Result}; +use rustc_hash::FxHashMap; +use serde_json::json; +use url::Url; + +use std::io::Write; + +use crate::fetcher::Fetcher; + +pub struct BuiltinsFetchGit; + +impl<'a> Fetcher<'a> for BuiltinsFetchGit { + fn fetch_nix( + &'a self, + out: &mut impl Write, + url: &'a Url, + rev: Option, + args: Vec<(String, String)>, + args_str: Vec<(String, String)>, + overwrites: FxHashMap, + indent: String, + ) -> Result<()> { + let mut overwrites = overwrites; + let rev = rev.context("builtins.fetchGit does not support feching the latest revision")?; + let rev_type = if rev.len() == 40 { "rev" } else { "ref" }; + + writeln!(out, "builtins.fetchGit {{")?; + + if let Some(url) = overwrites.remove("url") { + writeln!(out, "{indent} {url} = {url};")?; + } else { + writeln!(out, r#"{indent} url = "{url}";"#)?; + } + + if let Some(rev) = overwrites.remove(rev_type) { + writeln!(out, "{indent} {} = {rev};", rev_type)?; + } else { + writeln!(out, r#"{indent} {} = "{rev}";"#, rev_type)?; + } + + for (key, value) in args { + let value = overwrites.remove(&key).unwrap_or(value); + writeln!(out, "{indent} {key} = {value};")?; + } + for (key, value) in args_str { + if let Some(value) = overwrites.remove(&key) { + writeln!(out, "{indent} {key} = {value};")?; + } else { + writeln!(out, r#"{indent} {key} = "{value}";"#)?; + } + } + + for (key, value) in overwrites { + writeln!(out, "{indent} {key} = {value};")?; + } + + write!(out, "{indent}}}")?; + + Ok(()) + } + + fn fetch_hash( + &'a self, + _: &mut impl Write, + _: &'a Url, + _: Option, + _: Vec<(String, String)>, + _: Vec<(String, String)>, + ) -> Result<()> { + bail!("builtins.fetchGit does not support hashes"); + } + + fn fetch_json( + &'a self, + out: &mut impl Write, + url: &'a Url, + rev: Option, + args: Vec<(String, String)>, + args_str: Vec<(String, String)>, + overwrites: Vec<(String, String)>, + overwrites_str: Vec<(String, String)>, + ) -> Result<()> { + let rev = rev.context("builtins.fetchGit does not support feching the latest revision")?; + let rev_type = if rev.len() == 40 { "rev" } else { "ref" }; + + let mut fetcher_args = json!({ + "url": url.to_string(), + rev_type: rev, + }); + + for (key, value) in args { + fetcher_args[key] = json!({ + "type": "nix", + "value": value, + }); + } + for (key, value) in args_str { + fetcher_args[key] = json!(value); + } + + 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( + out, + &json!({ + "fetcher": "builtins.fetchGit", + "args": fetcher_args, + }), + )?; + + Ok(()) + } + + fn to_json(&'a self, out: &mut impl Write, url: &'a Url, rev: Option) -> Result<()> { + let rev = rev.context("builtins.fetchGit does not support feching the latest revision")?; + let rev_type = if rev.len() == 40 { "rev" } else { "ref" }; + + serde_json::to_writer( + out, + &json!({ + "fetcher": "builtins.fetchGit", + "args": { + "url": url.to_string(), + rev_type: rev, + }, + }), + )?; + + Ok(()) + } +} diff --git a/src/fetcher/mod.rs b/src/fetcher/mod.rs index bd593aa..41e4385 100644 --- a/src/fetcher/mod.rs +++ b/src/fetcher/mod.rs @@ -1,4 +1,5 @@ mod bitbucket; +mod builtin_git; mod crates_io; mod git; mod gitea; @@ -12,6 +13,7 @@ mod sourcehut; mod svn; pub use bitbucket::FetchFromBitbucket; +pub use builtin_git::BuiltinsFetchGit; pub use crates_io::FetchCrate; pub use git::Fetchgit; pub use gitea::FetchFromGitea; @@ -74,6 +76,7 @@ pub trait Fetcher<'a> { #[enum_dispatch(Fetcher)] pub enum FetcherDispatch<'a> { + BuiltinsFetchGit(BuiltinsFetchGit), FetchCrate(FetchCrate), FetchFromBitbucket(FetchFromBitbucket), FetchFromGitHub(FetchFromGitHub<'a>), diff --git a/src/main.rs b/src/main.rs index 3d6ba28..082d578 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,8 @@ use rustc_hash::FxHashMap; use crate::{ cli::{FetcherFunction, Opts}, fetcher::{ - FetchCrate, FetchFromBitbucket, FetchFromGitHub, FetchFromGitLab, FetchFromGitea, - FetchFromGitiles, FetchFromRepoOrCz, FetchFromSourcehut, FetchHex, Fetcher, + BuiltinsFetchGit, FetchCrate, FetchFromBitbucket, FetchFromGitHub, FetchFromGitLab, + FetchFromGitea, FetchFromGitiles, FetchFromRepoOrCz, FetchFromSourcehut, FetchHex, Fetcher, FetcherDispatch, Fetchgit, Fetchhg, Fetchsvn, }, }; @@ -34,6 +34,9 @@ fn main() -> Result<()> { let mut out = stdout().lock(); let fetchers = FetcherFunction::value_variants() .iter() + .filter(|fetcher| { + opts.list_fetchers || !matches!(fetcher, FetcherFunction::BuiltinsFetchGit) + }) .filter_map(ValueEnum::to_possible_value); if let Some(sep) = opts.list_sep { @@ -54,6 +57,8 @@ fn main() -> Result<()> { } let fetcher: FetcherDispatch = match (opts.fetcher, opts.url.host_str(), opts.url.scheme()) { + (Some(FetcherFunction::BuiltinsFetchGit), ..) => BuiltinsFetchGit.into(), + (None | Some(FetcherFunction::FetchCrate), Some("crates.io"), _) => FetchCrate(true).into(), (None | Some(FetcherFunction::FetchCrate), Some("lib.rs"), _) => FetchCrate(false).into(), (Some(FetcherFunction::FetchCrate), ..) => { diff --git a/tests/cmd/fetcher/builtin_git.stdout b/tests/cmd/fetcher/builtin_git.stdout new file mode 100644 index 0000000..0b0eb1d --- /dev/null +++ b/tests/cmd/fetcher/builtin_git.stdout @@ -0,0 +1,4 @@ +builtins.fetchGit { + url = "https://github.com/nix-community/nurl"; + ref = "refs/tags/v0.3.0"; +} \ No newline at end of file diff --git a/tests/cmd/fetcher/builtin_git.toml b/tests/cmd/fetcher/builtin_git.toml new file mode 100644 index 0000000..2d604a8 --- /dev/null +++ b/tests/cmd/fetcher/builtin_git.toml @@ -0,0 +1,6 @@ +args = [ + "https://github.com/nix-community/nurl", + "refs/tags/v0.3.0", + "--fetcher", + "builtins.fetchGit", +] diff --git a/tests/integration.rs b/tests/integration.rs index 5eb851f..f77eca9 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -31,12 +31,15 @@ fn verify_outputs() { eprintln!("testing {}", path.display()); let mut expr = String::from_utf8(fs::read(&path).unwrap()).unwrap(); - expr.insert_str(0, "(import { })."); - if name == "overwrite" { - expr.insert_str(0, r#"let pname = "nurl"; in "#); - } else if name == "overwrite_str" { - expr.insert_str(0, r#"let version = "0.3.0"; in "#); + if name != "builtin_git" { + expr.insert_str(0, "(import { })."); + + if name == "overwrite" { + expr.insert_str(0, r#"let pname = "nurl"; in "#); + } else if name == "overwrite_str" { + expr.insert_str(0, r#"let version = "0.3.0"; in "#); + } } Command::new("nix")