From ef770992796f7d992cdc8aa171da1ee582d7f600 Mon Sep 17 00:00:00 2001
From: prsabahrami
Date: Wed, 22 Jan 2025 00:26:12 -0500
Subject: [PATCH] replace `optional_features` with `extras`
---
.github/workflows/rust-compile.yml | 89 +------------------
crates/rattler_conda_types/Cargo.toml | 2 +-
.../rattler_conda_types/src/match_spec/mod.rs | 12 +--
.../src/match_spec/parse.rs | 16 ++--
crates/rattler_solve/Cargo.toml | 2 +-
crates/rattler_solve/src/resolvo/mod.rs | 6 +-
crates/rattler_solve/tests/backends.rs | 48 +++++-----
.../noarch/repodata.json | 6 +-
8 files changed, 48 insertions(+), 133 deletions(-)
diff --git a/.github/workflows/rust-compile.yml b/.github/workflows/rust-compile.yml
index 01a00afb7..5b43f11f5 100644
--- a/.github/workflows/rust-compile.yml
+++ b/.github/workflows/rust-compile.yml
@@ -146,7 +146,7 @@ jobs:
run: >
cargo nextest run
--workspace
- --features ${{ env.DEFAULT_FEATURES }}
+ --features ${{ env.DEFAULT_FEATURES }} extras
--target ${{ matrix.target }}
${{ steps.build-options.outputs.CARGO_BUILD_OPTIONS}}
${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
@@ -154,89 +154,4 @@ jobs:
- name: Run doctests
if: ${{ !matrix.skip-tests }}
run: >
- cargo test --doc
-
- test-experimental:
- name: Test Experimental Features (${{ matrix.name }})
- runs-on: ${{ matrix.os }}
- needs: [ format_and_lint ]
- strategy:
- fail-fast: false
- matrix:
- include:
- - { name: "Linux-x86_64", target: x86_64-unknown-linux-musl, os: ubuntu-22.04 }
- - { name: "Linux-aarch64", target: aarch64-unknown-linux-musl, os: ubuntu-latest, skip-tests: true }
- - { name: "Linux-arm", target: arm-unknown-linux-musleabi, os: ubuntu-latest, use-cross: true, skip-tests: true }
-
- # - { name: "Linux-mips", target: mips-unknown-linux-musl, os: ubuntu-latest, use-cross: true, skip-tests: true }
- # - { name: "Linux-mipsel", target: mipsel-unknown-linux-musl, os: ubuntu-latest, use-cross: true, skip-tests: true }
- # - { name: "Linux-mips64", target: mips64-unknown-linux-muslabi64, os: ubuntu-latest, use-cross: true, skip-tests: true }
- # - { name: "Linux-mips64el", target: mips64el-unknown-linux-muslabi64, os: ubuntu-latest, use-cross: true, skip-tests: true }
-
-# - { name: "Linux-powerpc", target: powerpc-unknown-linux-gnu, os: ubuntu-latest, use-cross: true, skip-tests: true }
- - { name: "Linux-powerpc64", target: powerpc64-unknown-linux-gnu, os: ubuntu-latest, use-cross: true, skip-tests: true }
- - { name: "Linux-powerpc64le", target: powerpc64le-unknown-linux-gnu, os: ubuntu-latest, use-cross: true, skip-tests: true }
-
- - { name: "Linux-s390x", target: s390x-unknown-linux-gnu, os: ubuntu-latest, use-cross: true, skip-tests: true }
-
- - { name: "macOS-x86_64", target: x86_64-apple-darwin, os: macOS-latest }
- - { name: "macOS-aarch64", target: aarch64-apple-darwin, os: macOS-latest, skip-tests: true }
-
- - { name: "Windows-x86_64", target: x86_64-pc-windows-msvc, os: windows-latest }
- - { name: "Windows-aarch64", target: aarch64-pc-windows-msvc, os: windows-latest, skip-tests: true }
- feature-set:
- - "optional_features"
-
- steps:
- - uses: actions/checkout@v4
- with:
- submodules: recursive
-
- - name: Install Rust toolchain
- uses: actions-rust-lang/setup-rust-toolchain@v1
- with:
- target: ${{ matrix.target }}
- components: rustfmt
- cache: false
-
- - uses: taiki-e/setup-cross-toolchain-action@v1
- if: matrix.target != 'x86_64-unknown-linux-musl'
- with:
- target: ${{ matrix.target }}
-
- - if: matrix.target == 'x86_64-unknown-linux-musl'
- run: |
- sudo apt install musl-tools gcc g++
- sudo ln -s /usr/bin/musl-gcc /usr/bin/musl-g++
-
- - uses: Swatinem/rust-cache@v2
-
- - name: Install cargo nextest
- if: ${{ !matrix.skip-tests }}
- uses: taiki-e/install-action@v2
- with:
- tool: cargo-nextest
-
- - name: Use rustls on musl targets.
- id: build-options
- if: contains(matrix.target, '-musl') || startsWith(matrix.target, 'powerpc') || startsWith(matrix.target, 's390x')
- run: |
- echo "CARGO_BUILD_OPTIONS=${CARGO_BUILD_OPTIONS} --no-default-features --features rustls-tls" >> $GITHUB_OUTPUT
-
- - name: Run feature-specific tests
- if: ${{ !matrix.skip-tests }}
- run: >
- cargo nextest run
- --workspace
- --features ${{ matrix.feature-set }}
- --target ${{ matrix.target }}
- ${{ steps.build-options.outputs.CARGO_BUILD_OPTIONS}}
- "optional_"
-
- - name: Run feature-specific doctests
- if: ${{ !matrix.skip-tests }}
- run: >
- cargo test --doc
- --features ${{ matrix.feature-set }}
- --target ${{ matrix.target }}
- ${{ steps.build-options.outputs.CARGO_BUILD_OPTIONS}}
+ cargo test --doc
\ No newline at end of file
diff --git a/crates/rattler_conda_types/Cargo.toml b/crates/rattler_conda_types/Cargo.toml
index 0d8da2ff0..2a9b3559f 100644
--- a/crates/rattler_conda_types/Cargo.toml
+++ b/crates/rattler_conda_types/Cargo.toml
@@ -12,7 +12,7 @@ readme.workspace = true
[features]
default = ["rayon"]
-optional_features = []
+extras = []
[dependencies]
chrono = { workspace = true }
diff --git a/crates/rattler_conda_types/src/match_spec/mod.rs b/crates/rattler_conda_types/src/match_spec/mod.rs
index c21c7df3c..1e2f3b6ac 100644
--- a/crates/rattler_conda_types/src/match_spec/mod.rs
+++ b/crates/rattler_conda_types/src/match_spec/mod.rs
@@ -137,7 +137,7 @@ pub struct MatchSpec {
/// Match the specific filename of the package
pub file_name: Option,
/// The selected optional features of the package
- pub optional_features: Option>,
+ pub extras: Option>,
/// The channel of the package
pub channel: Option>,
/// The subdir of the channel
@@ -176,7 +176,7 @@ impl Display for MatchSpec {
None => write!(f, "*")?,
}
- match &self.optional_features {
+ match &self.extras {
Some(dependencies) => {
write!(f, "[")?;
write!(f, "{}", dependencies.iter().format(", "))?;
@@ -233,7 +233,7 @@ impl MatchSpec {
build: self.build,
build_number: self.build_number,
file_name: self.file_name,
- optional_features: self.optional_features,
+ extras: self.extras,
channel: self.channel,
subdir: self.subdir,
namespace: self.namespace,
@@ -279,7 +279,7 @@ pub struct NamelessMatchSpec {
/// Match the specific filename of the package
pub file_name: Option,
/// The selected optional features of the package
- pub optional_features: Option>,
+ pub extras: Option>,
/// The channel of the package
#[serde(deserialize_with = "deserialize_channel", default)]
pub channel: Option>,
@@ -333,7 +333,7 @@ impl From for NamelessMatchSpec {
build: spec.build,
build_number: spec.build_number,
file_name: spec.file_name,
- optional_features: spec.optional_features,
+ extras: spec.extras,
channel: spec.channel,
subdir: spec.subdir,
namespace: spec.namespace,
@@ -353,7 +353,7 @@ impl MatchSpec {
build: spec.build,
build_number: spec.build_number,
file_name: spec.file_name,
- optional_features: spec.optional_features,
+ extras: spec.extras,
channel: spec.channel,
subdir: spec.subdir,
namespace: spec.namespace,
diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs
index fd4cd09b3..57c519449 100644
--- a/crates/rattler_conda_types/src/match_spec/parse.rs
+++ b/crates/rattler_conda_types/src/match_spec/parse.rs
@@ -227,9 +227,9 @@ fn strip_brackets(input: &str) -> Result<(Cow<'_, str>, BracketVec<'_>), ParseMa
}
}
-#[cfg(feature = "optional_features")]
+#[cfg(feature = "extras")]
/// Parses a list of optional dependencies from a string `[feat1, feat2, feat3]`.
-pub fn parse_optional_features(input: &str) -> Result, ParseMatchSpecError> {
+pub fn parse_extras(input: &str) -> Result, ParseMatchSpecError> {
use nom::combinator::map;
fn parse_features(input: &str) -> IResult<&str, Vec> {
@@ -272,16 +272,16 @@ fn parse_bracket_vec_into_components(
"version" => match_spec.version = Some(VersionSpec::from_str(value, strictness)?),
"build" => match_spec.build = Some(StringMatcher::from_str(value)?),
"build_number" => match_spec.build_number = Some(BuildNumberSpec::from_str(value)?),
- "optional_features" => {
+ "extras" => {
// Optional features are still experimental
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
{
- match_spec.optional_features = Some(parse_optional_features(value)?);
+ match_spec.extras = Some(parse_extras(value)?);
}
- #[cfg(not(feature = "optional_features"))]
+ #[cfg(not(feature = "extras"))]
{
return Err(ParseMatchSpecError::InvalidBracketKey(
- "optional_features".to_string(),
+ "extras".to_string(),
));
}
}
@@ -1379,7 +1379,7 @@ mod tests {
build: "py27_0*".parse().ok(),
build_number: Some(BuildNumberSpec::from_str(">=6").unwrap()),
file_name: Some("foo-1.0-py27_0.tar.bz2".to_string()),
- optional_features: None,
+ extras: None,
channel: Some(
Channel::from_str("conda-forge", &channel_config())
.map(Arc::new)
diff --git a/crates/rattler_solve/Cargo.toml b/crates/rattler_solve/Cargo.toml
index 85be7e10e..14c9d3324 100644
--- a/crates/rattler_solve/Cargo.toml
+++ b/crates/rattler_solve/Cargo.toml
@@ -44,7 +44,7 @@ url = { workspace = true }
default = ["resolvo"]
libsolv_c = ["rattler_libsolv_c", "libc"]
resolvo = ["dep:resolvo", "dep:futures"]
-optional_features = []
+extras = []
[[bench]]
name = "bench"
diff --git a/crates/rattler_solve/src/resolvo/mod.rs b/crates/rattler_solve/src/resolvo/mod.rs
index 38ab82616..b8076c24a 100644
--- a/crates/rattler_solve/src/resolvo/mod.rs
+++ b/crates/rattler_solve/src/resolvo/mod.rs
@@ -679,7 +679,7 @@ impl<'a> DependencyProvider for CondaDependencyProvider<'a> {
subdir: Some(record.package_record.subdir.clone()),
md5: record.package_record.md5,
sha256: record.package_record.sha256,
- optional_features: None,
+ extras: None,
..Default::default()
};
@@ -841,7 +841,7 @@ impl super::SolverImpl for Solver {
let root_requirements = task.specs.iter().flat_map(|spec| {
let (name, nameless_spec) = spec.clone().into_nameless();
- let features = &spec.optional_features;
+ let features = &spec.extras;
let name = name.expect("cannot use matchspec without a name");
let name_id = provider.pool.intern_package_name(name.as_normalized());
let mut reqs = vec![provider
@@ -940,7 +940,7 @@ fn parse_match_spec(
let (name, spec) = match_spec.into_nameless();
let mut version_set_ids = vec![];
- if let Some(ref features) = spec.optional_features {
+ if let Some(ref features) = spec.extras {
let spec_with_feature: SolverMatchSpec<'_> = spec.clone().into();
for feature in features {
diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs
index 432a6d615..6677af948 100644
--- a/crates/rattler_solve/tests/backends.rs
+++ b/crates/rattler_solve/tests/backends.rs
@@ -46,7 +46,7 @@ fn dummy_channel_json_path() -> String {
)
}
-#[cfg(feature = "optional_features")]
+#[cfg(feature = "extras")]
fn dummy_channel_with_optional_dependencies_json_path() -> String {
format!(
"{}/{}",
@@ -724,7 +724,7 @@ mod resolvo {
GenericVirtualPackage, SimpleSolveTask, SolveError, Version,
};
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
use super::dummy_channel_with_optional_dependencies_json_path;
solver_backend_tests!(rattler_solve::resolvo::Solver);
@@ -971,7 +971,7 @@ mod resolvo {
insta::assert_snapshot!(result.unwrap_err());
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Installs `foo` while enabling a single optional dependency `[with-latest-bors]`.
/// This should pull in `bors >=2.0`.
#[test]
@@ -979,7 +979,7 @@ mod resolvo {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-latest-bors]]"],
+ specs: &["foo[extras=[with-latest-bors]]"],
..SimpleSolveTask::default()
},
)
@@ -1012,14 +1012,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Installs `cuda-version` with `[with-cudadev]` which depends on `"foo >=4.0.2", "bar >=1.2.3"`.
#[test]
fn test_solve_dummy_repo_optional_depends_cuda_dev_resolvo() {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["cuda-version[optional_features=[with-cudadev]]"],
+ specs: &["cuda-version[extras=[with-cudadev]]"],
..SimpleSolveTask::default()
},
)
@@ -1062,7 +1062,7 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Attempts to enable two optional features that conflict: `[with-oldbors,with-latest-bors]`.
/// This should fail because one requests `bors <2.0` and the other requests `bors >=2.0`.
#[test]
@@ -1070,7 +1070,7 @@ mod resolvo {
let result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-oldbors,with-latest-bors]]"],
+ specs: &["foo[extras=[with-oldbors,with-latest-bors]]"],
..SimpleSolveTask::default()
},
);
@@ -1078,7 +1078,7 @@ mod resolvo {
insta::assert_snapshot!(result.unwrap_err());
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Enables multiple optional dependencies in the same spec (like `[with-baz2,with-bar]`).
/// This should pull in `baz >=2.0` and `bar >=1.2.3` if both can coexist.
#[test]
@@ -1086,7 +1086,7 @@ mod resolvo {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-baz2,with-bar]]"],
+ specs: &["foo[extras=[with-baz2,with-bar]]"],
..SimpleSolveTask::default()
},
)
@@ -1127,14 +1127,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Should install xfoo with the feature with-issue717 which requires `with-issue717[with-bors21]` hence pulling in bors 2.1 as well
#[test]
fn test_solve_dummy_repo_optional_depends_xfoo_optional_depends_with_features() {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["xfoo[optional_features=[with-issue717]]"],
+ specs: &["xfoo[extras=[with-issue717]]"],
..SimpleSolveTask::default()
},
)
@@ -1180,14 +1180,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Tests what happens when a feature depends on the base package but with another feature enabled
#[test]
fn test_solve_dummy_repo_optional_depends_recursive_feature() {
let result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-recursive]]"],
+ specs: &["foo[extras=[with-recursive]]"],
..SimpleSolveTask::default()
},
);
@@ -1196,14 +1196,14 @@ mod resolvo {
insta::assert_snapshot!(result.unwrap_err());
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Tests that an optional dependency can restrict the highest version of a base dependency
#[test]
fn test_solve_dummy_repo_optional_depends_version_restriction() {
let result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-version-restrict]]"],
+ specs: &["foo[extras=[with-version-restrict]]"],
..SimpleSolveTask::default()
},
)
@@ -1223,14 +1223,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Tests what happens if a feature introduces a dependency on the base package itself
#[test]
fn test_solve_dummy_repo_optional_depends_self_dependency() {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-self]]"],
+ specs: &["foo[extras=[with-self]]"],
..SimpleSolveTask::default()
},
)
@@ -1255,14 +1255,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Tests what happens if there are two packages for foo but only the package with the lower version has the package that is requested
#[test]
fn test_solve_dummy_repo_optional_depends_feature_only_in_older() {
let mut result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[legacy-only]]"],
+ specs: &["foo[extras=[legacy-only]]"],
..SimpleSolveTask::default()
},
)
@@ -1295,14 +1295,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Test what happens if a feature is requested that doesn't exist
#[test]
fn test_solve_dummy_repo_optional_depends_nonexistent_feature() {
let result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[does-not-exist]]"],
+ specs: &["foo[extras=[does-not-exist]]"],
..SimpleSolveTask::default()
},
);
@@ -1313,14 +1313,14 @@ mod resolvo {
);
}
- #[cfg(feature = "optional_features")]
+ #[cfg(feature = "extras")]
/// Test what happens when the only package that provides a certain feature cannot be selected due to a conflict
#[test]
fn test_solve_dummy_repo_optional_depends_feature_conflict() {
let result = solve::(
&[dummy_channel_with_optional_dependencies_json_path()],
SimpleSolveTask {
- specs: &["foo[optional_features=[with-bar]]", "foo>=4.0"],
+ specs: &["foo[extras=[with-bar]]", "foo>=4.0"],
..SimpleSolveTask::default()
},
);
diff --git a/test-data/channels/dummy-optional-dependencies/noarch/repodata.json b/test-data/channels/dummy-optional-dependencies/noarch/repodata.json
index b6ac0fcf5..2c85b7ceb 100644
--- a/test-data/channels/dummy-optional-dependencies/noarch/repodata.json
+++ b/test-data/channels/dummy-optional-dependencies/noarch/repodata.json
@@ -51,7 +51,7 @@
"bar >=1.0"
],
"with-recursive": [
- "foo[optional_features=[with-bar]]"
+ "foo[extras=[with-bar]]"
],
"with-self": [
"foo >=2.0"
@@ -351,7 +351,7 @@
"build_number": 0,
"depends": [],
"constrains": [
- "ray[version=>=2.9.0, optional_features=[default,data]]"
+ "ray[version=>=2.9.0, extras=[default,data]]"
],
"license": "MIT",
"license_family": "MIT",
@@ -402,7 +402,7 @@
"version": "2",
"optional_depends": {
"with-issue717": [
- "issue_717[version=>=2.1, optional_features=[with-bors21]]"
+ "issue_717[version=>=2.1, extras=[with-bors21]]"
]
}
},