mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
feat: Support parse string as git/gitoxide features from ENV and Config
- pass true to enable all pre-definded git/gitoxide features - support parse git/gitoxide as table in Config, if the field is tagged with #[serde(default)], then it can be skipped
This commit is contained in:
parent
b176adbfe1
commit
ee87c915d3
@ -764,7 +764,9 @@ unstable_cli_options!(
|
|||||||
dual_proc_macros: bool = ("Build proc-macros for both the host and the target"),
|
dual_proc_macros: bool = ("Build proc-macros for both the host and the target"),
|
||||||
features: Option<Vec<String>>,
|
features: Option<Vec<String>>,
|
||||||
gc: bool = ("Track cache usage and \"garbage collect\" unused files"),
|
gc: bool = ("Track cache usage and \"garbage collect\" unused files"),
|
||||||
|
#[serde(deserialize_with = "deserialize_git_features")]
|
||||||
git: Option<GitFeatures> = ("Enable support for shallow git fetch operations"),
|
git: Option<GitFeatures> = ("Enable support for shallow git fetch operations"),
|
||||||
|
#[serde(deserialize_with = "deserialize_gitoxide_features")]
|
||||||
gitoxide: Option<GitoxideFeatures> = ("Use gitoxide for the given git interactions, or all of them if no argument is given"),
|
gitoxide: Option<GitoxideFeatures> = ("Use gitoxide for the given git interactions, or all of them if no argument is given"),
|
||||||
host_config: bool = ("Enable the `[host]` section in the .cargo/config.toml file"),
|
host_config: bool = ("Enable the `[host]` section in the .cargo/config.toml file"),
|
||||||
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
|
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
|
||||||
@ -874,7 +876,8 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Default, Deserialize)]
|
#[derive(Debug, Copy, Clone, Default, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct GitFeatures {
|
pub struct GitFeatures {
|
||||||
/// When cloning the index, perform a shallow clone. Maintain shallowness upon subsequent fetches.
|
/// When cloning the index, perform a shallow clone. Maintain shallowness upon subsequent fetches.
|
||||||
pub shallow_index: bool,
|
pub shallow_index: bool,
|
||||||
@ -883,12 +886,71 @@ pub struct GitFeatures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GitFeatures {
|
impl GitFeatures {
|
||||||
fn all() -> Self {
|
pub fn all() -> Self {
|
||||||
GitFeatures {
|
GitFeatures {
|
||||||
shallow_index: true,
|
shallow_index: true,
|
||||||
shallow_deps: true,
|
shallow_deps: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expecting() -> String {
|
||||||
|
let fields = vec!["`shallow-index`", "`shallow-deps`"];
|
||||||
|
format!(
|
||||||
|
"unstable 'git' only takes {} as valid inputs",
|
||||||
|
fields.join(" and ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_git_features<'de, D>(deserializer: D) -> Result<Option<GitFeatures>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GitFeaturesVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GitFeaturesVisitor {
|
||||||
|
type Value = Option<GitFeatures>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
formatter.write_str(&GitFeatures::expecting())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
if v {
|
||||||
|
Ok(Some(GitFeatures::all()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(parse_git(s.split(",")).map_err(serde::de::Error::custom)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let git = GitFeatures::deserialize(deserializer)?;
|
||||||
|
Ok(Some(git))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mvd = serde::de::value::MapAccessDeserializer::new(map);
|
||||||
|
Ok(Some(GitFeatures::deserialize(mvd)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(GitFeaturesVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_git(it: impl Iterator<Item = impl AsRef<str>>) -> CargoResult<Option<GitFeatures>> {
|
fn parse_git(it: impl Iterator<Item = impl AsRef<str>>) -> CargoResult<Option<GitFeatures>> {
|
||||||
@ -903,16 +965,15 @@ fn parse_git(it: impl Iterator<Item = impl AsRef<str>>) -> CargoResult<Option<Gi
|
|||||||
"shallow-index" => *shallow_index = true,
|
"shallow-index" => *shallow_index = true,
|
||||||
"shallow-deps" => *shallow_deps = true,
|
"shallow-deps" => *shallow_deps = true,
|
||||||
_ => {
|
_ => {
|
||||||
bail!(
|
bail!(GitFeatures::expecting())
|
||||||
"unstable 'git' only takes 'shallow-index' and 'shallow-deps' as valid inputs"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(out))
|
Ok(Some(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Default, Deserialize)]
|
#[derive(Debug, Copy, Clone, Default, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct GitoxideFeatures {
|
pub struct GitoxideFeatures {
|
||||||
/// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index.
|
/// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index.
|
||||||
pub fetch: bool,
|
pub fetch: bool,
|
||||||
@ -926,7 +987,7 @@ pub struct GitoxideFeatures {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GitoxideFeatures {
|
impl GitoxideFeatures {
|
||||||
fn all() -> Self {
|
pub fn all() -> Self {
|
||||||
GitoxideFeatures {
|
GitoxideFeatures {
|
||||||
fetch: true,
|
fetch: true,
|
||||||
checkout: true,
|
checkout: true,
|
||||||
@ -943,6 +1004,67 @@ impl GitoxideFeatures {
|
|||||||
internal_use_git2: false,
|
internal_use_git2: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expecting() -> String {
|
||||||
|
let fields = vec!["`fetch`", "`checkout`", "`internal-use-git2`"];
|
||||||
|
format!(
|
||||||
|
"unstable 'gitoxide' only takes {} as valid inputs, for shallow fetches see `-Zgit=shallow-index,shallow-deps`",
|
||||||
|
fields.join(" and ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_gitoxide_features<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Option<GitoxideFeatures>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct GitoxideFeaturesVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for GitoxideFeaturesVisitor {
|
||||||
|
type Value = Option<GitoxideFeatures>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
formatter.write_str(&GitoxideFeatures::expecting())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(parse_gitoxide(s.split(",")).map_err(serde::de::Error::custom)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
if v {
|
||||||
|
Ok(Some(GitoxideFeatures::all()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let gitoxide = GitoxideFeatures::deserialize(deserializer)?;
|
||||||
|
Ok(Some(gitoxide))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mvd = serde::de::value::MapAccessDeserializer::new(map);
|
||||||
|
Ok(Some(GitoxideFeatures::deserialize(mvd)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(GitoxideFeaturesVisitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_gitoxide(
|
fn parse_gitoxide(
|
||||||
@ -961,7 +1083,7 @@ fn parse_gitoxide(
|
|||||||
"checkout" => *checkout = true,
|
"checkout" => *checkout = true,
|
||||||
"internal-use-git2" => *internal_use_git2 = true,
|
"internal-use-git2" => *internal_use_git2 = true,
|
||||||
_ => {
|
_ => {
|
||||||
bail!("unstable 'gitoxide' only takes `fetch` and 'checkout' as valid input, for shallow fetches see `-Zgit=shallow-index,shallow-deps`")
|
bail!(GitoxideFeatures::expecting())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,12 @@ impl<'de, 'gctx> de::Deserializer<'de> for Deserializer<'gctx> {
|
|||||||
let (res, def) = res;
|
let (res, def) = res;
|
||||||
return res.map_err(|e| e.with_key_context(&self.key, Some(def)));
|
return res.map_err(|e| e.with_key_context(&self.key, Some(def)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The effect here is the same as in `deserialize_option`.
|
||||||
|
if self.gctx.has_key(&self.key, self.env_prefix_ok)? {
|
||||||
|
return visitor.visit_some(self);
|
||||||
|
}
|
||||||
|
|
||||||
Err(ConfigError::missing(&self.key))
|
Err(ConfigError::missing(&self.key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Tests for config settings.
|
//! Tests for config settings.
|
||||||
|
|
||||||
|
use cargo::core::features::{GitFeatures, GitoxideFeatures};
|
||||||
use cargo::core::{PackageIdSpec, Shell};
|
use cargo::core::{PackageIdSpec, Shell};
|
||||||
use cargo::util::context::{
|
use cargo::util::context::{
|
||||||
self, Definition, GlobalContext, JobsConfig, SslVersionConfig, StringList,
|
self, Definition, GlobalContext, JobsConfig, SslVersionConfig, StringList,
|
||||||
@ -1925,11 +1926,102 @@ Caused by:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn git_features_env() {
|
fn git_features() {
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GIT", "shallow-index")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: true,
|
||||||
|
..GitFeatures::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GIT", "shallow-index,abc")
|
||||||
|
.build();
|
||||||
|
assert_error(
|
||||||
|
gctx.get::<Option<cargo::core::CliUnstable>>("unstable")
|
||||||
|
.unwrap_err(),
|
||||||
|
"\
|
||||||
|
error in environment variable `CARGO_UNSTABLE_GIT`: could not load config key `unstable.git`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
[..]unstable 'git' only takes [..] as valid inputs",
|
||||||
|
);
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GIT", "shallow-deps")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: false,
|
||||||
|
shallow_deps: true,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
let gctx = GlobalContextBuilder::new()
|
let gctx = GlobalContextBuilder::new()
|
||||||
.env("CARGO_UNSTABLE_GIT", "true")
|
.env("CARGO_UNSTABLE_GIT", "true")
|
||||||
.build();
|
.build();
|
||||||
verify(gctx);
|
assert!(do_check(gctx, Some(GitFeatures::all())));
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GIT_SHALLOW_INDEX", "true")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GIT_SHALLOW_INDEX", "true")
|
||||||
|
.env("CARGO_UNSTABLE_GIT_SHALLOW_DEPS", "true")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: true,
|
||||||
|
shallow_deps: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
write_config_toml(
|
||||||
|
"\
|
||||||
|
[unstable]
|
||||||
|
git = 'shallow-index'
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: true,
|
||||||
|
shallow_deps: false,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
write_config_toml(
|
||||||
|
"\
|
||||||
|
[unstable.git]
|
||||||
|
shallow_deps = false
|
||||||
|
shallow_index = true
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitFeatures {
|
||||||
|
shallow_index: true,
|
||||||
|
shallow_deps: false,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
write_config_toml(
|
write_config_toml(
|
||||||
"\
|
"\
|
||||||
@ -1937,23 +2029,92 @@ fn git_features_env() {
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
let gctx = GlobalContextBuilder::new().build();
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
verify(gctx);
|
assert!(do_check(gctx, Some(Default::default())));
|
||||||
|
|
||||||
fn verify(gctx: GlobalContext) {
|
fn do_check(gctx: GlobalContext, expect: Option<GitFeatures>) -> bool {
|
||||||
assert_error(
|
let unstable_flags = gctx
|
||||||
gctx.get::<Option<cargo::core::CliUnstable>>("unstable")
|
.get::<Option<cargo::core::CliUnstable>>("unstable")
|
||||||
.unwrap_err(),
|
.unwrap()
|
||||||
"missing field `shallow_index`",
|
.unwrap();
|
||||||
);
|
unstable_flags.git == expect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn gitoxide_features_env() {
|
fn gitoxide_features() {
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GITOXIDE", "fetch")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitoxideFeatures {
|
||||||
|
fetch: true,
|
||||||
|
..GitoxideFeatures::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GITOXIDE", "fetch,abc")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_error(
|
||||||
|
gctx.get::<Option<cargo::core::CliUnstable>>("unstable")
|
||||||
|
.unwrap_err(),
|
||||||
|
"\
|
||||||
|
error in environment variable `CARGO_UNSTABLE_GITOXIDE`: could not load config key `unstable.gitoxide`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
[..]unstable 'gitoxide' only takes [..] as valid inputs, for shallow fetches see `-Zgit=shallow-index,shallow-deps`",
|
||||||
|
);
|
||||||
|
|
||||||
let gctx = GlobalContextBuilder::new()
|
let gctx = GlobalContextBuilder::new()
|
||||||
.env("CARGO_UNSTABLE_GITOXIDE", "true")
|
.env("CARGO_UNSTABLE_GITOXIDE", "true")
|
||||||
.build();
|
.build();
|
||||||
verify(gctx);
|
assert!(do_check(gctx, Some(GitoxideFeatures::all())));
|
||||||
|
|
||||||
|
let gctx = GlobalContextBuilder::new()
|
||||||
|
.env("CARGO_UNSTABLE_GITOXIDE_FETCH", "true")
|
||||||
|
.build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitoxideFeatures {
|
||||||
|
fetch: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
write_config_toml(
|
||||||
|
"\
|
||||||
|
[unstable]
|
||||||
|
gitoxide = \"fetch\"
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitoxideFeatures {
|
||||||
|
fetch: true,
|
||||||
|
..GitoxideFeatures::default()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
write_config_toml(
|
||||||
|
"\
|
||||||
|
[unstable.gitoxide]
|
||||||
|
fetch = true
|
||||||
|
checkout = false
|
||||||
|
internal_use_git2 = false
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
|
assert!(do_check(
|
||||||
|
gctx,
|
||||||
|
Some(GitoxideFeatures {
|
||||||
|
fetch: true,
|
||||||
|
checkout: false,
|
||||||
|
internal_use_git2: false,
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
write_config_toml(
|
write_config_toml(
|
||||||
"\
|
"\
|
||||||
@ -1961,13 +2122,13 @@ fn gitoxide_features_env() {
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
let gctx = GlobalContextBuilder::new().build();
|
let gctx = GlobalContextBuilder::new().build();
|
||||||
verify(gctx);
|
assert!(do_check(gctx, Some(Default::default())));
|
||||||
|
|
||||||
fn verify(gctx: GlobalContext) {
|
fn do_check(gctx: GlobalContext, expect: Option<GitoxideFeatures>) -> bool {
|
||||||
assert_error(
|
let unstable_flags = gctx
|
||||||
gctx.get::<Option<cargo::core::CliUnstable>>("unstable")
|
.get::<Option<cargo::core::CliUnstable>>("unstable")
|
||||||
.unwrap_err(),
|
.unwrap()
|
||||||
"missing field `fetch`",
|
.unwrap();
|
||||||
);
|
unstable_flags.gitoxide == expect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user