diff --git a/Cargo.lock b/Cargo.lock index a8d7955149..de15d2e0db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2868,6 +2868,17 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "file_url" +version = "0.3.1" +dependencies = [ + "itertools 0.14.0", + "percent-encoding", + "thiserror 2.0.18", + "typed-path", + "url", +] + [[package]] name = "file_url" version = "0.3.1" @@ -5938,7 +5949,7 @@ dependencies = [ "pixi_test_utils", "pixi_utils", "pypi_mapping", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rattler_virtual_packages", "reqwest", @@ -5976,7 +5987,7 @@ dependencies = [ "rattler_build_jinja", "rattler_build_recipe", "rattler_build_types", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", "serde", "serde_json", @@ -6001,7 +6012,7 @@ dependencies = [ "rattler_build_jinja", "rattler_build_recipe", "rattler_build_types", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", "serde", "serde_json", @@ -6026,7 +6037,7 @@ dependencies = [ "pixi_build_types", "pyproject-toml", "rattler_build_recipe", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest", "serde", "serde_json", @@ -6053,7 +6064,7 @@ dependencies = [ "pixi_build_backend", "pixi_build_types", "rattler_build_recipe", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", "serde", "serde_json", @@ -6079,7 +6090,7 @@ dependencies = [ "rattler_build_core", "rattler_build_recipe", "rattler_build_variant_config", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "tempfile", @@ -6101,7 +6112,7 @@ dependencies = [ "rattler_build_jinja", "rattler_build_recipe", "rattler_build_types", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex", "reqwest", "roxmltree", @@ -6130,7 +6141,7 @@ dependencies = [ "pixi_build_backend", "pixi_build_types", "rattler_build_recipe", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", "serde", "serde_json", @@ -6170,7 +6181,7 @@ dependencies = [ "pixi_utils", "pixi_uv_conversions", "pypi_modifiers", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "regex", "same-file", @@ -6221,8 +6232,8 @@ dependencies = [ "rattler_build_recipe", "rattler_build_types", "rattler_build_variant_config", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_virtual_packages", "serde", "serde_json", @@ -6245,8 +6256,8 @@ dependencies = [ "ordermap", "pixi_build_frontend", "pixi_build_types", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_package_streaming", "serde", "serde_json", @@ -6272,7 +6283,7 @@ dependencies = [ "pixi_spec", "pixi_spec_containers", "pixi_test_utils", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "thiserror 2.0.18", @@ -6290,7 +6301,7 @@ dependencies = [ "ordermap", "pixi_build_discovery", "pixi_build_types", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "thiserror 2.0.18", @@ -6309,7 +6320,7 @@ dependencies = [ "pixi_build_types", "pixi_manifest", "pixi_spec", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", ] @@ -6319,8 +6330,8 @@ version = "0.1.0" dependencies = [ "ordermap", "pixi_stable_hash", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "schemars 1.2.1", "serde", "serde_json", @@ -6384,7 +6395,7 @@ dependencies = [ "pixi_uv_conversions", "pypi_modifiers", "rattler", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_index", "rattler_lock", "rattler_networking", @@ -6465,8 +6476,8 @@ dependencies = [ "pixi_utils", "pixi_variant", "rattler", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_package_streaming", "rattler_repodata_gateway", @@ -6564,7 +6575,7 @@ dependencies = [ "pixi_spec", "pixi_test_utils", "pixi_url", - "rattler_digest", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "serde", "tempfile", @@ -6582,13 +6593,15 @@ dependencies = [ "console", "dirs", "fs-err", + "indexmap 2.14.0", "insta", "itertools 0.14.0", "miette 7.6.0", "nix 0.29.0", "pixi_consts", "rattler", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_config", "rattler_networking", "rattler_repodata_gateway", "reqwest", @@ -6608,7 +6621,7 @@ version = "0.1.0" dependencies = [ "console", "rattler_cache", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "url", ] @@ -6668,8 +6681,8 @@ dependencies = [ "pypi_mapping", "pypi_modifiers", "rattler", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rattler_networking", "rattler_repodata_gateway", @@ -6722,7 +6735,7 @@ dependencies = [ name = "pixi_default_versions" version = "0.1.0" dependencies = [ - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6735,7 +6748,7 @@ dependencies = [ "itertools 0.14.0", "pixi_consts", "pixi_manifest", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "serde", "serde_json", @@ -6750,7 +6763,7 @@ dependencies = [ "fs-err", "itertools 0.14.0", "pixi_cli", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6784,7 +6797,7 @@ dependencies = [ "itertools 0.14.0", "memchr", "parking_lot 0.12.5", - "rattler_digest", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rstest", "serde", "tempfile", @@ -6825,7 +6838,7 @@ dependencies = [ "pixi_toml", "pixi_utils", "rattler", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rattler_menuinst", "rattler_networking", @@ -6874,7 +6887,7 @@ dependencies = [ "pixi_uv_conversions", "pypi_modifiers", "rattler", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rayon", "serde", @@ -6933,7 +6946,7 @@ dependencies = [ "pixi_test_utils", "pixi_toml", "pyproject-toml", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rattler_solve", "rattler_virtual_packages", @@ -7014,7 +7027,7 @@ dependencies = [ name = "pixi_record" version = "0.1.0" dependencies = [ - "file_url", + "file_url 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "insta", "itertools 0.14.0", "miette 7.6.0", @@ -7023,8 +7036,8 @@ dependencies = [ "pixi_spec", "pixi_spec_containers", "pixi_variant", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "serde", "serde_with", @@ -7050,7 +7063,7 @@ dependencies = [ "pixi_git", "pixi_progress", "rattler", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_repodata_gateway", "regex", "tokio", @@ -7071,7 +7084,7 @@ version = "0.1.0" dependencies = [ "chrono", "dirs", - "file_url", + "file_url 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "humantime", "insta", "itertools 0.14.0", @@ -7080,8 +7093,8 @@ dependencies = [ "pixi_git", "pixi_path", "pixi_toml", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rattler_solve", "serde", @@ -7103,7 +7116,7 @@ dependencies = [ "itertools 0.14.0", "ordermap", "pixi_spec", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", ] @@ -7112,8 +7125,8 @@ name = "pixi_stable_hash" version = "0.1.0" dependencies = [ "ordermap", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json", "url", "xxhash-rust", @@ -7136,7 +7149,7 @@ dependencies = [ "pixi_glob", "pixi_manifest", "pixi_progress", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_lock", "rayon", "serde", @@ -7159,8 +7172,8 @@ dependencies = [ "itertools 0.14.0", "miette 7.6.0", "pixi_consts", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_package_streaming", "serde_json", "tempfile", @@ -7198,7 +7211,7 @@ dependencies = [ "pixi_record", "pixi_spec", "pixi_utils", - "rattler_digest", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "reqwest", "sevenz-rust2 0.21.0", @@ -7231,7 +7244,7 @@ dependencies = [ "pixi_config", "pixi_consts", "pixi_variant", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_shell", "reqwest", @@ -7634,8 +7647,8 @@ dependencies = [ "pep440_rs", "pep508_rs", "pixi_config", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "reqwest", "serde", @@ -7653,7 +7666,7 @@ dependencies = [ "miette 7.6.0", "pixi_default_versions", "pixi_manifest", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_virtual_packages", "regex", "thiserror 2.0.18", @@ -7922,8 +7935,8 @@ dependencies = [ "parking_lot 0.12.5", "path_resolver", "rattler_cache", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_menuinst", "rattler_networking", "rattler_package_streaming", @@ -7986,15 +7999,15 @@ dependencies = [ "rattler_build_source_cache", "rattler_build_types", "rattler_cache", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_config", - "rattler_digest", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_git", "rattler_index", "rattler_menuinst", "rattler_networking", "rattler_package_streaming", - "rattler_redaction", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_repodata_gateway", "rattler_s3", "rattler_shell", @@ -8039,7 +8052,7 @@ dependencies = [ "lazy_static", "minijinja", "rattler_build_types", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "serde_with", @@ -8080,8 +8093,8 @@ dependencies = [ "rattler_build_types", "rattler_build_variant_config", "rattler_build_yaml_parser", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex", "serde", "serde-value", @@ -8106,7 +8119,7 @@ dependencies = [ "indexmap 2.14.0", "itertools 0.14.0", "minijinja", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_shell", "serde", "thiserror 2.0.18", @@ -8161,7 +8174,7 @@ source = "git+https://github.com/prefix-dev/rattler-build?branch=main#954057dfa4 dependencies = [ "globset", "itertools 0.14.0", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "serde_with", @@ -8181,7 +8194,7 @@ dependencies = [ "rattler_build_jinja", "rattler_build_types", "rattler_build_yaml_parser", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex", "serde", "serde_yaml", @@ -8218,11 +8231,11 @@ dependencies = [ "futures", "itertools 0.14.0", "parking_lot 0.12.5", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_package_streaming", - "rattler_redaction", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon", "reqwest", "serde_json", @@ -8234,6 +8247,46 @@ dependencies = [ "url", ] +[[package]] +name = "rattler_conda_types" +version = "0.46.2" +dependencies = [ + "ahash", + "chrono", + "core-foundation 0.10.1", + "dirs", + "fancy-regex", + "file_url 0.3.1", + "fs-err", + "glob", + "hex", + "indexmap 2.14.0", + "itertools 0.14.0", + "lazy-regex", + "memmap2 0.9.10", + "nom 8.0.0", + "nom-language", + "purl", + "rattler_digest 1.2.5", + "rattler_macros 1.0.14", + "rattler_redaction 0.2.0", + "regex", + "serde", + "serde-untagged", + "serde_json", + "serde_repr", + "serde_with", + "serde_yaml", + "simd-json", + "smallvec", + "strum", + "tempfile", + "thiserror 2.0.18", + "tracing", + "typed-path", + "url", +] + [[package]] name = "rattler_conda_types" version = "0.46.2" @@ -8245,7 +8298,7 @@ dependencies = [ "core-foundation 0.10.1", "dirs", "fancy-regex", - "file_url", + "file_url 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs-err", "glob", "hex", @@ -8256,9 +8309,9 @@ dependencies = [ "nom 8.0.0", "nom-language", "purl", - "rattler_digest", - "rattler_macros", - "rattler_redaction", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_macros 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon", "regex", "serde", @@ -8280,13 +8333,11 @@ dependencies = [ [[package]] name = "rattler_config" version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683b0151673468245567a9c6c037f5bffefab61b57a00bf2a850edb395d73476" dependencies = [ "console", "fs-err", "indexmap 2.14.0", - "rattler_conda_types", + "rattler_conda_types 0.46.2", "serde", "serde_json", "thiserror 2.0.18", @@ -8295,6 +8346,23 @@ dependencies = [ "url", ] +[[package]] +name = "rattler_digest" +version = "1.2.5" +dependencies = [ + "blake2", + "digest 0.10.7", + "generic-array", + "hex", + "md-5 0.10.6", + "serde", + "serde-untagged", + "serde_bytes", + "serde_with", + "sha2 0.10.9", + "url", +] + [[package]] name = "rattler_digest" version = "1.2.5" @@ -8353,8 +8421,8 @@ dependencies = [ "indexmap 2.14.0", "indicatif", "opendal", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_package_streaming", "rattler_s3", @@ -8381,13 +8449,13 @@ checksum = "af3c6773c6c8f35f5b35abfcfea1196a768f5c064e332b63659e9d18d7fe43d1" dependencies = [ "ahash", "chrono", - "file_url", + "file_url 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 2.14.0", "itertools 0.14.0", "pep440_rs", "pep508_rs", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_solve", "serde", "serde-untagged", @@ -8402,6 +8470,14 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "rattler_macros" +version = "1.0.14" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "rattler_macros" version = "1.0.14" @@ -8427,7 +8503,7 @@ dependencies = [ "once_cell", "plist", "quick-xml 0.37.5", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_shell", "regex", "serde", @@ -8498,10 +8574,10 @@ dependencies = [ "getrandom 0.4.2", "http 1.4.0", "num_cpus", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", - "rattler_redaction", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest", "serde_json", "simple_spawn_blocking", @@ -8542,6 +8618,13 @@ dependencies = [ "tokio", ] +[[package]] +name = "rattler_redaction" +version = "0.2.0" +dependencies = [ + "url", +] + [[package]] name = "rattler_redaction" version = "0.2.0" @@ -8573,7 +8656,7 @@ dependencies = [ "coalesced_map", "dashmap", "dirs", - "file_url", + "file_url 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs-err", "fslock", "futures", @@ -8590,11 +8673,11 @@ dependencies = [ "parking_lot 0.12.5", "pin-project-lite", "rattler_cache", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_package_streaming", - "rattler_redaction", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest", "retry-policies", "rmp-serde", @@ -8644,7 +8727,7 @@ dependencies = [ "fs-err", "indexmap 2.14.0", "itertools 0.14.0", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_pty", "serde_json", "shlex", @@ -8665,8 +8748,8 @@ dependencies = [ "futures", "humantime", "itertools 0.14.0", - "rattler_conda_types", - "rattler_digest", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "resolvo", "serde", "tempfile", @@ -8689,12 +8772,12 @@ dependencies = [ "indicatif", "miette 7.6.0", "opendal", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_config", - "rattler_digest", + "rattler_digest 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_networking", "rattler_package_streaming", - "rattler_redaction", + "rattler_redaction 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rattler_s3", "rattler_solve", "reqwest", @@ -8722,7 +8805,7 @@ dependencies = [ "nom 8.0.0", "once_cell", "plist", - "rattler_conda_types", + "rattler_conda_types 0.46.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex", "serde", "thiserror 2.0.18", diff --git a/Cargo.toml b/Cargo.toml index a7df1cb1be..0213efb276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -226,6 +226,7 @@ rattler_cache = { version = "0.8", default-features = false } rattler_conda_types = { version = "0.46", default-features = false, features = [ "rayon", ] } +rattler_config = { version = "0.3", default-features = false } rattler_digest = { version = "1.2", default-features = false } rattler_index = { version = "0.29", default-features = false, features = [ "s3", @@ -267,6 +268,22 @@ version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "d8efd776 # `astral-reqwest-middleware` (rattler, rattler-build, uv). reqwest-middleware = { path = "patches/reqwest_middleware_shim" } +# Temporary patch: iterate on rattler_config locally while migrating +# pixi_config to ConfigBase. Remove once the next rattler +# release ships with everything pixi needs. See +# crates/pixi_config/RATTLER_MIGRATION.md. +# +# NOTE: rattler_config pulls in rattler_conda_types from rattler's local +# workspace, so the dep graph has two copies of rattler_conda_types +# (one from crates.io that pixi uses directly, one from path that +# rattler_config uses internally). Types from `PackageFormatAndCompression` +# therefore don't unify across the boundary — direct field construction +# of that struct in pixi code is currently impossible. Use `FromStr` to +# build values instead. Path-patching rattler_conda_types is not viable +# because the local copy has API drift that breaks other crates.io +# rattler crates (e.g. rattler_repodata_gateway). +rattler_config = { path = "../rattler/crates/rattler_config" } + # Temporary patch: rattler-build main has been updated to use the new rattler # versions but no release has been published yet. Remove once rattler-build # cuts a new release. diff --git a/crates/pixi_api/src/workspace/init/mod.rs b/crates/pixi_api/src/workspace/init/mod.rs index 224c5ee0f3..e56d8fd986 100644 --- a/crates/pixi_api/src/workspace/init/mod.rs +++ b/crates/pixi_api/src/workspace/init/mod.rs @@ -8,7 +8,7 @@ use std::{ use miette::{Context, IntoDiagnostic}; use minijinja::{Environment, context}; -use pixi_config::{Config, get_default_author, pixi_home}; +use pixi_config::{Config, S3OptionsMap, get_default_author, pixi_home}; use pixi_consts::consts; use pixi_core::{Workspace, workspace::WorkspaceMut}; use pixi_manifest::{FeatureName, pyproject::PyProjectManifest}; @@ -341,7 +341,7 @@ fn render_workspace( platforms: &Vec, index_url: Option<&Url>, extra_index_urls: &Vec, - s3_options: HashMap, + s3_options: S3OptionsMap, env_vars: Option<&HashMap>, pypi_mapping: Option<&HashMap>, ) -> String { @@ -375,7 +375,7 @@ fn render_workspace( } fn relevant_s3_options( - s3_options: HashMap, + s3_options: S3OptionsMap, channels: Vec, ) -> HashMap { // only take s3 options in manifest if they are used in the default channels @@ -395,6 +395,7 @@ fn relevant_s3_options( .collect::>(); s3_options + .0 .into_iter() .filter(|(key, _)| s3_buckets.contains(key)) .collect() diff --git a/crates/pixi_config/Cargo.toml b/crates/pixi_config/Cargo.toml index 30912cee83..3f4d06014b 100644 --- a/crates/pixi_config/Cargo.toml +++ b/crates/pixi_config/Cargo.toml @@ -14,11 +14,13 @@ clap = { workspace = true, features = ["std", "derive", "env"] } console = { workspace = true } dirs = { workspace = true } fs-err = { workspace = true } +indexmap = { workspace = true } itertools = { workspace = true } miette = { workspace = true } pixi_consts = { workspace = true } rattler = { workspace = true } rattler_conda_types = { workspace = true } +rattler_config = { workspace = true } rattler_networking = { workspace = true, features = ["s3"] } rattler_repodata_gateway = { workspace = true, features = ["gateway"] } reqwest = { workspace = true } diff --git a/crates/pixi_config/src/lib.rs b/crates/pixi_config/src/lib.rs index 4415cb69cf..7dca18cff9 100644 --- a/crates/pixi_config/src/lib.rs +++ b/crates/pixi_config/src/lib.rs @@ -12,17 +12,12 @@ use miette::{Context, IntoDiagnostic, miette}; use pixi_consts::consts; use rattler_conda_types::{ ChannelConfig, NamedChannelOrUrl, Platform, Version, VersionBumpType, VersionSpec, - compression_level::CompressionLevel, - package::CondaArchiveType, version_spec::{EqualityOperator, LogicalOperator, RangeOperator}, }; use rattler_networking::s3_middleware; use rattler_repodata_gateway::{Gateway, GatewayBuilder, SourceConfig}; use reqwest::{NoProxy, Proxy}; -use serde::{ - Deserialize, Serialize, - de::{Error, IntoDeserializer}, -}; +use serde::{Deserialize, Serialize, de::IntoDeserializer}; use url::Url; const EXPERIMENTAL: &str = "experimental"; @@ -703,98 +698,12 @@ impl ConfigCliPrompt { } } -#[derive(Clone, Default, Debug, Serialize, PartialEq, Eq)] -pub struct RepodataConfig { - #[serde(flatten)] - pub default: RepodataChannelConfig, - - #[serde(flatten)] - pub per_channel: HashMap, -} - -impl<'de> Deserialize<'de> for RepodataConfig { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct RepodataConfigVisitor; - - impl<'de> serde::de::Visitor<'de> for RepodataConfigVisitor { - type Value = RepodataConfig; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("a repodata config map") - } - - fn visit_map(self, mut access: M) -> Result - where - M: serde::de::MapAccess<'de>, - { - let mut default = RepodataChannelConfig::default(); - let mut per_channel = HashMap::new(); - - while let Some(key) = access.next_key::()? { - match key.as_str() { - "disable-bzip2" | "disable_bzip2" => { - default.disable_bzip2 = Some(access.next_value()?); - } - "disable-zstd" | "disable_zstd" => { - default.disable_zstd = Some(access.next_value()?); - } - "disable-sharded" | "disable_sharded" => { - default.disable_sharded = Some(access.next_value()?); - } - other => { - if let Ok(url) = Url::parse(other) { - per_channel.insert(url, access.next_value()?); - } else { - // Unknown/deprecated keys (e.g. `disable-jlap`) are - // silently ignored. `serde_ignored` will report them - // as unused so the "Ignoring '…'" warning fires. - let _: serde::de::IgnoredAny = access.next_value()?; - } - } - } - } - - Ok(RepodataConfig { - default, - per_channel, - }) - } - } - - deserializer.deserialize_map(RepodataConfigVisitor) - } -} - -impl RepodataConfig { - pub fn is_empty(&self) -> bool { - self.default.is_empty() && self.per_channel.is_empty() - } - - /// Merge the given RepodataConfig into the current one. - /// `other` is mutable to allow for moving the values out of it. - /// The given config will have higher priority - pub fn merge(&self, mut other: Self) -> Self { - let mut per_channel: HashMap<_, _> = self - .per_channel - .clone() - .into_iter() - .map(|(url, config)| { - let other_config = other.per_channel.remove(&url).unwrap_or_default(); - (url, config.merge(other_config)) - }) - .collect(); - - per_channel.extend(other.per_channel); - - Self { - default: self.default.merge(other.default), - per_channel, - } - } -} +// `RepodataConfig` and `RepodataChannelConfig` now live in +// `rattler_config`. The upstream `RepodataConfig` already includes the +// tolerant `Deserialize` impl that pixi used to maintain locally — +// unknown/deprecated keys (e.g. `disable-jlap`) are silently consumed +// and surface as `serde_ignored` warnings. +pub use rattler_config::config::repodata_config::{RepodataChannelConfig, RepodataConfig}; #[derive(Parser, Debug, Default, Clone)] pub struct ConfigCliActivation { @@ -819,46 +728,15 @@ impl ConfigCliActivation { } } -#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub struct RepodataChannelConfig { - /// Disable bzip2 compression for repodata. - #[serde(alias = "disable_bzip2")] // BREAK: remove to stop supporting snake_case alias - #[serde(skip_serializing_if = "Option::is_none")] - pub disable_bzip2: Option, - /// Disable zstd compression for repodata. - #[serde(alias = "disable_zstd")] // BREAK: remove to stop supporting snake_case alias - #[serde(skip_serializing_if = "Option::is_none")] - pub disable_zstd: Option, - /// Disable the use of sharded repodata - #[serde(skip_serializing_if = "Option::is_none")] - pub disable_sharded: Option, -} - -impl RepodataChannelConfig { - pub fn is_empty(&self) -> bool { - self.disable_bzip2.is_none() - && self.disable_zstd.is_none() - && self.disable_sharded.is_none() - } - - pub fn merge(&self, other: Self) -> Self { - Self { - disable_zstd: self.disable_zstd.or(other.disable_zstd), - disable_bzip2: self.disable_bzip2.or(other.disable_bzip2), - disable_sharded: self.disable_sharded.or(other.disable_sharded), - } - } -} - -impl From for SourceConfig { - fn from(value: RepodataChannelConfig) -> Self { - SourceConfig { - zstd_enabled: !value.disable_zstd.unwrap_or(false), - bz2_enabled: !value.disable_bzip2.unwrap_or(false), - sharded_enabled: !value.disable_sharded.unwrap_or(false), - cache_action: Default::default(), - } +// Convert a `RepodataChannelConfig` into rattler's `SourceConfig`. +// Used to be a `From` impl, but both types are now foreign — orphan +// rule means we need a free function. Call sites use it explicitly. +fn repodata_channel_to_source(value: RepodataChannelConfig) -> SourceConfig { + SourceConfig { + zstd_enabled: !value.disable_zstd.unwrap_or(false), + bz2_enabled: !value.disable_bzip2.unwrap_or(false), + sharded_enabled: !value.disable_sharded.unwrap_or(false), + cache_action: Default::default(), } } @@ -890,18 +768,10 @@ pub struct PyPIConfig { pub allow_insecure_host: Vec, } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub struct S3Options { - /// S3 endpoint URL - pub endpoint_url: Url, - - /// The name of the S3 region - pub region: String, - - /// Force path style URLs instead of subdomain style - pub force_path_style: bool, -} +// `S3Options` and the `S3OptionsMap` newtype now live in `rattler_config`. +// Re-exported so external crates that referenced `pixi_config::S3Options` +// keep compiling. +pub use rattler_config::config::s3::{S3Options, S3OptionsMap}; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[serde(untagged)] @@ -1005,66 +875,11 @@ impl ExperimentalConfig { } } -/// The default maximum number of concurrent solves that can be run at once. -/// Defaulting to the number of CPUs available. -fn default_max_concurrent_solves() -> usize { - std::thread::available_parallelism().map_or(1, |n| n.get()) -} - -/// The default maximum number of concurrent downloads that can be run at once. -/// 50 is a reasonable default for the number of concurrent downloads. -/// More verification is needed to determine the optimal number. -fn default_max_concurrent_downloads() -> usize { - 50 -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub struct ConcurrencyConfig { - /// The maximum number of concurrent solves that can be run at once. - // Needing to set this default next to the default of the full struct to avoid serde defaulting - // to 0 of partial struct was omitted. - #[serde(default = "default_max_concurrent_solves")] - pub solves: usize, - - /// The maximum number of concurrent HTTP requests to make. - // Needing to set this default next to the default of the full struct to avoid serde defaulting - // to 0 of partial struct was omitted. - #[serde(default = "default_max_concurrent_downloads")] - pub downloads: usize, -} - -impl Default for ConcurrencyConfig { - fn default() -> Self { - Self { - solves: default_max_concurrent_solves(), - downloads: default_max_concurrent_downloads(), - } - } -} - -impl ConcurrencyConfig { - /// Merge the given ConcurrencyConfig into the current one. - pub fn merge(self, other: Self) -> Self { - // Merging means using the other value if they are none default. - Self { - solves: if other.solves != ConcurrencyConfig::default().solves { - other.solves - } else { - self.solves - }, - downloads: if other.downloads != ConcurrencyConfig::default().downloads { - other.downloads - } else { - self.downloads - }, - } - } - - pub fn is_default(&self) -> bool { - ConcurrencyConfig::default() == *self - } -} +// `ConcurrencyConfig` and its default helpers now live in `rattler_config`. +// Re-exported so external code keeps compiling against `pixi_config::…`. +pub use rattler_config::config::concurrency::{ + ConcurrencyConfig, default_max_concurrent_downloads, default_max_concurrent_solves, +}; impl PyPIConfig { /// Merge the given PyPIConfig into the current one. @@ -1216,22 +1031,10 @@ impl PinningStrategy { } } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Default)] -#[serde(rename_all = "kebab-case")] -pub enum RunPostLinkScripts { - /// Run the post link scripts, we call this insecure as it may run arbitrary - /// code. - Insecure, - /// Do not run the post link scripts - #[default] - False, -} -impl FromStr for RunPostLinkScripts { - type Err = serde::de::value::Error; - fn from_str(s: &str) -> Result { - Self::deserialize(s.into_deserializer()) - } -} +// `RunPostLinkScripts` now lives in `rattler_config`. Re-exported so +// `pixi_config::RunPostLinkScripts` remains a valid path for external +// crates (pixi_core, pixi_global). +pub use rattler_config::config::run_post_link_scripts::RunPostLinkScripts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] @@ -1254,6 +1057,8 @@ pub struct Config { pub tls_no_verify: Option, /// Which TLS root certificates to use for HTTPS connections. + // TODO(rattler-config): promote — TLS root cert selection is a + // generic HTTPS knob, not pixi-specific. See RATTLER_MIGRATION.md. #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub tls_root_certs: Option, @@ -1264,6 +1069,9 @@ pub struct Config { /// Dependency Pinning strategy used for dependency modification through /// automated logic like `pixi add` + // TODO(rattler-config): promote — useful for any tool that + // adds/updates conda deps. rattler_config already lists this as + // missing. See RATTLER_MIGRATION.md. #[serde(skip_serializing_if = "Option::is_none")] pub pinning_strategy: Option, @@ -1286,8 +1094,8 @@ pub struct Config { /// Configuration for S3. #[serde(default)] - #[serde(skip_serializing_if = "HashMap::is_empty")] - pub s3_options: HashMap, + #[serde(skip_serializing_if = "S3OptionsMap::is_empty")] + pub s3_options: S3OptionsMap, /// The option to specify the directory where detached environments are /// stored. When using 'true', it defaults to the cache directory. @@ -1318,16 +1126,22 @@ pub struct Config { pub run_post_link_scripts: Option, /// If set to false, symbolic links will not be used during package installation. + // TODO(rattler-config): promote — package-install link strategy is + // not pixi-specific. See RATTLER_MIGRATION.md. #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub allow_symbolic_links: Option, /// If set to false, hard links will not be used during package installation. + // TODO(rattler-config): promote — package-install link strategy is + // not pixi-specific. See RATTLER_MIGRATION.md. #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub allow_hard_links: Option, /// If set to false, ref links (copy-on-write) will not be used during package installation. + // TODO(rattler-config): promote — package-install link strategy is + // not pixi-specific. See RATTLER_MIGRATION.md. #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] pub allow_ref_links: Option, @@ -1385,7 +1199,7 @@ impl Default for Config { channel_config: default_channel_config(), repodata_config: RepodataConfig::default(), pypi_config: PyPIConfig::default(), - s3_options: HashMap::new(), + s3_options: S3OptionsMap::default(), detached_environments: None, pinning_strategy: None, shell: ShellConfig::default(), @@ -1494,7 +1308,7 @@ impl From for rattler_repodata_gateway::ChannelConfig { impl From<&Config> for rattler_repodata_gateway::ChannelConfig { fn from(config: &Config) -> Self { let repodata_config = &config.repodata_config; - let default = repodata_config.default.clone().into(); + let default = repodata_channel_to_source(repodata_config.default.clone()); let per_channel = repodata_config .per_channel @@ -1502,7 +1316,7 @@ impl From<&Config> for rattler_repodata_gateway::ChannelConfig { .map(|(url, config)| { ( url.clone(), - config.merge(repodata_config.default.clone()).into(), + repodata_channel_to_source(config.merge(repodata_config.default.clone())), ) }) .collect(); @@ -1556,158 +1370,19 @@ impl ShellConfig { } } -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub struct ProxyConfig { - /// https proxy. - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - pub https: Option, - /// http proxy. - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - pub http: Option, - /// A list of no proxy pattern - #[serde(default)] - #[serde(skip_serializing_if = "Vec::is_empty")] - pub non_proxy_hosts: Vec, -} - -impl ProxyConfig { - pub fn is_default(&self) -> bool { - self.https.is_none() && self.https.is_none() && self.non_proxy_hosts.is_empty() - } - pub fn merge(&self, other: Self) -> Self { - Self { - https: other.https.as_ref().or(self.https.as_ref()).cloned(), - http: other.http.as_ref().or(self.http.as_ref()).cloned(), - non_proxy_hosts: if other.is_default() { - self.non_proxy_hosts.clone() - } else { - other.non_proxy_hosts.clone() - }, - } - } -} - -/// Container for the package format and compression level -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct PackageFormatAndCompression { - /// The archive type that is selected - pub archive_type: CondaArchiveType, - /// The compression level that is selected - pub compression_level: CompressionLevel, -} +// `ProxyConfig` now lives in `rattler_config`. Re-exported for +// back-compat. Note: rattler's `Default::default()` reads `HTTP_PROXY` +// / `HTTPS_PROXY` / `NO_PROXY` env vars into the struct, whereas +// pixi's old `Default` was empty. The local `ENV_*_PROXY` / `USE_PROXY_FROM_ENV` +// statics below are kept because `get_proxies()` and the load-time +// warning still consult env vars directly to decide whether to defer +// to reqwest's own env-var handling. We end up reading the env twice +// per process (once cached in rattler, once cached here) — acceptable. +pub use rattler_config::config::proxy::ProxyConfig; -// deserializer for the package format and compression level -impl<'de> Deserialize<'de> for PackageFormatAndCompression { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - let s = s.as_str(); - PackageFormatAndCompression::from_str(s).map_err(D::Error::custom) - } -} - -impl FromStr for PackageFormatAndCompression { - type Err = String; - - fn from_str(s: &str) -> Result { - let mut split = s.split(':'); - let package_format = split.next().ok_or("invalid")?; - - let compression = split.next().unwrap_or("default"); - - // remove all non-alphanumeric characters - let package_format = package_format - .chars() - .filter(|c| c.is_alphanumeric()) - .collect::(); - - let archive_type = match package_format.to_lowercase().as_str() { - "tarbz2" => CondaArchiveType::TarBz2, - "conda" => CondaArchiveType::Conda, - _ => return Err(format!("Unknown package format: {package_format}")), - }; - - let compression_level = match compression { - "max" | "highest" => CompressionLevel::Highest, - "default" | "normal" => CompressionLevel::Default, - "fast" | "lowest" | "min" => CompressionLevel::Lowest, - number if number.parse::().is_ok() => { - let number = number.parse::().unwrap_or_default(); - match archive_type { - CondaArchiveType::TarBz2 => { - if !(1..=9).contains(&number) { - return Err("Compression level for .tar.bz2 must be between 1 and 9" - .to_string()); - } - } - CondaArchiveType::Conda => { - if !(-7..=22).contains(&number) { - return Err( - "Compression level for conda packages (zstd) must be between -7 and 22".to_string() - ); - } - } - } - CompressionLevel::Numeric(number) - } - _ => return Err(format!("Unknown compression level: {compression}")), - }; - - Ok(PackageFormatAndCompression { - archive_type, - compression_level, - }) - } -} - -impl Serialize for PackageFormatAndCompression { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let package_format = match self.archive_type { - CondaArchiveType::TarBz2 => "tarbz2", - CondaArchiveType::Conda => "conda", - }; - let compression_level = match self.compression_level { - CompressionLevel::Default => "default", - CompressionLevel::Highest => "max", - CompressionLevel::Lowest => "min", - CompressionLevel::Numeric(level) => &level.to_string(), - }; - - serializer.serialize_str(format!("{package_format}:{compression_level}").as_str()) - } -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub struct BuildConfig { - /// package format and compression level - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - pub package_format: Option, -} - -impl BuildConfig { - pub fn is_default(&self) -> bool { - self.package_format.is_none() - } - pub fn merge(&self, other: Self) -> Self { - Self { - package_format: other - .package_format - .as_ref() - .or(self.package_format.as_ref()) - .cloned(), - } - } -} +// `BuildConfig` and `PackageFormatAndCompression` now live in +// `rattler_config`. Re-exported so external paths keep compiling. +pub use rattler_config::config::build::{BuildConfig, PackageFormatAndCompression}; #[derive(thiserror::Error, Debug)] pub enum ConfigError { @@ -2045,6 +1720,10 @@ impl Config { /// The `other` config will have higher priority #[must_use] pub fn merge_config(mut self, mut other: Config) -> Self { + // Brought in for the trait methods on rattler_config types + // (e.g. ConcurrencyConfig::merge_config). + use rattler_config::config::Config as _; + self.mirrors.extend(other.mirrors); other.loaded_from.extend(self.loaded_from); @@ -2067,27 +1746,40 @@ impl Config { } else { other.channel_config }, - repodata_config: self.repodata_config.merge(other.repodata_config), + repodata_config: self + .repodata_config + .merge_config(&other.repodata_config) + .expect("RepodataConfig::merge_config is infallible"), pypi_config: self.pypi_config.merge(other.pypi_config), - s3_options: { - let mut merged = HashMap::new(); - merged.extend(self.s3_options); - merged.extend(other.s3_options); - merged - }, + s3_options: S3OptionsMap( + self.s3_options + .0 + .into_iter() + .chain(other.s3_options.0) + .collect(), + ), detached_environments: other.detached_environments.or(self.detached_environments), pinning_strategy: other.pinning_strategy.or(self.pinning_strategy), shell: self.shell.merge(other.shell), experimental: self.experimental.merge(other.experimental), // Make other take precedence over self to allow for setting the value through the CLI - concurrency: self.concurrency.merge(other.concurrency), + concurrency: self + .concurrency + .merge_config(&other.concurrency) + .expect("ConcurrencyConfig::merge_config is infallible"), run_post_link_scripts: other.run_post_link_scripts.or(self.run_post_link_scripts), allow_symbolic_links: other.allow_symbolic_links.or(self.allow_symbolic_links), allow_hard_links: other.allow_hard_links.or(self.allow_hard_links), allow_ref_links: other.allow_ref_links.or(self.allow_ref_links), - proxy_config: self.proxy_config.merge(other.proxy_config), - build: self.build.merge(other.build), + proxy_config: self + .proxy_config + .merge_config(&other.proxy_config) + .expect("ProxyConfig::merge_config is infallible"), + build: self + .build + .merge_config(&other.build) + .expect("BuildConfig::merge_config is infallible"), tool_platform: self.tool_platform.or(other.tool_platform), cache: self.cache.merge(other.cache), @@ -2381,7 +2073,7 @@ impl Config { return Err(err); }; if let Some((bucket, rest)) = subkey.split_once('.') { - if let Some(bucket_config) = self.s3_options.get_mut(bucket) { + if let Some(bucket_config) = self.s3_options.0.get_mut(bucket) { match rest { "endpoint-url" => { if let Some(value) = value { @@ -2422,7 +2114,7 @@ impl Config { let value = value.ok_or_else(|| miette!("s3-options requires a value"))?; let s3_options: S3Options = serde_json::de::from_str(&value).into_diagnostic()?; - self.s3_options.insert(subkey.to_string(), s3_options); + self.s3_options.0.insert(subkey.to_string(), s3_options); } } key if key.starts_with(EXPERIMENTAL) => { @@ -2646,7 +2338,7 @@ impl Config { pub fn compute_s3_config(&self) -> HashMap { self.s3_options - .clone() + .0 .iter() .map(|(k, v)| { ( @@ -2701,6 +2393,7 @@ pub fn config_path_global() -> Vec { #[cfg(test)] mod tests { + use indexmap::IndexMap; use rstest::rstest; use super::*; @@ -2923,7 +2616,7 @@ UNUSED = "unused" force-path-style = false "#; let (config, _) = Config::from_toml(toml, None).unwrap(); - let s3_options = config.s3_options; + let s3_options = config.s3_options.0; assert_eq!( s3_options["bucket1"].endpoint_url, Url::parse("https://my-s3-host").unwrap() @@ -2996,14 +2689,14 @@ UNUSED = "unused" index_url: Some(Url::parse("https://conda.anaconda.org/conda-forge").unwrap()), keyring_provider: Some(KeyringProvider::Subprocess), }, - s3_options: HashMap::from([( + s3_options: S3OptionsMap(IndexMap::from([( "bucket1".into(), S3Options { endpoint_url: Url::parse("https://my-s3-host").unwrap(), region: "us-east-1".to_string(), force_path_style: false, }, - )]), + )])), repodata_config: RepodataConfig { default: RepodataChannelConfig { disable_bzip2: Some(true), @@ -3049,7 +2742,7 @@ UNUSED = "unused" solves: 5, ..ConcurrencyConfig::default() }, - s3_options: HashMap::from([ + s3_options: S3OptionsMap(IndexMap::from([ ( "bucket1".into(), S3Options { @@ -3066,7 +2759,7 @@ UNUSED = "unused" force_path_style: false, }, ), - ]), + ])), ..Default::default() }; config = config.merge_config(other); @@ -3079,7 +2772,7 @@ UNUSED = "unused" config.detached_environments().path().unwrap(), Some(PathBuf::from("/path/to/envs")) ); - assert!(config.s3_options.contains_key("bucket1")); + assert!(config.s3_options.0.contains_key("bucket1")); let other2 = Config { default_channels: vec![NamedChannelOrUrl::from_str("channel").unwrap()], @@ -3088,14 +2781,14 @@ UNUSED = "unused" detached_environments: Some(DetachedEnvironments::Path(PathBuf::from( "/path/to/envs2", ))), - s3_options: HashMap::from([( + s3_options: S3OptionsMap(IndexMap::from([( "bucket2".into(), S3Options { endpoint_url: Url::parse("https://my-new-s3-host").unwrap(), region: "us-east-1".to_string(), force_path_style: false, }, - )]), + )])), ..Default::default() }; @@ -3110,10 +2803,10 @@ UNUSED = "unused" Some(PathBuf::from("/path/to/envs2")) ); assert_eq!(config.max_concurrent_solves(), 5); - assert!(config.s3_options.contains_key("bucket1")); - assert!(config.s3_options.contains_key("bucket2")); + assert!(config.s3_options.0.contains_key("bucket1")); + assert!(config.s3_options.0.contains_key("bucket2")); assert!( - config.s3_options["bucket2"] + config.s3_options.0["bucket2"] .endpoint_url .to_string() .contains("my-new-s3-host") @@ -3133,7 +2826,7 @@ UNUSED = "unused" let mut merged = config_1.clone(); merged = merged.merge_config(config_2); - assert!(merged.s3_options.contains_key("bucket1")); + assert!(merged.s3_options.0.contains_key("bucket1")); let debug = format!("{merged:#?}"); let debug = debug.replace("\\\\", "/"); @@ -3312,7 +3005,7 @@ UNUSED = "unused" assert_eq!(config.max_concurrent_downloads(), 1); config.set("s3-options.my-bucket", Some(r#"{"endpoint-url": "http://localhost:9000", "force-path-style": true, "region": "auto"}"#.to_string())).unwrap(); - let s3_options = config.s3_options.get("my-bucket").unwrap(); + let s3_options = config.s3_options.0.get("my-bucket").unwrap(); assert!( s3_options .endpoint_url @@ -3650,92 +3343,30 @@ UNUSED = "unused" use std::str::FromStr; - use rattler_conda_types::{compression_level::CompressionLevel, package::CondaArchiveType}; - use super::PackageFormatAndCompression; + // We compare via the canonical `archive:level` string emitted by the + // type's `Serialize` impl. Directly constructing the struct would + // mix `rattler_conda_types` types from the path-patched rattler_config + // workspace with the ones pixi pulls from crates.io — they don't + // unify even at the same version. See the patch note in the root + // Cargo.toml. + fn parsed_as(input: &str) -> String { + let p = PackageFormatAndCompression::from_str(input).unwrap(); + serde_json::to_string(&p).unwrap() + } + #[test] fn test_parse_packaging() { - let package_format = PackageFormatAndCompression::from_str("tar-bz2").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::TarBz2, - compression_level: CompressionLevel::Default - } - ); - - let package_format = PackageFormatAndCompression::from_str("conda").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::Conda, - compression_level: CompressionLevel::Default - } - ); - - let package_format = PackageFormatAndCompression::from_str("tar-bz2:1").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::TarBz2, - compression_level: CompressionLevel::Numeric(1) - } - ); - - let package_format = PackageFormatAndCompression::from_str(".tar.bz2:max").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::TarBz2, - compression_level: CompressionLevel::Highest - } - ); - - let package_format = PackageFormatAndCompression::from_str("tarbz2:5").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::TarBz2, - compression_level: CompressionLevel::Numeric(5) - } - ); - - let package_format = PackageFormatAndCompression::from_str("conda:1").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::Conda, - compression_level: CompressionLevel::Numeric(1) - } - ); - - let package_format = PackageFormatAndCompression::from_str("conda:max").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::Conda, - compression_level: CompressionLevel::Highest - } - ); - - let package_format = PackageFormatAndCompression::from_str("conda:-5").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::Conda, - compression_level: CompressionLevel::Numeric(-5) - } - ); - - let package_format = PackageFormatAndCompression::from_str("conda:fast").unwrap(); - assert_eq!( - package_format, - PackageFormatAndCompression { - archive_type: CondaArchiveType::Conda, - compression_level: CompressionLevel::Lowest - } - ); + assert_eq!(parsed_as("tar-bz2"), "\"tarbz2:default\""); + assert_eq!(parsed_as("conda"), "\"conda:default\""); + assert_eq!(parsed_as("tar-bz2:1"), "\"tarbz2:1\""); + assert_eq!(parsed_as(".tar.bz2:max"), "\"tarbz2:max\""); + assert_eq!(parsed_as("tarbz2:5"), "\"tarbz2:5\""); + assert_eq!(parsed_as("conda:1"), "\"conda:1\""); + assert_eq!(parsed_as("conda:max"), "\"conda:max\""); + assert_eq!(parsed_as("conda:-5"), "\"conda:-5\""); + assert_eq!(parsed_as("conda:fast"), "\"conda:min\""); } // Serialize env-var-sensitive tests so they don't race against each other. diff --git a/crates/pixi_config/src/snapshots/pixi_config__tests__config_merge_multiple.snap b/crates/pixi_config/src/snapshots/pixi_config__tests__config_merge_multiple.snap index 0a067a5d2e..d700319f6b 100644 --- a/crates/pixi_config/src/snapshots/pixi_config__tests__config_merge_multiple.snap +++ b/crates/pixi_config/src/snapshots/pixi_config__tests__config_merge_multiple.snap @@ -1,6 +1,6 @@ --- source: crates/pixi_config/src/lib.rs -assertion_line: 2831 +assertion_line: 3147 expression: debug --- Config { @@ -92,27 +92,29 @@ Config { keyring_provider: None, allow_insecure_host: [], }, - s3_options: { - "bucket1": S3Options { - endpoint_url: Url { - scheme: "https", - cannot_be_a_base: false, - username: "", - password: None, - host: Some( - Domain( - "my-s3-host", + s3_options: S3OptionsMap( + { + "bucket1": S3Options { + endpoint_url: Url { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "my-s3-host", + ), ), - ), - port: None, - path: "/", - query: None, - fragment: None, + port: None, + path: "/", + query: None, + fragment: None, + }, + region: "us-east-1", + force_path_style: false, }, - region: "us-east-1", - force_path_style: false, }, - }, + ), detached_environments: Some( Boolean( true,