From ec0010fd1293a1d4d322896d9d9a4ee63c0b41d8 Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Tue, 26 Aug 2025 14:40:33 +0300 Subject: [PATCH 01/10] refactor: use source location spec for `pin_and_checkout` --- .../pixi_command_dispatcher/src/command_dispatcher/mod.rs | 8 ++++---- .../src/solve_pixi/source_metadata_collector.rs | 2 +- crates/pixi_global/src/project/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs b/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs index 804d54b5e6..cf10de7f3f 100644 --- a/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs +++ b/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs @@ -20,7 +20,7 @@ use pixi_build_frontend::BackendOverride; use pixi_git::resolver::GitResolver; use pixi_glob::GlobHashCache; use pixi_record::{PinnedPathSpec, PinnedSourceSpec, PixiRecord}; -use pixi_spec::{SourceLocationSpec, SourceSpec}; +use pixi_spec::SourceLocationSpec; use rattler::package_cache::PackageCache; use rattler_conda_types::{ChannelConfig, GenericVirtualPackage, Platform}; use rattler_networking::LazyClient; @@ -560,7 +560,7 @@ impl CommandDispatcher { self.execute_task(spec).await } - /// Checks out a particular source based on a source spec. + /// Checks out a particular source based on a source location spec. /// /// This function resolves the source specification to a concrete checkout /// by: @@ -576,9 +576,9 @@ impl CommandDispatcher { /// same source is used multiple times. pub async fn pin_and_checkout( &self, - source_spec: SourceSpec, + source_location_spec: SourceLocationSpec, ) -> Result> { - match source_spec.location { + match source_location_spec { SourceLocationSpec::Url(url) => { unimplemented!("fetching URL sources ({}) is not yet implemented", url.url) } diff --git a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs index b09010f97a..5bca9933a6 100644 --- a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs +++ b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs @@ -163,7 +163,7 @@ impl SourceMetadataCollector { // Get the source for the particular package. let source = self .command_queue - .pin_and_checkout(spec) + .pin_and_checkout(spec.location) .await .map_err(|err| CollectSourceMetadataError::SourceCheckoutError { name: name.as_source().to_string(), diff --git a/crates/pixi_global/src/project/mod.rs b/crates/pixi_global/src/project/mod.rs index 7dcaebf890..b5bdc952b7 100644 --- a/crates/pixi_global/src/project/mod.rs +++ b/crates/pixi_global/src/project/mod.rs @@ -1372,7 +1372,7 @@ impl Project { ) -> Result { let command_dispatcher = self.command_dispatcher()?; let checkout = command_dispatcher - .pin_and_checkout(source_spec) + .pin_and_checkout(source_spec.location) .await .map_err(|e| InferPackageNameError::BuildBackendMetadata(Box::new(e)))?; From a7d02850d913fbf5f18ef662315ca4d7a464430d Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Tue, 26 Aug 2025 15:10:40 +0300 Subject: [PATCH 02/10] feat(pixi build): git source --- Cargo.lock | 77 +- crates/pixi_build_discovery/src/discovery.rs | 6 +- .../snapshots/discovery__direct_recipe.snap | 2 +- .../discovery__discovery@inherit__nested.snap | 2 +- .../discovery__discovery@nested__nested.snap | 2 +- ...iscovery__discovery@nested_recipe_yml.snap | 2 +- .../discovery__discovery@recipe_yaml.snap | 2 +- .../discovery__discovery@recipe_yml.snap | 2 +- .../discovery__discovery@simple.snap | 2 +- ...onversions_v1_examples@cpp-git-source.snap | 42 + crates/pixi_cli/src/build.rs | 27 +- crates/pixi_cli/src/update.rs | 1 + crates/pixi_command_dispatcher/Cargo.toml | 1 + .../src/build/build_cache.rs | 2 +- .../src/build/conversion.rs | 1 + .../src/build_backend_metadata/mod.rs | 83 +- .../command_dispatcher/instantiate_backend.rs | 21 +- .../src/install_pixi/mod.rs | 3 +- .../src/instantiate_tool_env/mod.rs | 1 + .../src/solve_conda/mod.rs | 2 + .../src/solve_pixi/mod.rs | 8 + .../solve_pixi/source_metadata_collector.rs | 12 +- .../src/source_build/mod.rs | 153 ++- .../src/source_metadata/mod.rs | 29 +- .../tests/integration/event_tree.rs | 10 +- .../src/lock_file/satisfiability/mod.rs | 108 ++ crates/pixi_core/src/lock_file/update.rs | 54 +- crates/pixi_global/Cargo.toml | 1 + crates/pixi_global/src/project/mod.rs | 3 +- .../src/project/parsed_manifest.rs | 2 +- crates/pixi_manifest/src/build_system.rs | 42 +- .../pixi_manifest/src/toml/build_backend.rs | 6 +- crates/pixi_record/Cargo.toml | 3 + crates/pixi_record/src/source_record.rs | 161 ++- docs/reference/cli/pixi.md | 2 +- docs/reference/cli/pixi/build.md | 14 +- docs/reference/pixi_manifest.md | 3 + examples/pixi-build/cpp-git-source/pixi.lock | 1123 +++++++++++++++++ examples/pixi-build/cpp-git-source/pixi.toml | 28 + schema/model.py | 19 +- schema/schema.json | 35 + tests/integration_python/test_main_cli.py | 52 + 42 files changed, 1963 insertions(+), 186 deletions(-) create mode 100644 crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap create mode 100644 examples/pixi-build/cpp-git-source/pixi.lock create mode 100644 examples/pixi-build/cpp-git-source/pixi.toml diff --git a/Cargo.lock b/Cargo.lock index 963bb8d732..3d3d251ec1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,7 +1017,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e9d642a7e3a318e37c2c9427b5a6a48aa1ad55dcd986f3034ab2239045a645" dependencies = [ - "darling 0.21.3", + "darling", "ident_case", "prettyplease", "proc-macro2", @@ -1317,8 +1317,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "coalesced_map" version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf5a7a58a9d5b914bddb0a3a2bd920af2be897114dc8128af022af81fc43b8b" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "dashmap", "tokio", @@ -1612,22 +1611,8 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -1644,24 +1629,13 @@ dependencies = [ "syn", ] -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core 0.20.11", - "quote", - "syn", -] - [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.21.3", + "darling_core", "quote", "syn", ] @@ -2126,8 +2100,7 @@ dependencies = [ [[package]] name = "file_url" version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765662dc0b26e038099a5a1529f5d48443111eea45377c312be892997651710e" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "itertools 0.14.0", "percent-encoding", @@ -2994,7 +2967,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.59.0", ] [[package]] @@ -4327,8 +4300,7 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" [[package]] name = "path_resolver" version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67957e099f5b76f4cad98e0d41dd53746ab3a2debc1da12ee5b1cccb1d7b8dc8" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "fs-err", "fxhash", @@ -4525,6 +4497,7 @@ dependencies = [ "reqwest", "reqwest-middleware", "rstest", + "serde_derive", "serde_json", "temp-env", "tempfile", @@ -4795,6 +4768,7 @@ dependencies = [ "rattler", "rattler_conda_types", "rattler_digest", + "rattler_lock", "rattler_networking", "rattler_package_streaming", "rattler_repodata_gateway", @@ -5074,6 +5048,7 @@ dependencies = [ "regex", "rstest", "serde", + "serde_derive", "serde_json", "serde_with", "tempfile", @@ -5253,6 +5228,7 @@ dependencies = [ "rattler_digest", "rattler_lock", "serde", + "serde_json", "serde_with", "thiserror 2.0.17", "typed-path", @@ -6139,8 +6115,7 @@ dependencies = [ [[package]] name = "rattler_macros" version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "988d5d7ace4fb1d7549008236cf08de95e8ea2f1f80754109324a08c31e6dc6a" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "quote", "syn", @@ -6253,8 +6228,7 @@ dependencies = [ [[package]] name = "rattler_redaction" version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa5057629aeb20861919e9ae56875985d58028f3c6f433a20b5ded086e1cec5" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "reqwest", "reqwest-middleware", @@ -7227,9 +7201,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" dependencies = [ "base64 0.22.1", "chrono", @@ -7238,8 +7212,7 @@ dependencies = [ "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", - "serde", - "serde_derive", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -7247,11 +7220,11 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" dependencies = [ - "darling 0.20.11", + "darling", "proc-macro2", "quote", "syn", @@ -7416,8 +7389,7 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_spawn_blocking" version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0b0b683828aa9d4f5c0e59b0c856a12c30a65b5f1ca4292664734d76fa9c2" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "tokio", ] @@ -7684,7 +7656,7 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows 0.61.3", + "windows 0.59.0", ] [[package]] @@ -10691,3 +10663,8 @@ dependencies = [ "quote", "syn", ] + +[[patch.unused]] +name = "rattler_virtual_packages" +version = "2.2.0" +source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" diff --git a/crates/pixi_build_discovery/src/discovery.rs b/crates/pixi_build_discovery/src/discovery.rs index 875a19feab..946f7cf1fa 100644 --- a/crates/pixi_build_discovery/src/discovery.rs +++ b/crates/pixi_build_discovery/src/discovery.rs @@ -49,7 +49,7 @@ pub struct BackendInitializationParams { pub workspace_root: PathBuf, /// The location of the source code. - pub source: Option, + pub build_source: Option, /// The anchor for relative paths to the location of the source code. pub source_anchor: PathBuf, @@ -202,7 +202,7 @@ impl DiscoveredBackend { backend_spec: BackendSpec::JsonRpc(JsonRpcBackendSpec::default_rattler_build(channels)), init_params: BackendInitializationParams { workspace_root: source_dir.clone(), - source: None, + build_source: None, source_anchor: source_dir, manifest_path: recipe_absolute_path, project_model: None, @@ -273,7 +273,7 @@ impl DiscoveredBackend { init_params: BackendInitializationParams { workspace_root, manifest_path: provenance.path.clone(), - source: build_system.source, + build_source: build_system.source, source_anchor: provenance .path .parent() diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__direct_recipe.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__direct_recipe.snap index 5f80b4fb51..21a4b935f8 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__direct_recipe.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__direct_recipe.snap @@ -14,7 +14,7 @@ backend-spec: - "https://prefix.dev/conda-forge" init-params: workspace-root: "file:///recipe_yaml" - source: ~ + build-source: ~ source-anchor: "file:///recipe_yaml" manifest-path: "file:///recipe_yaml/recipe.yaml" project-model: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap index f26b3fc037..a25bdee7fb 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@inherit__nested.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/pixi-build-backends" init-params: workspace-root: "file:///inherit" - source: ~ + build-source: ~ source-anchor: "file:///inherit/nested" manifest-path: "file:///inherit/nested/pixi.toml" project-model: diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap index e72a7a0103..9db3f8a517 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested__nested.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/pixi-build-backends" init-params: workspace-root: "file:///nested" - source: ~ + build-source: ~ source-anchor: "file:///nested/nested" manifest-path: "file:///nested/nested/pixi.toml" project-model: diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested_recipe_yml.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested_recipe_yml.snap index ed10f8a182..c3ef6c8027 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested_recipe_yml.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@nested_recipe_yml.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/conda-forge" init-params: workspace-root: "file:///nested_recipe_yml" - source: ~ + build-source: ~ source-anchor: "file:///nested_recipe_yml" manifest-path: "file:///nested_recipe_yml/recipe/recipe.yml" project-model: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yaml.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yaml.snap index b999c8a58b..1f9ef76315 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yaml.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yaml.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/conda-forge" init-params: workspace-root: "file:///recipe_yaml" - source: ~ + build-source: ~ source-anchor: "file:///recipe_yaml" manifest-path: "file:///recipe_yaml/recipe.yaml" project-model: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yml.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yml.snap index eb73a4c1ef..ec4d0d1177 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yml.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@recipe_yml.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/conda-forge" init-params: workspace-root: "file:///recipe_yml" - source: ~ + build-source: ~ source-anchor: "file:///recipe_yml" manifest-path: "file:///recipe_yml/recipe.yml" project-model: ~ diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap index 1975d68310..a8dd4a1798 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__discovery@simple.snap @@ -15,7 +15,7 @@ backend-spec: - "https://prefix.dev/pixi-build-backends" init-params: workspace-root: "file:///simple" - source: ~ + build-source: ~ source-anchor: "file:///simple" manifest-path: "file:///simple/pixi.toml" project-model: diff --git a/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap new file mode 100644 index 0000000000..c372522d6b --- /dev/null +++ b/crates/pixi_build_type_conversions/src/snapshots/pixi_build_type_conversions__project_model__tests__conversions_v1_examples@cpp-git-source.snap @@ -0,0 +1,42 @@ +--- +source: crates/pixi_build_type_conversions/src/project_model.rs +expression: project_model +--- +{ + "version": "1", + "data": { + "name": "sdl_example", + "version": "0.1.0", + "description": null, + "authors": null, + "license": null, + "licenseFile": null, + "readme": null, + "homepage": null, + "repository": null, + "documentation": null, + "targets": { + "defaultTarget": { + "hostDependencies": { + "sdl2": { + "binary": { + "version": ">=2.26.5,<3.0", + "build": null, + "buildNumber": null, + "fileName": null, + "channel": null, + "subdir": null, + "md5": null, + "sha256": null, + "url": null, + "license": null + } + } + }, + "buildDependencies": {}, + "runDependencies": {} + }, + "targets": {} + } + } +} diff --git a/crates/pixi_cli/src/build.rs b/crates/pixi_cli/src/build.rs index d0c13dfc82..18d6bc5491 100644 --- a/crates/pixi_cli/src/build.rs +++ b/crates/pixi_cli/src/build.rs @@ -16,7 +16,7 @@ use pixi_utils::variants::VariantConfig; use rattler_conda_types::{GenericVirtualPackage, Platform}; use tempfile::tempdir; -use crate::cli_config::WorkspaceConfig; +use crate::cli_config::{LockAndInstallConfig, WorkspaceConfig}; #[derive(Parser, Debug)] #[clap(verbatim_doc_comment)] @@ -27,6 +27,9 @@ pub struct Args { #[clap(flatten)] pub config_cli: ConfigCli, + #[clap(flatten)] + pub lock_and_install_config: LockAndInstallConfig, + /// The target platform to build for (defaults to the current platform) #[clap(long, short, default_value_t = Platform::current())] pub target_platform: Platform, @@ -124,20 +127,33 @@ pub async fn execute(args: Args) -> miette::Result<()> { .into_diagnostic()?; // Determine the source of the package. - let source: PinnedSourceSpec = PinnedPathSpec { - path: manifest_spec_path.to_string_lossy().into_owned().into(), + let manifest_path_dir = if manifest_spec_path.is_file() { + if let Some(parent) = manifest_spec_path.parent() { + parent + } else { + miette::bail!( + "explicit manifest path: {} doesn't have a parent", + manifest_spec_path.display() + ); + } + } else { + manifest_spec_path.as_ref() + }; + let manifest_source: PinnedSourceSpec = PinnedPathSpec { + path: manifest_path_dir.to_string_lossy().into_owned().into(), } .into(); // Create the build backend metadata specification. let backend_metadata_spec = BuildBackendMetadataSpec { - source: source.clone(), + manifest_source: manifest_source.clone(), channels: channels.clone(), channel_config: channel_config.clone(), build_environment: build_environment.clone(), variants: Some(variants.clone()), variant_files: Some(variant_files.clone()), enabled_protocols: Default::default(), + pin_override: None, }; let backend_metadata = command_dispatcher .build_backend_metadata(backend_metadata_spec.clone()) @@ -168,7 +184,8 @@ pub async fn execute(args: Args) -> miette::Result<()> { package, // Build into a temporary directory first output_directory: Some(temp_output_dir.path().to_path_buf()), - source: source.clone(), + manifest_source: manifest_source.clone(), + build_source: None, channels: channels.clone(), channel_config: channel_config.clone(), build_environment: build_environment.clone(), diff --git a/crates/pixi_cli/src/update.rs b/crates/pixi_cli/src/update.rs index 7475508a0a..a33664b124 100644 --- a/crates/pixi_cli/src/update.rs +++ b/crates/pixi_cli/src/update.rs @@ -162,6 +162,7 @@ pub async fn execute(args: Args) -> miette::Result<()> { let updated_lock_file = UpdateContext::builder(&workspace) .with_lock_file(relaxed_lock_file.clone()) .with_no_install(args.no_install) + .with_update_targets(specs.packages.clone()) .finish() .await? .update() diff --git a/crates/pixi_command_dispatcher/Cargo.toml b/crates/pixi_command_dispatcher/Cargo.toml index aa2697d8bb..c919d11632 100644 --- a/crates/pixi_command_dispatcher/Cargo.toml +++ b/crates/pixi_command_dispatcher/Cargo.toml @@ -41,6 +41,7 @@ xxhash-rust = { workspace = true, features = ["xxh3"] } rattler = { workspace = true } rattler_conda_types = { workspace = true } rattler_digest = { workspace = true } +rattler_lock = { workspace = true } rattler_networking = { workspace = true } rattler_package_streaming = { workspace = true } rattler_repodata_gateway = { workspace = true } diff --git a/crates/pixi_command_dispatcher/src/build/build_cache.rs b/crates/pixi_command_dispatcher/src/build/build_cache.rs index 6b1c7da725..c76324df6f 100644 --- a/crates/pixi_command_dispatcher/src/build/build_cache.rs +++ b/crates/pixi_command_dispatcher/src/build/build_cache.rs @@ -356,7 +356,7 @@ impl<'a> From<&'a DiscoveredBackend> for PackageBuildInputHash { // These fields are not relevant for the package build input hash workspace_root: _, - source: _, + build_source: _, source_anchor: _, manifest_path: _, } = &value.init_params; diff --git a/crates/pixi_command_dispatcher/src/build/conversion.rs b/crates/pixi_command_dispatcher/src/build/conversion.rs index a9244dc401..58c97ef20f 100644 --- a/crates/pixi_command_dispatcher/src/build/conversion.rs +++ b/crates/pixi_command_dispatcher/src/build/conversion.rs @@ -112,6 +112,7 @@ pub(crate) fn package_metadata_to_source_records( SourceRecord { input_hash: input_hash.clone(), source: source.clone(), + pinned_source_spec: None, sources: p .sources .iter() diff --git a/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs b/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs index 78fb2b6cda..92771660db 100644 --- a/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs +++ b/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs @@ -47,8 +47,8 @@ fn warn_once_per_backend(backend_name: &str) { /// particular source. #[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Serialize)] pub struct BuildBackendMetadataSpec { - /// The source specification - pub source: PinnedSourceSpec, + /// The source specification where manifest is located at. + pub manifest_source: PinnedSourceSpec, /// The channel configuration to use for the build backend. pub channel_config: ChannelConfig, @@ -69,13 +69,21 @@ pub struct BuildBackendMetadataSpec { /// The protocols that are enabled for this source #[serde(skip_serializing_if = "crate::is_default")] pub enabled_protocols: EnabledProtocols, + + /// Optional override for the pinned build source of the current package. + /// When set, this takes precedence over any discovered build_source. + #[serde(skip)] + pub pin_override: Option, } /// The metadata of a source checkout. #[derive(Debug)] pub struct BuildBackendMetadata { /// The source checkout that the manifest was extracted from. - pub source: PinnedSourceSpec, + pub manifest_source: PinnedSourceSpec, + + /// The source checkout from which we want to build package. + pub build_source: Option, /// The cache entry that contains the metadata acquired from the build /// backend. @@ -93,7 +101,7 @@ impl BuildBackendMetadataSpec { skip_all, name="backend-metadata", fields( - source = %self.source, + source = %self.manifest_source, platform = %self.build_environment.host_platform, ) )] @@ -102,21 +110,46 @@ impl BuildBackendMetadataSpec { command_dispatcher: CommandDispatcher, ) -> Result> { // Ensure that the source is checked out before proceeding. - let source_checkout = command_dispatcher - .checkout_pinned_source(self.source.clone()) + let manifest_source_checkout = command_dispatcher + .checkout_pinned_source(self.manifest_source.clone()) .await .map_err_with(BuildBackendMetadataError::SourceCheckout)?; // Discover information about the build backend from the source code (cached by path). let discovered_backend = command_dispatcher .discover_backend( - &source_checkout.path, + &manifest_source_checkout.path, self.channel_config.clone(), self.enabled_protocols.clone(), ) .await .map_err_with(BuildBackendMetadataError::Discovery)?; + let build_source_checkout = if let Some(pin_override) = &self.pin_override { + Some( + command_dispatcher + .checkout_pinned_source(pin_override.clone()) + .await + .map_err_with(BuildBackendMetadataError::SourceCheckout)?, + ) + } else if let Some(build_source) = &discovered_backend.init_params.build_source { + Some( + command_dispatcher + .pin_and_checkout(build_source.clone()) + .await + .map_err_with(BuildBackendMetadataError::SourceCheckout)?, + ) + } else { + None + }; + + let (build_source_checkout, build_source) = if let Some(checkout) = build_source_checkout { + let pinned = checkout.pinned.clone(); + (checkout, Some(pinned)) + } else { + (manifest_source_checkout.clone(), None) + }; + // Calculate the hash of the project model let additional_glob_hash = calculate_additional_glob_hash( &discovered_backend.init_params.project_model, @@ -141,7 +174,7 @@ impl BuildBackendMetadataSpec { if !skip_cache { if let Some(metadata) = Self::verify_cache_freshness( - &source_checkout, + &build_source_checkout, &command_dispatcher, metadata, &additional_glob_hash, @@ -151,7 +184,8 @@ impl BuildBackendMetadataSpec { return Ok(BuildBackendMetadata { metadata, cache_entry, - source: source_checkout.pinned, + manifest_source: manifest_source_checkout.pinned, + package_build_source, }); } } else { @@ -161,19 +195,21 @@ impl BuildBackendMetadataSpec { warn_once_per_backend(backend_name); } + let build_source_dir = build_source_checkout.path.clone(); // Instantiate the backend with the discovered information. - let backend = command_dispatcher - .instantiate_backend(InstantiateBackendSpec { - backend_spec: discovered_backend - .backend_spec - .clone() - .resolve(SourceAnchor::from(SourceSpec::from(self.source.clone()))), - init_params: discovered_backend.init_params.clone(), - channel_config: self.channel_config.clone(), - enabled_protocols: self.enabled_protocols.clone(), - }) - .await - .map_err_with(BuildBackendMetadataError::Initialize)?; + let backend = + command_dispatcher + .instantiate_backend(InstantiateBackendSpec { + backend_spec: discovered_backend.backend_spec.clone().resolve( + SourceAnchor::from(SourceSpec::from(self.manifest_source.clone())), + ), + init_params: discovered_backend.init_params.clone(), + build_source_dir, + channel_config: self.channel_config.clone(), + enabled_protocols: self.enabled_protocols.clone(), + }) + .await + .map_err_with(BuildBackendMetadataError::Initialize)?; // Call the conda_outputs method to get metadata. let source = source_checkout.pinned.clone(); @@ -206,9 +242,10 @@ impl BuildBackendMetadataSpec { .map_err(CommandDispatcherError::Failed)?; Ok(BuildBackendMetadata { + manifest_source, + build_source, metadata, cache_entry, - source, }) } @@ -421,7 +458,7 @@ impl BuildBackendMetadataSpec { build_environment: self.build_environment.clone(), build_variants: self.variants.clone().unwrap_or_default(), enabled_protocols: self.enabled_protocols.clone(), - pinned_source: self.source.clone(), + pinned_source: self.manifest_source.clone(), } } } diff --git a/crates/pixi_command_dispatcher/src/command_dispatcher/instantiate_backend.rs b/crates/pixi_command_dispatcher/src/command_dispatcher/instantiate_backend.rs index cb5a3ffabd..07444fb4ba 100644 --- a/crates/pixi_command_dispatcher/src/command_dispatcher/instantiate_backend.rs +++ b/crates/pixi_command_dispatcher/src/command_dispatcher/instantiate_backend.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use miette::Diagnostic; use pixi_build_discovery::{ BackendInitializationParams, BackendSpec, CommandSpec, EnabledProtocols, @@ -8,7 +10,7 @@ use pixi_build_frontend::{ tool::{IsolatedTool, SystemTool, Tool}, }; use pixi_build_types::{PixiBuildApiVersion, procedures::initialize::InitializeParams}; -use pixi_spec::{SourceLocationSpec, SpecConversionError}; +use pixi_spec::SpecConversionError; use rattler_conda_types::ChannelConfig; use rattler_shell::{ activation::{ActivationError, ActivationVariables, Activator}, @@ -18,7 +20,7 @@ use rattler_virtual_packages::DetectVirtualPackageError; use thiserror::Error; use crate::{ - BuildEnvironment, CommandDispatcher, CommandDispatcherErrorResultExt, + BuildEnvironment, CommandDispatcher, CommandDispatcherErrorResultExt, SourceCheckoutError, command_dispatcher::error::CommandDispatcherError, instantiate_tool_env::{ InstantiateToolEnvironmentError, InstantiateToolEnvironmentResult, @@ -34,6 +36,9 @@ pub struct InstantiateBackendSpec { /// The parameters to initialize the backend with pub init_params: BackendInitializationParams, + /// The source directory to use for the backend + pub build_source_dir: PathBuf, + /// The channel configuration to use for any source packages required by the /// backend. pub channel_config: ChannelConfig, @@ -50,13 +55,7 @@ impl CommandDispatcher { ) -> Result> { let BackendSpec::JsonRpc(backend_spec) = spec.backend_spec; - let source_dir = if let Some(SourceLocationSpec::Path(path)) = spec.init_params.source { - path.resolve(&spec.init_params.source_anchor) - .map_err(InstantiateBackendError::from) - .map_err(CommandDispatcherError::Failed)? - } else { - spec.init_params.source_anchor - }; + let source_dir = spec.build_source_dir; // Canonicalize the source_dir to ensure it's a fully resolved absolute path // without any relative components like ".." or "." @@ -218,4 +217,8 @@ pub enum InstantiateBackendError { #[error(transparent)] SpecConversionError(#[from] SpecConversionError), + + #[error(transparent)] + #[diagnostic(transparent)] + SourceCheckout(#[from] SourceCheckoutError), } diff --git a/crates/pixi_command_dispatcher/src/install_pixi/mod.rs b/crates/pixi_command_dispatcher/src/install_pixi/mod.rs index 849178e1bd..cd04f5cb07 100644 --- a/crates/pixi_command_dispatcher/src/install_pixi/mod.rs +++ b/crates/pixi_command_dispatcher/src/install_pixi/mod.rs @@ -215,7 +215,7 @@ impl InstallPixiEnvironmentSpec { .contains(&source_record.package_record.name); let built_source = command_dispatcher .source_build(SourceBuildSpec { - source: source_record.source.clone(), + manifest_source: source_record.source.clone(), package: source_record.into(), channel_config: self.channel_config.clone(), channels: self.channels.clone(), @@ -230,6 +230,7 @@ impl InstallPixiEnvironmentSpec { force, // When we install a pixi environment we always build in development mode. build_profile: BuildProfile::Development, + build_source: None, }) .await?; diff --git a/crates/pixi_command_dispatcher/src/instantiate_tool_env/mod.rs b/crates/pixi_command_dispatcher/src/instantiate_tool_env/mod.rs index 665a6367bb..3e83bd31e8 100644 --- a/crates/pixi_command_dispatcher/src/instantiate_tool_env/mod.rs +++ b/crates/pixi_command_dispatcher/src/instantiate_tool_env/mod.rs @@ -216,6 +216,7 @@ impl InstantiateToolEnvironmentSpec { variants: self.variants.clone(), variant_files: self.variant_files.clone(), strategy: SolveStrategy::default(), + pin_overrides: BTreeMap::new(), }) .await .map_err_with(Box::new) diff --git a/crates/pixi_command_dispatcher/src/solve_conda/mod.rs b/crates/pixi_command_dispatcher/src/solve_conda/mod.rs index 876f4dcaab..08adc6ce6c 100644 --- a/crates/pixi_command_dispatcher/src/solve_conda/mod.rs +++ b/crates/pixi_command_dispatcher/src/solve_conda/mod.rs @@ -155,6 +155,8 @@ impl SolveCondaEnvironmentSpec { ), channel: None, }; + let mut record = record.clone(); + record.pinned_source_spec = source_metadata.pinned_build_source.clone(); url_to_source_package.insert(url, (record, repodata_record)); } } diff --git a/crates/pixi_command_dispatcher/src/solve_pixi/mod.rs b/crates/pixi_command_dispatcher/src/solve_pixi/mod.rs index 80ad930b06..af8f645bd5 100644 --- a/crates/pixi_command_dispatcher/src/solve_pixi/mod.rs +++ b/crates/pixi_command_dispatcher/src/solve_pixi/mod.rs @@ -86,6 +86,12 @@ pub struct PixiEnvironmentSpec { /// The protocols that are enabled for source packages #[serde(skip_serializing_if = "crate::is_default")] pub enabled_protocols: EnabledProtocols, + + /// Optional override for a specific packages: use this pinned + /// source for checkout and as the `package_build_source` instead + /// of pinning anew. + #[serde(skip)] + pub pin_overrides: BTreeMap, } impl Default for PixiEnvironmentSpec { @@ -104,6 +110,7 @@ impl Default for PixiEnvironmentSpec { variants: None, variant_files: None, enabled_protocols: EnabledProtocols::default(), + pin_overrides: BTreeMap::new(), } } } @@ -141,6 +148,7 @@ impl PixiEnvironmentSpec { self.variants.clone(), self.variant_files.clone(), self.enabled_protocols.clone(), + self.pin_overrides.clone(), ) .collect( source_specs diff --git a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs index 5bca9933a6..c4e6b95efc 100644 --- a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs +++ b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs @@ -29,6 +29,7 @@ pub struct SourceMetadataCollector { enabled_protocols: EnabledProtocols, variants: Option>>, variant_files: Option>, + pin_overrides: BTreeMap, } #[derive(Default)] @@ -76,6 +77,7 @@ impl SourceMetadataCollector { variants: Option>>, variant_files: Option>, enabled_protocols: EnabledProtocols, + pin_overrides: BTreeMap, ) -> Self { Self { command_queue, @@ -85,6 +87,7 @@ impl SourceMetadataCollector { channel_config, variants, variant_files, + pin_overrides, } } @@ -160,7 +163,11 @@ impl SourceMetadataCollector { > { tracing::trace!("Collecting source metadata for {name:#?}"); - // Get the source for the particular package. + // Determine if we should override the build_source pin for this package. + let override_pin = self.pin_overrides.get(&name).cloned(); + + // Always checkout the manifest-defined source location (root), discovery + // will pick build_source; we only override the build pin later. let source = self .command_queue .pin_and_checkout(spec.location) @@ -177,13 +184,14 @@ impl SourceMetadataCollector { .source_metadata(SourceMetadataSpec { package: name.clone(), backend_metadata: BuildBackendMetadataSpec { - source: source.pinned, + manifest_source: source.pinned, channel_config: self.channel_config.clone(), channels: self.channels.clone(), build_environment: self.build_environment.clone(), variants: self.variants.clone(), variant_files: self.variant_files.clone(), enabled_protocols: self.enabled_protocols.clone(), + pin_override: override_pin, }, }) .await diff --git a/crates/pixi_command_dispatcher/src/source_build/mod.rs b/crates/pixi_command_dispatcher/src/source_build/mod.rs index 986fcb3f15..27a622c92a 100644 --- a/crates/pixi_command_dispatcher/src/source_build/mod.rs +++ b/crates/pixi_command_dispatcher/src/source_build/mod.rs @@ -9,7 +9,7 @@ use pixi_build_discovery::EnabledProtocols; use pixi_build_frontend::Backend; use pixi_build_types::procedures::conda_outputs::CondaOutputsParams; use pixi_record::{PinnedSourceSpec, PixiRecord}; -use pixi_spec::{SourceAnchor, SourceSpec}; +use pixi_spec::{SourceAnchor, SourceLocationSpec, SourceSpec}; use rattler_conda_types::{ ChannelConfig, ChannelUrl, ConvertSubdirError, InvalidPackageNameError, PackageRecord, Platform, RepoDataRecord, prefix::Prefix, @@ -51,7 +51,11 @@ pub struct SourceBuildSpec { pub package: PackageIdentifier, /// The location of the source code to build. - pub source: PinnedSourceSpec, + pub manifest_source: PinnedSourceSpec, + + /// Optional source spec of sources which will be built. + #[serde(skip_serializing_if = "Option::is_none")] + pub build_source: Option, /// The channel configuration to use when resolving metadata pub channel_config: ChannelConfig, @@ -119,7 +123,7 @@ impl SourceBuildSpec { skip_all, name = "source-build", fields( - source= %self.source, + source= %self.manifest_source, package = %self.package, ) )] @@ -137,10 +141,11 @@ impl SourceBuildSpec { } else { // Query the source build cache. let build_cache = command_dispatcher + .clone() .source_build_cache_status(SourceBuildCacheStatusSpec { package: self.package.clone(), build_environment: self.build_environment.clone(), - source: self.source.clone(), + source: self.manifest_source.clone(), channels: self.channels.clone(), channel_config: self.channel_config.clone(), enabled_protocols: self.enabled_protocols.clone(), @@ -213,8 +218,8 @@ impl SourceBuildSpec { }; // Check out the source code. - let source_checkout = command_dispatcher - .checkout_pinned_source(self.source.clone()) + let manifest_source_checkout = command_dispatcher + .checkout_pinned_source(self.manifest_source.clone()) .await .map_err_with(SourceBuildError::SourceCheckout)?; @@ -222,7 +227,7 @@ impl SourceBuildSpec { // path). let discovered_backend = command_dispatcher .discover_backend( - &source_checkout.path, + &manifest_source_checkout.path, self.channel_config.clone(), self.enabled_protocols.clone(), ) @@ -232,19 +237,56 @@ impl SourceBuildSpec { // Compute the package input hash for caching purposes. let package_build_input_hash = PackageBuildInputHash::from(discovered_backend.as_ref()); + // Determine the build source to use: either from lock file or workspace + + // Ensure legacy lock entries that missed the git subdirectory pick it up from the + // manifest so we check out the correct directory. + let mut build_source = self.build_source.clone(); + if let (Some(PinnedSourceSpec::Git(pinned_git)), Some(SourceLocationSpec::Git(git_spec))) = ( + build_source.as_mut(), + discovered_backend.init_params.build_source.clone(), + ) { + if pinned_git.source.subdirectory.is_none() { + pinned_git.source.subdirectory = git_spec.subdirectory.clone(); + } + } + + // Here we have to get path in which we will run build. We have those options in order of decreasing priority: + // 1. Lock file `package_build_source`. Since we're running lock file update before building package it should pin source in there. + // 2. Manifest package build. This can happen if package isn't added to the dependencies of manifest, so no pinning happens in that case. + // 3. Manifest source. Just assume that source is located at the same directory as the manifest. + let build_source_dir = if let Some(pinned_build_source) = build_source { + let build_source_checkout = command_dispatcher + .checkout_pinned_source(pinned_build_source) + .await + .map_err_with(SourceBuildError::SourceCheckout)?; + build_source_checkout.path + } else if let Some(manifest_build_source) = + discovered_backend.init_params.build_source.clone() + { + let build_source_checkout = command_dispatcher + .pin_and_checkout(manifest_build_source) + .await + .map_err_with(SourceBuildError::SourceCheckout)?; + build_source_checkout.path + } else { + manifest_source_checkout.path + }; + // Instantiate the backend with the discovered information. - let backend = command_dispatcher - .instantiate_backend(InstantiateBackendSpec { - backend_spec: discovered_backend - .backend_spec - .clone() - .resolve(SourceAnchor::from(SourceSpec::from(self.source.clone()))), - init_params: discovered_backend.init_params.clone(), - channel_config: self.channel_config.clone(), - enabled_protocols: self.enabled_protocols.clone(), - }) - .await - .map_err_with(SourceBuildError::Initialize)?; + let backend = + command_dispatcher + .instantiate_backend(InstantiateBackendSpec { + backend_spec: discovered_backend.backend_spec.clone().resolve( + SourceAnchor::from(SourceSpec::from(self.manifest_source.clone())), + ), + init_params: discovered_backend.init_params.clone(), + build_source_dir, + channel_config: self.channel_config.clone(), + enabled_protocols: self.enabled_protocols.clone(), + }) + .await + .map_err_with(SourceBuildError::Initialize)?; // Determine the working directory for the build. let work_directory = match std::mem::take(&mut self.work_directory) { @@ -252,7 +294,7 @@ impl SourceBuildSpec { None => command_dispatcher.cache_dirs().working_dirs().join( WorkDirKey { source: SourceRecordOrCheckout::Record { - pinned: self.source.clone(), + pinned: self.manifest_source.clone(), package_name: self.package.name.clone(), }, host_platform: self.build_environment.host_platform, @@ -393,9 +435,41 @@ impl SourceBuildSpec { }) } + /// Little helper function the build a `BuildHostPackage` from expected and + /// installed records. + fn extract_prefix_repodata( + records: Vec, + prefix: Option, + ) -> Vec { + let Some(prefix) = prefix else { + return vec![]; + }; + + records + .into_iter() + .map(|record| match record { + PixiRecord::Binary(repodata_record) => BuildHostPackage { + repodata_record, + source: None, + }, + PixiRecord::Source(source) => { + let repodata_record = prefix + .resolved_source_records + .get(&source.package_record.name) + .cloned() + .expect("the source record should be present in the result sources"); + BuildHostPackage { + repodata_record, + source: Some(source.source), + } + } + }) + .collect() + } + /// Returns whether the package should be built in an editable mode. fn editable(&self) -> bool { - self.build_profile == BuildProfile::Development && self.source.is_mutable() + self.build_profile == BuildProfile::Development && self.manifest_source.is_mutable() } async fn build_v1( @@ -406,7 +480,7 @@ impl SourceBuildSpec { package_build_input_hash: PackageBuildInputHash, reporter: Option>, ) -> Result> { - let source_anchor = SourceAnchor::from(SourceSpec::from(self.source.clone())); + let source_anchor = SourceAnchor::from(SourceSpec::from(self.manifest_source.clone())); let host_platform = self.build_environment.host_platform; let build_platform = self.build_environment.build_platform; @@ -624,7 +698,7 @@ impl SourceBuildSpec { }), backend, package: self.package, - source: self.source, + source: self.manifest_source, work_directory, channels: self.channels, channel_config: self.channel_config, @@ -647,38 +721,6 @@ impl SourceBuildSpec { }) } - /// Little helper function the build a `BuildHostPackage` from expected and - /// installed records. - fn extract_prefix_repodata( - records: Vec, - prefix: Option, - ) -> Vec { - let Some(prefix) = prefix else { - return vec![]; - }; - - records - .into_iter() - .map(|record| match record { - PixiRecord::Binary(repodata_record) => BuildHostPackage { - repodata_record, - source: None, - }, - PixiRecord::Source(source) => { - let repodata_record = prefix - .resolved_source_records - .get(&source.package_record.name) - .cloned() - .expect("the source record should be present in the result sources"); - BuildHostPackage { - repodata_record, - source: Some(source.source), - } - } - }) - .collect() - } - async fn solve_dependencies( &self, name: String, @@ -712,6 +754,7 @@ impl SourceBuildSpec { variants: self.variants.clone(), variant_files: self.variant_files.clone(), enabled_protocols: self.enabled_protocols.clone(), + pin_overrides: BTreeMap::new(), }) .await } diff --git a/crates/pixi_command_dispatcher/src/source_metadata/mod.rs b/crates/pixi_command_dispatcher/src/source_metadata/mod.rs index ef0aba85a3..9d377d6c7f 100644 --- a/crates/pixi_command_dispatcher/src/source_metadata/mod.rs +++ b/crates/pixi_command_dispatcher/src/source_metadata/mod.rs @@ -1,6 +1,9 @@ mod cycle; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; pub use cycle::{Cycle, CycleEnvironment}; use futures::TryStreamExt; @@ -45,6 +48,8 @@ pub struct SourceMetadata { /// package. pub source: PinnedSourceSpec, + pub pinned_build_source: Option, + /// All the source records for this particular package. pub records: Vec, @@ -57,7 +62,7 @@ impl SourceMetadataSpec { skip_all, name = "source-metadata", fields( - source= %self.backend_metadata.source, + source= %self.backend_metadata.manifest_source, name = %self.package.as_source(), platform = %self.backend_metadata.build_environment.host_platform, ) @@ -79,17 +84,18 @@ impl SourceMetadataSpec { MetadataKind::GetMetadata { packages } => { // Convert the metadata to source records. let records = conversion::package_metadata_to_source_records( - &build_backend_metadata.source, + &build_backend_metadata.manifest_source, packages, &self.package, &build_backend_metadata.metadata.input_hash, ); Ok(SourceMetadata { - source: build_backend_metadata.source.clone(), + source: build_backend_metadata.manifest_source.clone(), records, // As the GetMetadata kind returns all records at once and we don't solve them we can skip this. skipped_packages: Default::default(), + pinned_build_source: None, }) } MetadataKind::Outputs { outputs } => { @@ -104,15 +110,16 @@ impl SourceMetadataSpec { &command_dispatcher, output, build_backend_metadata.metadata.input_hash.clone(), - build_backend_metadata.source.clone(), + build_backend_metadata.manifest_source.clone(), reporter.clone(), )); } Ok(SourceMetadata { - source: build_backend_metadata.source.clone(), + source: build_backend_metadata.manifest_source.clone(), records: futures.try_collect().await?, skipped_packages, + pinned_build_source: build_backend_metadata.build_source.clone(), }) } } @@ -287,6 +294,8 @@ impl SourceMetadataSpec { strong_constrains: binary_specs_to_match_spec(run_exports.strong_constrains)?, }; + let pinned_source_spec = None; + Ok(SourceRecord { package_record: PackageRecord { // We cannot now these values from the metadata because no actual package @@ -342,6 +351,7 @@ impl SourceMetadataSpec { }, source, input_hash, + pinned_source_spec, sources: sources .into_iter() .map(|(name, source)| (name.as_source().to_string(), source)) @@ -360,6 +370,12 @@ impl SourceMetadataSpec { if dependencies.dependencies.is_empty() { return Ok(vec![]); } + let pin_overrides = self + .backend_metadata + .pin_override + .as_ref() + .map(|pinned| BTreeMap::from([(pkg_name.clone(), pinned.clone())])) + .unwrap_or_default(); match command_dispatcher .solve_pixi_environment(PixiEnvironmentSpec { name: Some(format!("{} ({})", pkg_name.as_source(), env_type)), @@ -383,6 +399,7 @@ impl SourceMetadataSpec { variants: self.backend_metadata.variants.clone(), variant_files: self.backend_metadata.variant_files.clone(), enabled_protocols: self.backend_metadata.enabled_protocols.clone(), + pin_overrides, }) .await { diff --git a/crates/pixi_command_dispatcher/tests/integration/event_tree.rs b/crates/pixi_command_dispatcher/tests/integration/event_tree.rs index 14a33ecbf3..234df1521a 100644 --- a/crates/pixi_command_dispatcher/tests/integration/event_tree.rs +++ b/crates/pixi_command_dispatcher/tests/integration/event_tree.rs @@ -130,7 +130,7 @@ impl EventTree { format!( "{} @ {}", &spec.package.as_source(), - spec.backend_metadata.source + spec.backend_metadata.manifest_source ), ); builder.set_event_parent((*id).into(), *context); @@ -146,7 +146,7 @@ impl EventTree { } Event::SourceMetadataFinished { .. } => {} Event::BuildBackendMetadataQueued { id, context, spec } => { - build_backend_metadata_label.insert(*id, spec.source.to_string()); + build_backend_metadata_label.insert(*id, spec.manifest_source.to_string()); builder.set_event_parent((*id).into(), *context); } Event::BuildBackendMetadataStarted { id } => { @@ -162,7 +162,11 @@ impl EventTree { Event::SourceBuildQueued { id, context, spec } => { source_build_label.insert( *id, - format!("{} @ {}", spec.package.name.as_source(), spec.source), + format!( + "{} @ {}", + spec.package.name.as_source(), + spec.manifest_source + ), ); builder.set_event_parent((*id).into(), *context); } diff --git a/crates/pixi_core/src/lock_file/satisfiability/mod.rs b/crates/pixi_core/src/lock_file/satisfiability/mod.rs index df4c637054..7ad58c3485 100644 --- a/crates/pixi_core/src/lock_file/satisfiability/mod.rs +++ b/crates/pixi_core/src/lock_file/satisfiability/mod.rs @@ -397,6 +397,11 @@ pub enum PlatformUnsat { #[error("'{name}' is locked as a conda package but only requested by pypi dependencies")] CondaPackageShouldBePypi { name: String }, + + #[error( + "the locked package build source for '{0}' does not match the requested build source, {1}" + )] + PackageBuildSourceMismatch(String, SourceMismatchError), } #[derive(Debug, Error, Diagnostic)] @@ -1587,6 +1592,9 @@ pub(crate) async fn verify_package_platform_satisfiability( ))); } + // Verify the pixi build package's package_build_source matches the manifest. + verify_build_source_matches_manifest(environment, locked_pixi_records)?; + Ok(VerifiedIndividualEnvironment { expected_conda_packages, conda_packages_used_by_pypi, @@ -1840,6 +1848,106 @@ impl Display for EditablePackagesMismatch { } } +/// Verify that the current package's build.source in the manifest +/// matches the lock file's `package_build_source` (if applicable). +/// Path-based sources are not represented in the lock file's +/// `package_build_source` and are skipped. +fn verify_build_source_matches_manifest( + environment: &Environment<'_>, + locked_pixi_records: &PixiRecordsByName, +) -> Result<(), Box> { + let Some(pkg_manifest) = environment.workspace().package.as_ref() else { + return Ok(()); + }; + let Some(pkg_name) = &pkg_manifest.value.package.name else { + return Ok(()); + }; + let Some(requested_loc) = pkg_manifest.value.build.source.clone() else { + return Ok(()); + }; + + // Find the source record for the current package in locked conda packages. + let Some(record) = locked_pixi_records + .records + .iter() + .find(|r| r.package_record().name.as_source() == pkg_name) + else { + return Ok(()); + }; + + let PixiRecord::Source(src_record) = record else { + return Ok(()); + }; + + match requested_loc { + pixi_spec::SourceLocationSpec::Url(url_spec) => { + let Some(locked_url) = src_record + .pinned_source_spec + .as_ref() + .and_then(|p| p.as_url()) + else { + return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + SourceMismatchError::SourceTypeMismatch, + ))); + }; + locked_url.satisfies(&url_spec).map_err(|e| { + Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + e, + )) + }) + } + pixi_spec::SourceLocationSpec::Git(mut git_spec) => { + let Some(locked_git) = src_record + .pinned_source_spec + .as_ref() + .and_then(|p| p.as_git()) + else { + return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + SourceMismatchError::SourceTypeMismatch, + ))); + }; + // If the lock omitted subdirectory for package_build_source, ignore subdirectory + // difference in comparison. + if locked_git.source.subdirectory.is_none() { + git_spec.subdirectory = None; + } + // If manifest does not specify a rev (branch/tag/rev), treat it as DefaultBranch + // to ensure we compare references, not silently accept any locked branch. + if git_spec.rev.is_none() { + git_spec.rev = Some(pixi_spec::GitReference::DefaultBranch); + } + locked_git.satisfies(&git_spec).map_err(|e| { + Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + e, + )) + }) + } + pixi_spec::SourceLocationSpec::Path(path_spec) => { + let Some(locked_path) = src_record + .pinned_source_spec + .as_ref() + .and_then(|p| p.as_path()) + else { + return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + SourceMismatchError::SourceTypeMismatch, + ))); + }; + + locked_path.satisfies(&path_spec).map_err(|e| { + Box::new(PlatformUnsat::PackageBuildSourceMismatch( + src_record.package_record.name.as_source().to_string(), + e, + )) + }) + } + } +} + #[cfg(test)] mod tests { use std::{ diff --git a/crates/pixi_core/src/lock_file/update.rs b/crates/pixi_core/src/lock_file/update.rs index e7c3bfbf3a..dfbe5ddb30 100644 --- a/crates/pixi_core/src/lock_file/update.rs +++ b/crates/pixi_core/src/lock_file/update.rs @@ -1,6 +1,6 @@ use std::{ cmp::PartialEq, - collections::{HashMap, HashSet, hash_map::Entry}, + collections::{BTreeMap, HashMap, HashSet, hash_map::Entry}, future::{Future, ready}, iter, path::PathBuf, @@ -30,7 +30,7 @@ use pixi_install_pypi::{ }; use pixi_manifest::{ChannelPriority, EnvironmentName, FeaturesExt}; use pixi_progress::global_multi_progress; -use pixi_record::{ParseLockFileError, PixiRecord}; +use pixi_record::{ParseLockFileError, PinnedSourceSpec, PixiRecord, SourceRecord}; use pixi_utils::{prefix::Prefix, variants::VariantConfig}; use pixi_uv_context::UvResolutionContext; use pixi_uv_conversions::{ @@ -851,6 +851,9 @@ pub struct UpdateContext<'p> { /// The progress bar where all the command dispatcher progress will be /// placed. dispatcher_progress_bar: ProgressBar, + + /// Optional list of packages explicitly targeted for update. + update_targets: Option>, } impl<'p> UpdateContext<'p> { @@ -1027,6 +1030,9 @@ pub struct UpdateContextBuilder<'p> { /// Set the command dispatcher to use for the update process. command_dispatcher: Option, + + /// Optional list of package names explicitly targeted for update. + update_targets: Option>, } impl<'p> UpdateContextBuilder<'p> { @@ -1067,6 +1073,17 @@ impl<'p> UpdateContextBuilder<'p> { } } + /// Sets the packages explicitly targeted for update. + pub fn with_update_targets( + self, + update_targets: Option>, + ) -> Self { + Self { + update_targets, + ..self + } + } + /// Explicitly set the environments that are considered out-of-date. Only /// these environments will be updated during the update process. pub fn with_outdated_environments( @@ -1309,6 +1326,7 @@ impl<'p> UpdateContextBuilder<'p> { dispatcher_progress_bar: anchor_pb, no_install: self.no_install, + update_targets: self.update_targets, }) } } @@ -1326,6 +1344,7 @@ impl<'p> UpdateContext<'p> { glob_hash_cache: None, mapping_client: None, command_dispatcher: None, + update_targets: None, } } @@ -1396,6 +1415,33 @@ impl<'p> UpdateContext<'p> { .unwrap_or_default(); // Spawn a task to solve the group. + // Determine override pinned sources for source packages when performing + // a targeted update. + let pin_overrides = (|| { + let targets = self.update_targets.as_ref()?; + if targets.is_empty() { + return None; + } + Some( + locked_group_records + .records + .iter() + .filter_map(|r| match r { + PixiRecord::Source(src) => { + let name = src.package_record.name.clone(); + if targets.contains(name.as_source()) { + src.pinned_source_spec.clone().map(|spec| (name, spec)) + } else { + None + } + } + _ => None, + }) + .collect(), + ) + })() + .unwrap_or_default(); + let group_solve_task = spawn_solve_conda_environment_task( source.clone(), locked_group_records, @@ -1403,6 +1449,7 @@ impl<'p> UpdateContext<'p> { platform, channel_priority, self.command_dispatcher.clone(), + pin_overrides, ) .map_err(Report::new) .boxed_local(); @@ -1908,6 +1955,7 @@ async fn spawn_solve_conda_environment_task( platform: Platform, channel_priority: ChannelPriority, command_dispatcher: CommandDispatcher, + pin_overrides: BTreeMap, ) -> Result { // Get the dependencies for this platform let dependencies = group.combined_dependencies(Some(platform)); @@ -1964,6 +2012,7 @@ async fn spawn_solve_conda_environment_task( let start = Instant::now(); // Solve the environment using the command dispatcher. + // Determine if we should override the pinned source for the current package let mut records = command_dispatcher .solve_pixi_environment(PixiEnvironmentSpec { name: Some(group_name.to_string()), @@ -1979,6 +2028,7 @@ async fn spawn_solve_conda_environment_task( variants: Some(variants), variant_files: Some(variant_files), enabled_protocols: Default::default(), + pin_overrides, }) .await .map_err(|source| SolveCondaEnvironmentError::SolveFailed { diff --git a/crates/pixi_global/Cargo.toml b/crates/pixi_global/Cargo.toml index 51a7220465..9c50a9be46 100644 --- a/crates/pixi_global/Cargo.toml +++ b/crates/pixi_global/Cargo.toml @@ -46,6 +46,7 @@ rattler_virtual_packages = { workspace = true } regex = { workspace = true } rstest = { workspace = true } serde = { workspace = true } +serde_derive = { workspace = true } serde_json = { workspace = true } serde_with = { workspace = true } tempfile = { workspace = true } diff --git a/crates/pixi_global/src/project/mod.rs b/crates/pixi_global/src/project/mod.rs index b5bdc952b7..a39953ff6b 100644 --- a/crates/pixi_global/src/project/mod.rs +++ b/crates/pixi_global/src/project/mod.rs @@ -1380,7 +1380,7 @@ impl Project { // Create the metadata spec let metadata_spec = BuildBackendMetadataSpec { - source: pinned_source_spec, + manifest_source: pinned_source_spec, channel_config: self.global_channel_config().clone(), channels: self .config() @@ -1392,6 +1392,7 @@ impl Project { variants: None, variant_files: None, enabled_protocols: Default::default(), + pin_override: None, }; // Get the metadata using the command dispatcher diff --git a/crates/pixi_global/src/project/parsed_manifest.rs b/crates/pixi_global/src/project/parsed_manifest.rs index bb403a4d37..10f6b2abe6 100644 --- a/crates/pixi_global/src/project/parsed_manifest.rs +++ b/crates/pixi_global/src/project/parsed_manifest.rs @@ -11,7 +11,7 @@ use pixi_spec::PixiSpec; use pixi_toml::{TomlFromStr, TomlIndexMap, TomlIndexSet, TomlWith}; use rattler_conda_types::{NamedChannelOrUrl, PackageName, Platform}; use serde::{Serialize, Serializer, ser::SerializeMap}; -use serde_with::serde_derive::Deserialize; +use serde_derive::Deserialize; use thiserror::Error; use toml_span::{DeserError, Deserialize, Value, de_helpers::TableHelper}; diff --git a/crates/pixi_manifest/src/build_system.rs b/crates/pixi_manifest/src/build_system.rs index a523af3352..ef5a11ed01 100644 --- a/crates/pixi_manifest/src/build_system.rs +++ b/crates/pixi_manifest/src/build_system.rs @@ -106,7 +106,47 @@ mod tests { "https://prefix.dev/pixi-build-backends", "https://prefix.dev/conda-forge", ] - source = { git = "https://github.com/conda-forge/numpy-feedstock" } + source = { git = "https://github.com/conda-forge/numpy-feedstock", rev ="ee87916a49d5e96d4f322f68c3650e8ff6b8866b" } + "#; + + let build = PackageBuild::from_toml_str(toml).unwrap(); + assert_eq!( + build.value.backend.name.as_source(), + "pixi-build-rattler-build" + ); + assert!(build.value.source.is_some()); + assert!(build.value.source.unwrap().is_git()); + } + + #[test] + fn deserialize_build_with_git_source_branch() { + let toml = r#" + backend = { name = "pixi-build-rattler-build", version = "0.1.*" } + channels = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", + ] + source = { git = "https://github.com/conda-forge/numpy-feedstock", branch = "main" } + "#; + + let build = PackageBuild::from_toml_str(toml).unwrap(); + assert_eq!( + build.value.backend.name.as_source(), + "pixi-build-rattler-build" + ); + assert!(build.value.source.is_some()); + assert!(build.value.source.unwrap().is_git()); + } + + #[test] + fn deserialize_build_with_git_source_tag() { + let toml = r#" + backend = { name = "pixi-build-rattler-build", version = "0.1.*" } + channels = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", + ] + source = { git = "https://github.com/conda-forge/numpy-feedstock", tag = "v1.0.0" } "#; let build = PackageBuild::from_toml_str(toml).unwrap(); diff --git a/crates/pixi_manifest/src/toml/build_backend.rs b/crates/pixi_manifest/src/toml/build_backend.rs index a5df603eee..457f547e17 100644 --- a/crates/pixi_manifest/src/toml/build_backend.rs +++ b/crates/pixi_manifest/src/toml/build_backend.rs @@ -169,7 +169,7 @@ static BOTH_ADDITIONAL_DEPS_WARNING: Once = Once::new(); fn spec_from_spanned_toml_location( spanned_toml: Spanned, ) -> Result { - spanned_toml + let source_location_spec = spanned_toml .value .into_source_location_spec() .map_err(|err| { @@ -178,7 +178,9 @@ fn spec_from_spanned_toml_location( span: spanned_toml.span, line_info: None, }) - }) + })?; + + Ok(source_location_spec) } impl<'de> toml_span::Deserialize<'de> for TomlPackageBuild { diff --git a/crates/pixi_record/Cargo.toml b/crates/pixi_record/Cargo.toml index fb59a6397b..31a4990a4a 100644 --- a/crates/pixi_record/Cargo.toml +++ b/crates/pixi_record/Cargo.toml @@ -22,3 +22,6 @@ serde_with = { workspace = true } thiserror = { workspace = true } typed-path = { workspace = true } url = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true } diff --git a/crates/pixi_record/src/source_record.rs b/crates/pixi_record/src/source_record.rs index 85537b4b50..8f80f3ba79 100644 --- a/crates/pixi_record/src/source_record.rs +++ b/crates/pixi_record/src/source_record.rs @@ -1,12 +1,17 @@ -use std::collections::{BTreeSet, HashMap}; +use std::{ + collections::{BTreeSet, HashMap}, + str::FromStr, +}; -use pixi_spec::SourceSpec; +use pixi_git::sha::GitSha; +use pixi_spec::{GitReference, SourceSpec}; use rattler_conda_types::{MatchSpec, Matches, NamelessMatchSpec, PackageRecord}; use rattler_digest::{Sha256, Sha256Hash}; -use rattler_lock::{CondaPackageData, CondaSourceData}; +use rattler_lock::{CondaPackageData, CondaSourceData, GitShallowSpec, PackageBuildSource}; use serde::{Deserialize, Serialize}; +use typed_path::Utf8TypedPathBuf; -use crate::{ParseLockFileError, PinnedSourceSpec}; +use crate::{ParseLockFileError, PinnedGitCheckout, PinnedSourceSpec}; /// A record of a conda package that still requires building. #[derive(Debug, Clone, serde::Serialize)] @@ -18,6 +23,8 @@ pub struct SourceRecord { /// Exact definition of the source of the package. pub source: PinnedSourceSpec, + pub pinned_source_spec: Option, + /// The hash of the input that was used to build the metadata of the /// package. This can be used to verify that the metadata is still valid. /// @@ -48,9 +55,41 @@ pub struct InputHash { impl From for CondaPackageData { fn from(value: SourceRecord) -> Self { + let package_build_source = value.pinned_source_spec.map(|s| match s { + PinnedSourceSpec::Url(pinned_url_spec) => PackageBuildSource::Url { + url: pinned_url_spec.url, + sha256: pinned_url_spec.sha256, + subdir: None, + }, + PinnedSourceSpec::Git(pinned_git_spec) => { + let subdirectory = pinned_git_spec + .source + .subdirectory + .as_deref() + .map(Utf8TypedPathBuf::from); + + let spec = match &pinned_git_spec.source.reference { + GitReference::Branch(branch) => Some(GitShallowSpec::Branch(branch.clone())), + GitReference::Tag(tag) => Some(GitShallowSpec::Tag(tag.clone())), + GitReference::Rev(_) => Some(GitShallowSpec::Rev), + GitReference::DefaultBranch => None, + }; + + PackageBuildSource::Git { + url: pinned_git_spec.git, + spec, + rev: pinned_git_spec.source.commit.to_string(), + subdir: subdirectory, + } + } + PinnedSourceSpec::Path(pinned_path) => PackageBuildSource::Path { + path: pinned_path.path, + }, + }); CondaPackageData::Source(CondaSourceData { package_record: value.package_record, - location: value.source.into(), + location: value.source.clone().into(), + package_build_source, input: value.input_hash.map(|i| rattler_lock::InputHash { hash: i.hash, // TODO: fix this in rattler @@ -61,7 +100,6 @@ impl From for CondaPackageData { .into_iter() .map(|(k, v)| (k, v.into())) .collect(), - package_build_source: None, }) } } @@ -70,6 +108,42 @@ impl TryFrom for SourceRecord { type Error = ParseLockFileError; fn try_from(value: CondaSourceData) -> Result { + let pinned_source_spec = value.package_build_source.map(|source| match source { + PackageBuildSource::Git { + url, + spec, + rev, + subdir, + } => { + let reference = match spec { + Some(GitShallowSpec::Branch(branch)) => GitReference::Branch(branch), + Some(GitShallowSpec::Tag(tag)) => GitReference::Tag(tag), + Some(GitShallowSpec::Rev) => GitReference::Rev(rev.clone()), + None => GitReference::DefaultBranch, + }; + + PinnedSourceSpec::Git(crate::PinnedGitSpec { + git: url, + source: PinnedGitCheckout { + commit: GitSha::from_str(&rev).unwrap(), + subdirectory: subdir.map(|s| s.to_string()), + reference, + }, + }) + } + PackageBuildSource::Url { + url, + sha256, + subdir: _, + } => PinnedSourceSpec::Url(crate::PinnedUrlSpec { + url, + sha256, + md5: None, + }), + PackageBuildSource::Path { path } => { + PinnedSourceSpec::Path(crate::PinnedPathSpec { path }) + } + }); Ok(Self { package_record: value.package_record, source: value.location.try_into()?, @@ -77,6 +151,7 @@ impl TryFrom for SourceRecord { hash: hash.hash, globs: BTreeSet::from_iter(hash.globs), }), + pinned_source_spec, sources: value .sources .into_iter() @@ -123,3 +198,77 @@ impl AsRef for SourceRecord { &self.package_record } } + +#[cfg(test)] +mod tests { + use super::*; + use pixi_git::sha::GitSha; + use serde_json::json; + use std::str::FromStr; + use url::Url; + + #[test] + fn package_build_source_roundtrip_preserves_git_subdirectory() { + let package_record: PackageRecord = serde_json::from_value(json!({ + "name": "example", + "version": "1.0.0", + "build": "0", + "build_number": 0, + "subdir": "noarch", + })) + .expect("valid package record"); + + let git_url = Url::parse("https://example.com/repo.git").unwrap(); + let pinned_source = PinnedSourceSpec::Git(crate::PinnedGitSpec { + git: git_url.clone(), + source: PinnedGitCheckout { + commit: GitSha::from_str("0123456789abcdef0123456789abcdef01234567").unwrap(), + subdirectory: Some("nested/project".to_string()), + reference: GitReference::Branch("main".to_string()), + }, + }); + + let record = SourceRecord { + package_record, + source: pinned_source.clone(), + pinned_source_spec: Some(pinned_source.clone()), + input_hash: None, + sources: Default::default(), + }; + + let CondaPackageData::Source(conda_source) = record.clone().into() else { + panic!("expected source package data"); + }; + + let package_build_source = conda_source + .package_build_source + .as_ref() + .expect("expected package build source"); + + let PackageBuildSource::Git { + url, + spec, + rev, + subdir, + } = package_build_source + else { + panic!("expected git package build source"); + }; + + assert_eq!(url.path(), "/repo.git"); + assert_eq!(url.host_str(), Some("example.com")); + assert_eq!(subdir.as_ref().map(|s| s.as_str()), Some("nested/project")); + assert!(matches!(spec, Some(GitShallowSpec::Branch(branch)) if branch == "main")); + assert_eq!(rev, "0123456789abcdef0123456789abcdef01234567"); + + let roundtrip = SourceRecord::try_from(conda_source).expect("roundtrip should succeed"); + let Some(PinnedSourceSpec::Git(roundtrip_git)) = roundtrip.pinned_source_spec else { + panic!("expected git pinned source"); + }; + assert_eq!( + roundtrip_git.source.subdirectory.as_deref(), + Some("nested/project") + ); + assert_eq!(roundtrip_git.git, git_url); + } +} diff --git a/docs/reference/cli/pixi.md b/docs/reference/cli/pixi.md index 931a48e653..ea7f2d749a 100644 --- a/docs/reference/cli/pixi.md +++ b/docs/reference/cli/pixi.md @@ -13,7 +13,7 @@ pixi [OPTIONS] [COMMAND] |---------|-------------| | [`add`](pixi/add.md) | Adds dependencies to the workspace | | [`auth`](pixi/auth.md) | Login to prefix.dev or anaconda.org servers to access private channels | -| [`build`](pixi/build.md) | Workspace configuration | +| [`build`](pixi/build.md) | Lock file and installation configuration with --as-is support Used by shell, shell-hook, and run commands | | [`clean`](pixi/clean.md) | Cleanup the environments | | [`completion`](pixi/completion.md) | Generates a completion script for a shell | | [`config`](pixi/config.md) | Configuration management | diff --git a/docs/reference/cli/pixi/build.md b/docs/reference/cli/pixi/build.md index c9fb0452c1..075b2300c9 100644 --- a/docs/reference/cli/pixi/build.md +++ b/docs/reference/cli/pixi/build.md @@ -2,7 +2,7 @@ # [pixi](../pixi.md) build ## About -Workspace configuration +Lock file and installation configuration with --as-is support Used by shell, shell-hook, and run commands --8<-- "docs/reference/cli/pixi/build_extender:description" @@ -46,6 +46,18 @@ pixi build [OPTIONS] - `--use-environment-activation-cache` : Use environment activation cache (experimental) +## Update Options +- `--no-install` +: Don't modify the environment, only modify the lock-file +- `--frozen` +: Install the environment as defined in the lockfile, doesn't update lockfile if it isn't up-to-date with the manifest file +
**env**: `PIXI_FROZEN` +- `--locked` +: Check if lockfile is up-to-date before installing the environment, aborts when lockfile isn't up-to-date with the manifest file +
**env**: `PIXI_LOCKED` +- `--as-is` +: Shorthand for the combination of --no-install and --frozen + ## Global Options - `--manifest-path ` : The path to `pixi.toml`, `pyproject.toml`, or the workspace directory diff --git a/docs/reference/pixi_manifest.md b/docs/reference/pixi_manifest.md index 08c2674b7b..a504391b15 100644 --- a/docs/reference/pixi_manifest.md +++ b/docs/reference/pixi_manifest.md @@ -1038,6 +1038,9 @@ The build system is a table that can contain the following fields: - `source`: specifies the location of the source code for the package. Default: manifest directory. Currently supported options: - `path`: a string representing a relative or absolute path to the source code. + - `git`: a string representing URL to the source repository. + - `rev`: a string representing SHA revision to checkout. + - `subdirectory`: a string representing path to subdirectory to use. - `channels`: specifies the channels to get the build backend from. - `backend`: specifies the build backend to use. This is a table that can contain the following fields: - `name`: the name of the build backend to use. This will also be the executable name. diff --git a/examples/pixi-build/cpp-git-source/pixi.lock b/examples/pixi-build/cpp-git-source/pixi.lock new file mode 100644 index 0000000000..eb02736880 --- /dev/null +++ b/examples/pixi-build/cpp-git-source/pixi.lock @@ -0,0 +1,1123 @@ +version: 6 +environments: + default: + channels: + - url: https://prefix.dev/conda-forge/ + packages: + linux-64: + - conda: https://prefix.dev/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://prefix.dev/conda-forge/linux-64/attr-2.5.2-h39aace5_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + - conda: https://prefix.dev/conda-forge/linux-64/dbus-1.16.2-h3c4dab8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/gettext-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/gettext-tools-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 + - conda: https://prefix.dev/conda-forge/linux-64/libasprintf-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libasprintf-devel-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libcap-2.76-h0b2e76d_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcrypt-lib-1.11.1-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-devel-0.25.1-h3f43e3d_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgpg-error-1.55-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libopus-1.5.2-hd0c01bc_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.9-h996ca69_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.9-h085a93f_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/liburing-2.12-hb700be7_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libusb-1.0.29-h73b1eb8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.11.0-hca5e8e5_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxml2-16-2.15.0-ha9997c6_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.15.0-h26afc86_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + - conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-h9a8bead_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.56-h54a6638_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.22-h68140b3_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxscrnsaver-1.2.4-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + - conda: . + subdir: linux-64 + osx-arm64: + - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/dbus-1.16.2-hda038a8_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.2-hf598326_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libusb-1.0.29-hbc156a2_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2-2.32.56-h248ca61_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.22-he22eeb8_0.conda + - conda: . + subdir: osx-arm64 + win-64: + - conda: https://prefix.dev/conda-forge/win-64/libusb-1.0.29-h1839187_0.conda + - conda: https://prefix.dev/conda-forge/win-64/sdl2-2.32.56-h5112557_0.conda + - conda: https://prefix.dev/conda-forge/win-64/sdl3-3.2.22-h5112557_0.conda + - conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://prefix.dev/conda-forge/win-64/vc-14.3-h41ae7f8_31.conda + - conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_31.conda + - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda + - conda: . + build: h9352c13_0 +packages: +- conda: https://prefix.dev/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + md5: d7c89558ba9fa0495403155b64376d81 + license: None + size: 2562 + timestamp: 1578324546067 +- conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + build_number: 16 + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + md5: 73aaf86a425cc6e73fcf236a5a46396d + depends: + - _libgcc_mutex 0.1 conda_forge + - libgomp >=7.5.0 + constrains: + - openmp_impl 9999 + license: BSD-3-Clause + license_family: BSD + size: 23621 + timestamp: 1650670423406 +- conda: https://prefix.dev/conda-forge/linux-64/attr-2.5.2-h39aace5_0.conda + sha256: a9c114cbfeda42a226e2db1809a538929d2f118ef855372293bd188f71711c48 + md5: 791365c5f65975051e4e017b5da3abf5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: GPL-2.0-or-later + license_family: GPL + size: 68072 + timestamp: 1756738968573 +- conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + sha256: c30daba32ddebbb7ded490f0e371eae90f51e72db620554089103b4a6934b0d5 + md5: 51a19bba1b8ebfb60df25cde030b7ebc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + size: 260341 + timestamp: 1757437258798 +- conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda + sha256: b456200636bd5fecb2bec63f7e0985ad2097cf1b83d60ce0b6968dffa6d02aa1 + md5: 58fd217444c2a5701a44244faf518206 + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + size: 125061 + timestamp: 1757437486465 +- conda: https://prefix.dev/conda-forge/linux-64/dbus-1.16.2-h3c4dab8_0.conda + sha256: 3b988146a50e165f0fa4e839545c679af88e4782ec284cc7b6d07dd226d6a068 + md5: 679616eb5ad4e521c83da4650860aba7 + depends: + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libexpat >=2.7.0,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - libglib >=2.84.2,<3.0a0 + license: GPL-2.0-or-later + license_family: GPL + size: 437860 + timestamp: 1747855126005 +- conda: https://prefix.dev/conda-forge/osx-arm64/dbus-1.16.2-hda038a8_0.conda + sha256: 2ef01ab52dedb477cb7291994ad556279b37c8ad457521e75c47cad20248ea30 + md5: 80c663e4f6b0fd8d6723ff7d68f09429 + depends: + - __osx >=11.0 + - libcxx >=18 + - libzlib >=1.3.1,<2.0a0 + - libglib >=2.84.2,<3.0a0 + - libexpat >=2.7.0,<3.0a0 + license: GPL-2.0-or-later + license_family: GPL + size: 384376 + timestamp: 1747855177419 +- conda: https://prefix.dev/conda-forge/linux-64/gettext-0.25.1-h3f43e3d_1.conda + sha256: cbfa8c80771d1842c2687f6016c5e200b52d4ca8f2cc119f6377f64f899ba4ff + md5: c42356557d7f2e37676e121515417e3b + depends: + - __glibc >=2.17,<3.0.a0 + - gettext-tools 0.25.1 h3f43e3d_1 + - libasprintf 0.25.1 h3f43e3d_1 + - libasprintf-devel 0.25.1 h3f43e3d_1 + - libgcc >=14 + - libgettextpo 0.25.1 h3f43e3d_1 + - libgettextpo-devel 0.25.1 h3f43e3d_1 + - libiconv >=1.18,<2.0a0 + - libstdcxx >=14 + license: LGPL-2.1-or-later AND GPL-3.0-or-later + size: 541357 + timestamp: 1753343006214 +- conda: https://prefix.dev/conda-forge/linux-64/gettext-tools-0.25.1-h3f43e3d_1.conda + sha256: c792729288bdd94f21f25f80802d4c66957b4e00a57f7cb20513f07aadfaff06 + md5: a59c05d22bdcbb4e984bf0c021a2a02f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + license: GPL-3.0-or-later + license_family: GPL + size: 3644103 + timestamp: 1753342966311 +- conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda + sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e + md5: 8b189310083baabfb622af68fd9d3ae3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: MIT + license_family: MIT + size: 12129203 + timestamp: 1720853576813 +- conda: https://prefix.dev/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 + sha256: aad2a703b9d7b038c0f745b853c6bb5f122988fe1a7a096e0e606d9cbec4eaab + md5: a8832b479f93521a9e7b5b743803be51 + depends: + - libgcc-ng >=12 + license: LGPL-2.0-only + license_family: LGPL + size: 508258 + timestamp: 1664996250081 +- conda: https://prefix.dev/conda-forge/linux-64/libasprintf-0.25.1-h3f43e3d_1.conda + sha256: cb728a2a95557bb6a5184be2b8be83a6f2083000d0c7eff4ad5bbe5792133541 + md5: 3b0d184bc9404516d418d4509e418bdc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: LGPL-2.1-or-later + size: 53582 + timestamp: 1753342901341 +- conda: https://prefix.dev/conda-forge/linux-64/libasprintf-devel-0.25.1-h3f43e3d_1.conda + sha256: 2fc95060efc3d76547b7872875af0b7212d4b1407165be11c5f830aeeb57fc3a + md5: fd9cf4a11d07f0ef3e44fc061611b1ed + depends: + - __glibc >=2.17,<3.0.a0 + - libasprintf 0.25.1 h3f43e3d_1 + - libgcc >=14 + license: LGPL-2.1-or-later + size: 34734 + timestamp: 1753342921605 +- conda: https://prefix.dev/conda-forge/linux-64/libcap-2.76-h0b2e76d_0.conda + sha256: a946b61be1af15ff08c7722e9bac0fab446d8b9896c9f0f35657dfcf887fda8a + md5: 0f7f0c878c8dceb3b9ec67f5c06d6057 + depends: + - __glibc >=2.17,<3.0.a0 + - attr >=2.5.1,<2.6.0a0 + - libgcc >=13 + license: BSD-3-Clause + license_family: BSD + size: 121852 + timestamp: 1744577167992 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.2-hf598326_0.conda + sha256: 3de00998c8271f599d6ed9aea60dc0b3e5b1b7ff9f26f8eac95f86f135aa9beb + md5: edfa256c5391f789384e470ce5c9f340 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 568154 + timestamp: 1758698306949 +- conda: https://prefix.dev/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda + sha256: c076a213bd3676cc1ef22eeff91588826273513ccc6040d9bea68bccdc849501 + md5: 9314bc5a1fe7d1044dc9dfd3ef400535 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libpciaccess >=0.18,<0.19.0a0 + license: MIT + license_family: MIT + size: 310785 + timestamp: 1757212153962 +- conda: https://prefix.dev/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda + sha256: 7fd5408d359d05a969133e47af580183fbf38e2235b562193d427bb9dad79723 + md5: c151d5eb730e9b7480e6d48c0fc44048 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + size: 44840 + timestamp: 1731330973553 +- conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + sha256: da2080da8f0288b95dd86765c801c6e166c4619b910b11f9a8446fb852438dc2 + md5: 4211416ecba1866fab0c6470986c22d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + size: 74811 + timestamp: 1752719572741 +- conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + sha256: 8fbb17a56f51e7113ed511c5787e0dec0d4b10ef9df921c4fd1cccca0458f648 + md5: b1ca5f21335782f71a8bd69bdc093f67 + depends: + - __osx >=11.0 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + size: 65971 + timestamp: 1752719657566 +- conda: https://prefix.dev/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab + md5: ede4673863426c0883c0063d853bbd85 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 57433 + timestamp: 1743434498161 +- conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + sha256: c6a530924a9b14e193ea9adfe92843de2a806d1b7dbfd341546ece9653129e60 + md5: c215a60c2935b517dcda8cad4705734d + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 39839 + timestamp: 1743434670405 +- conda: https://prefix.dev/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda + sha256: 65908b75fa7003167b8a8f0001e11e58ed5b1ef5e98b96ab2ba66d7c1b822c7d + md5: ee48bf17cc83a00f59ca1494d5646869 + depends: + - gettext >=0.21.1,<1.0a0 + - libgcc-ng >=12 + - libogg 1.3.* + - libogg >=1.3.4,<1.4.0a0 + - libstdcxx-ng >=12 + license: BSD-3-Clause + license_family: BSD + size: 394383 + timestamp: 1687765514062 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda + sha256: 0caed73aac3966bfbf5710e06c728a24c6c138605121a3dacb2e03440e8baa6a + md5: 264fbfba7fb20acf3b29cde153e345ce + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgomp 15.1.0 h767d61c_5 + - libgcc-ng ==15.1.0=*_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 824191 + timestamp: 1757042543820 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda + sha256: f54bb9c3be12b24be327f4c1afccc2969712e0b091cdfbd1d763fb3e61cda03f + md5: 069afdf8ea72504e48d23ae1171d951c + depends: + - libgcc 15.1.0 h767d61c_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 29187 + timestamp: 1757042549554 +- conda: https://prefix.dev/conda-forge/linux-64/libgcrypt-lib-1.11.1-hb9d3cd8_0.conda + sha256: dc9c7d7a6c0e6639deee6fde2efdc7e119e7739a6b229fa5f9049a449bae6109 + md5: 8504a291085c9fb809b66cabd5834307 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libgpg-error >=1.55,<2.0a0 + license: LGPL-2.1-or-later + size: 590353 + timestamp: 1747060639058 +- conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-0.25.1-h3f43e3d_1.conda + sha256: 50a9e9815cf3f5bce1b8c5161c0899cc5b6c6052d6d73a4c27f749119e607100 + md5: 2f4de899028319b27eb7a4023be5dfd2 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + license: GPL-3.0-or-later + license_family: GPL + size: 188293 + timestamp: 1753342911214 +- conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-devel-0.25.1-h3f43e3d_1.conda + sha256: c7ea10326fd450a2a21955987db09dde78c99956a91f6f05386756a7bfe7cc04 + md5: 3f7a43b3160ec0345c9535a9f0d7908e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgettextpo 0.25.1 h3f43e3d_1 + - libiconv >=1.18,<2.0a0 + license: GPL-3.0-or-later + license_family: GPL + size: 37407 + timestamp: 1753342931100 +- conda: https://prefix.dev/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda + sha256: dc2752241fa3d9e40ce552c1942d0a4b5eeb93740c9723873f6fcf8d39ef8d2d + md5: 928b8be80851f5d8ffb016f9c81dae7a + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + - libglx 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + size: 134712 + timestamp: 1731330998354 +- conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda + sha256: 33336bd55981be938f4823db74291e1323454491623de0be61ecbe6cf3a4619c + md5: b8e4c93f4ab70c3b6f6499299627dbdc + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - pcre2 >=10.46,<10.47.0a0 + constrains: + - glib 2.86.0 *_0 + license: LGPL-2.1-or-later + size: 3978602 + timestamp: 1757403291664 +- conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda + sha256: 92d17f998e14218810493c9190c8721bf7f7f006bfc5c00dbba1cede83c02f1a + md5: 9e065148e6013b7d7cae64ed01ab7081 + depends: + - __osx >=11.0 + - libffi >=3.4.6,<3.5.0a0 + - libiconv >=1.18,<2.0a0 + - libintl >=0.25.1,<1.0a0 + - libzlib >=1.3.1,<2.0a0 + - pcre2 >=10.46,<10.47.0a0 + constrains: + - glib 2.86.0 *_0 + license: LGPL-2.1-or-later + size: 3701880 + timestamp: 1757404501093 +- conda: https://prefix.dev/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda + sha256: 1175f8a7a0c68b7f81962699751bb6574e6f07db4c9f72825f978e3016f46850 + md5: 434ca7e50e40f4918ab701e3facd59a0 + depends: + - __glibc >=2.17,<3.0.a0 + license: LicenseRef-libglvnd + size: 132463 + timestamp: 1731330968309 +- conda: https://prefix.dev/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda + sha256: 2d35a679624a93ce5b3e9dd301fff92343db609b79f0363e6d0ceb3a6478bfa7 + md5: c8013e438185f33b13814c5c488acd5c + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + - xorg-libx11 >=1.8.10,<2.0a0 + license: LicenseRef-libglvnd + size: 75504 + timestamp: 1731330988898 +- conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + sha256: 125051d51a8c04694d0830f6343af78b556dd88cc249dfec5a97703ebfb1832d + md5: dcd5ff1940cd38f6df777cac86819d60 + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 447215 + timestamp: 1757042483384 +- conda: https://prefix.dev/conda-forge/linux-64/libgpg-error-1.55-h3f2d84a_0.conda + sha256: 697334de4786a1067ea86853e520c64dd72b11a05137f5b318d8a444007b5e60 + md5: 2bd47db5807daade8500ed7ca4c512a4 + depends: + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-only + size: 312184 + timestamp: 1745575272035 +- conda: https://prefix.dev/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f + md5: 915f5995e94f60e9a4826e0b0920ee88 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: LGPL-2.1-only + size: 790176 + timestamp: 1754908768807 +- conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + sha256: de0336e800b2af9a40bdd694b03870ac4a848161b35c8a2325704f123f185f03 + md5: 4d5a7445f0b25b6a3ddbb56e790f5251 + depends: + - __osx >=11.0 + license: LGPL-2.1-only + size: 750379 + timestamp: 1754909073836 +- conda: https://prefix.dev/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + sha256: 99d2cebcd8f84961b86784451b010f5f0a795ed1c08f1e7c76fbb3c22abf021a + md5: 5103f6a6b210a3912faf8d7db516918c + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + license: LGPL-2.1-or-later + size: 90957 + timestamp: 1751558394144 +- conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: 1a580f7796c7bf6393fddb8bbbde58dc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - xz 5.8.1.* + license: 0BSD + size: 112894 + timestamp: 1749230047870 +- conda: https://prefix.dev/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda + sha256: ffb066ddf2e76953f92e06677021c73c85536098f1c21fcd15360dbc859e22e4 + md5: 68e52064ed3897463c0e958ab5c8f91b + depends: + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + license: BSD-3-Clause + license_family: BSD + size: 218500 + timestamp: 1745825989535 +- conda: https://prefix.dev/conda-forge/linux-64/libopus-1.5.2-hd0c01bc_0.conda + sha256: 786d43678d6d1dc5f88a6bad2d02830cfd5a0184e84a8caa45694049f0e3ea5f + md5: b64523fb87ac6f87f0790f324ad43046 + depends: + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + license: BSD-3-Clause + license_family: BSD + size: 312472 + timestamp: 1744330953241 +- conda: https://prefix.dev/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda + sha256: 0bd91de9b447a2991e666f284ae8c722ffb1d84acb594dbd0c031bd656fa32b2 + md5: 70e3400cbbfa03e96dcde7fc13e38c7b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 28424 + timestamp: 1749901812541 +- conda: https://prefix.dev/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda + sha256: f709cbede3d4f3aee4e2f8d60bd9e256057f410bd60b8964cb8cf82ec1457573 + md5: ef1910918dd895516a769ed36b5b3a4e + depends: + - lame >=3.100,<3.101.0a0 + - libflac >=1.4.3,<1.5.0a0 + - libgcc-ng >=12 + - libogg >=1.3.4,<1.4.0a0 + - libopus >=1.3.1,<2.0a0 + - libstdcxx-ng >=12 + - libvorbis >=1.3.7,<1.4.0a0 + - mpg123 >=1.32.1,<1.33.0a0 + license: LGPL-2.1-or-later + license_family: LGPL + size: 354372 + timestamp: 1695747735668 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda + sha256: 0f5f61cab229b6043541c13538d75ce11bd96fb2db76f94ecf81997b1fde6408 + md5: 4e02a49aaa9d5190cb630fa43528fbe6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.1.0 h767d61c_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 3896432 + timestamp: 1757042571458 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda + sha256: 7b8cabbf0ab4fe3581ca28fe8ca319f964078578a51dd2ca3f703c1d21ba23ff + md5: 8bba50c7f4679f08c861b597ad2bda6b + depends: + - libstdcxx 15.1.0 h8f9b012_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 29233 + timestamp: 1757042603319 +- conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.9-h996ca69_0.conda + sha256: 6b063df2d13dc9cedeae7b1591b1917ced7f4e1b04f7246e66cc7fb0088dea07 + md5: b6d222422c17dc11123e63fae4ad4178 + depends: + - __glibc >=2.17,<3.0.a0 + - libcap >=2.76,<2.77.0a0 + - libgcc >=14 + - libgcrypt-lib >=1.11.1,<2.0a0 + - liblzma >=5.8.1,<6.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: LGPL-2.1-or-later + size: 492733 + timestamp: 1757520335407 +- conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.9-h085a93f_0.conda + sha256: 1c8f0b02c400617a9f2ea8429c604b28e25a10f51b3c8d73ce127b4e7b462297 + md5: 973f365f19c1d702bda523658a77de26 + depends: + - __glibc >=2.17,<3.0.a0 + - libcap >=2.76,<2.77.0a0 + - libgcc >=14 + license: LGPL-2.1-or-later + size: 144265 + timestamp: 1757520342166 +- conda: https://prefix.dev/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda + sha256: 71c8b9d5c72473752a0bb6e91b01dd209a03916cb71f36cc6a564e3a2a132d7a + md5: e179a69edd30d75c0144d7a380b88f28 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + size: 75995 + timestamp: 1757032240102 +- conda: https://prefix.dev/conda-forge/linux-64/liburing-2.12-hb700be7_0.conda + sha256: 880b1f76b24814c9f07b33402e82fa66d5ae14738a35a943c21c4434eef2403d + md5: f0531fc1ebc0902555670e9cb0127758 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + size: 127967 + timestamp: 1756125594973 +- conda: https://prefix.dev/conda-forge/linux-64/libusb-1.0.29-h73b1eb8_0.conda + sha256: 89c84f5b26028a9d0f5c4014330703e7dff73ba0c98f90103e9cef6b43a5323c + md5: d17e3fb595a9f24fa9e149239a33475d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libudev1 >=257.4 + license: LGPL-2.1-or-later + size: 89551 + timestamp: 1748856210075 +- conda: https://prefix.dev/conda-forge/osx-arm64/libusb-1.0.29-hbc156a2_0.conda + sha256: 5eee9a2bf359e474d4548874bcfc8d29ebad0d9ba015314439c256904e40aaad + md5: f6654e9e96e9d973981b3b2f898a5bfa + depends: + - __osx >=11.0 + license: LGPL-2.1-or-later + size: 83849 + timestamp: 1748856224950 +- conda: https://prefix.dev/conda-forge/win-64/libusb-1.0.29-h1839187_0.conda + sha256: 9837f8e8de20b6c9c033561cd33b4554cd551b217e3b8d2862b353ed2c23d8b8 + md5: a656b2c367405cd24988cf67ff2675aa + depends: + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + license: LGPL-2.1-or-later + size: 118204 + timestamp: 1748856290542 +- conda: https://prefix.dev/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda + sha256: ca494c99c7e5ecc1b4cd2f72b5584cef3d4ce631d23511184411abcbb90a21a5 + md5: b4ecbefe517ed0157c37f8182768271c + depends: + - libogg + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - libogg >=1.3.5,<1.4.0a0 + license: BSD-3-Clause + license_family: BSD + size: 285894 + timestamp: 1753879378005 +- conda: https://prefix.dev/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda + sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa + md5: 92ed62436b625154323d40d5f2f11dd7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - pthread-stubs + - xorg-libxau >=1.0.11,<2.0a0 + - xorg-libxdmcp + license: MIT + license_family: MIT + size: 395888 + timestamp: 1727278577118 +- conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.11.0-hca5e8e5_1.conda + sha256: 2febd0cdea153a97737df3cfb900c312b012c0af3cc5a62f2968bd398d25b6b6 + md5: 9abb1e8cbc0039155a8ed2aa149b1067 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - libxcb >=1.17.0,<2.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - xkeyboard-config + - xorg-libxau >=1.0.12,<2.0a0 + license: MIT/X11 Derivative + license_family: MIT + size: 800138 + timestamp: 1757977095650 +- conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.15.0-h26afc86_1.conda + sha256: 4310577d7eea817d35a1c05e1e54575b06ce085d73e6dd59aa38523adf50168f + md5: 8337b675e0cad517fbcb3daf7588087a + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.1,<6.0a0 + - libxml2-16 2.15.0 ha9997c6_1 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + size: 45363 + timestamp: 1758640621036 +- conda: https://prefix.dev/conda-forge/linux-64/libxml2-16-2.15.0-ha9997c6_1.conda + sha256: 5420ea77505a8d5ca7b5351ddb2da7e8a178052fccf8fca00189af7877608e89 + md5: b24dd2bd61cd8e4f8a13ee2a945a723c + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.1,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.0 + license: MIT + license_family: MIT + size: 556276 + timestamp: 1758640612398 +- conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 + md5: edb0dca6bc32e4f4789199455a1dbeb8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 60963 + timestamp: 1727963148474 +- conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b + md5: 369964e85dc26bfe78f41399b366c435 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 46438 + timestamp: 1727963202283 +- conda: https://prefix.dev/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda + sha256: 47326f811392a5fd3055f0f773036c392d26fdb32e4d8e7a8197eed951489346 + md5: 9de5350a85c4a20c685259b889aa6393 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: BSD-2-Clause + license_family: BSD + size: 167055 + timestamp: 1733741040117 +- conda: https://prefix.dev/conda-forge/linux-64/mpg123-1.32.9-hc50e24c_0.conda + sha256: 39c4700fb3fbe403a77d8cc27352fa72ba744db487559d5d44bf8411bb4ea200 + md5: c7f302fd11eeb0987a6a5e1f3aed6a21 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: LGPL-2.1-only + license_family: LGPL + size: 491140 + timestamp: 1730581373280 +- conda: https://prefix.dev/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda + sha256: 5c7380c8fd3ad5fc0f8039069a45586aa452cf165264bc5a437ad80397b32934 + md5: 7fa07cb0fb1b625a089ccc01218ee5b1 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 1209177 + timestamp: 1756742976157 +- conda: https://prefix.dev/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda + sha256: 5bf2eeaa57aab6e8e95bea6bd6bb2a739f52eb10572d8ed259d25864d3528240 + md5: 0e6e82c3cc3835f4692022e9b9cd5df8 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 835080 + timestamp: 1756743041908 +- conda: https://prefix.dev/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 + md5: b3c17d95b5a10c6e64a21fa17573e70e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 8252 + timestamp: 1726802366959 +- conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-h9a8bead_2.conda + sha256: 8a6729861c9813a756b0438c30bd271722fb3f239ded3afc3bf1cb03327a640e + md5: b6f21b1c925ee2f3f7fc37798c5988db + depends: + - __glibc >=2.17,<3.0.a0 + - dbus >=1.16.2,<2.0a0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + - libiconv >=1.18,<2.0a0 + - libsndfile >=1.2.2,<1.3.0a0 + - libsystemd0 >=257.7 + - libxcb >=1.17.0,<2.0a0 + constrains: + - pulseaudio 17.0 *_2 + license: LGPL-2.1-or-later + license_family: LGPL + size: 761857 + timestamp: 1757472971364 +- conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.56-h54a6638_0.conda + sha256: 987ad072939fdd51c92ea8d3544b286bb240aefda329f9b03a51d9b7e777f9de + md5: cdd138897d94dc07d99afe7113a07bec + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libgl >=1.7.0,<2.0a0 + - sdl3 >=3.2.22,<4.0a0 + - libegl >=1.7.0,<2.0a0 + license: Zlib + size: 589145 + timestamp: 1757842881 +- conda: https://prefix.dev/conda-forge/osx-arm64/sdl2-2.32.56-h248ca61_0.conda + sha256: 704c5cae4bc839a18c70cbf3387d7789f1902828c79c6ddabcd34daf594f4103 + md5: 092c5b693dc6adf5f409d12f33295a2a + depends: + - libcxx >=19 + - __osx >=11.0 + - sdl3 >=3.2.22,<4.0a0 + license: Zlib + size: 542508 + timestamp: 1757842919681 +- conda: https://prefix.dev/conda-forge/win-64/sdl2-2.32.56-h5112557_0.conda + sha256: d17da21386bdbf32bce5daba5142916feb95eed63ef92b285808c765705bbfd2 + md5: 4cffbfebb6614a1bff3fc666527c25c7 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - sdl3 >=3.2.22,<4.0a0 + license: Zlib + size: 572101 + timestamp: 1757842925694 +- conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.22-h68140b3_0.conda + sha256: 789ae811b7b93b01c2300461345027fd1a19a7a404e1b8729f58fbe81a82b3bc + md5: ebfddf2601e082193bb550924bbb9744 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - libgcc >=14 + - xorg-libxfixes >=6.0.1,<7.0a0 + - dbus >=1.16.2,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - libudev1 >=257.7 + - libdrm >=2.4.125,<2.5.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + - libxkbcommon >=1.11.0,<2.0a0 + - libusb >=1.0.29,<2.0a0 + - libgl >=1.7.0,<2.0a0 + - pulseaudio-client >=17.0,<17.1.0a0 + - xorg-libxscrnsaver >=1.2.4,<2.0a0 + - libunwind >=1.8.2,<1.9.0a0 + - wayland >=1.24.0,<2.0a0 + - liburing >=2.12,<2.13.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: Zlib + size: 1936633 + timestamp: 1756780211365 +- conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.22-he22eeb8_0.conda + sha256: f4bebfe966e4df667887b06bea6539f2fde23bf3a89649f5b57b53716f1cc2d5 + md5: cd2b01e16daf07b77c3754bfdeb8095d + depends: + - __osx >=11.0 + - libcxx >=19 + - libusb >=1.0.29,<2.0a0 + - dbus >=1.16.2,<2.0a0 + license: Zlib + size: 1416196 + timestamp: 1756780255242 +- conda: https://prefix.dev/conda-forge/win-64/sdl3-3.2.22-h5112557_0.conda + sha256: 01d040f2ebe976a0b9cafc13e8b6fd2cf297afbcdec462a5e254cc8c261f70c5 + md5: ce2d3317d46b92ea361dd9178bc7df91 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libusb >=1.0.29,<2.0a0 + license: Zlib + size: 1521753 + timestamp: 1756780243694 +- conda: . + name: sdl_example + version: 0.1.0 + build: h9352c13_0 + subdir: win-64 + depends: + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + - sdl2 >=2.32.56,<3.0a0 + input: + hash: 21845b1fd51f8827fc89a50b134dc086fba8a8b5f8c9cc5ed3b800c99ea61f57 + globs: [] + package_build_source: + git: https://github.com/prefix-dev/pixi-build-testsuite?subdirectory=tests%2Fdata%2Fpixi_build%2Fcpp-with-path-to-source%2Fproject + rev: 6f94028045df9c753596a3084ce6ca2df4bc25c5 +- conda: . + name: sdl_example + version: 0.1.0 + build: hbf21a9e_0 + subdir: linux-64 + depends: + - libstdcxx >=15 + - libgcc >=15 + - sdl2 >=2.32.56,<3.0a0 + input: + hash: 21845b1fd51f8827fc89a50b134dc086fba8a8b5f8c9cc5ed3b800c99ea61f57 + globs: [] + package_build_source: + git: https://github.com/prefix-dev/pixi-build-testsuite?subdirectory=tests%2Fdata%2Fpixi_build%2Fcpp-with-path-to-source%2Fproject + rev: 6f94028045df9c753596a3084ce6ca2df4bc25c5 +- conda: . + name: sdl_example + version: 0.1.0 + build: hbf21a9e_0 + subdir: osx-arm64 + depends: + - libcxx >=21 + - sdl2 >=2.32.56,<3.0a0 + input: + hash: 21845b1fd51f8827fc89a50b134dc086fba8a8b5f8c9cc5ed3b800c99ea61f57 + globs: [] + package_build_source: + git: https://github.com/prefix-dev/pixi-build-testsuite?subdirectory=tests%2Fdata%2Fpixi_build%2Fcpp-with-path-to-source%2Fproject + rev: 6f94028045df9c753596a3084ce6ca2df4bc25c5 +- conda: https://prefix.dev/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + sha256: 3005729dce6f3d3f5ec91dfc49fc75a0095f9cd23bab49efb899657297ac91a5 + md5: 71b24316859acd00bdb8b38f5e2ce328 + constrains: + - vc14_runtime >=14.29.30037 + - vs2015_runtime >=14.29.30037 + license: LicenseRef-MicrosoftWindowsSDK10 + size: 694692 + timestamp: 1756385147981 +- conda: https://prefix.dev/conda-forge/win-64/vc-14.3-h41ae7f8_31.conda + sha256: cb357591d069a1e6cb74199a8a43a7e3611f72a6caed9faa49dbb3d7a0a98e0b + md5: 28f4ca1e0337d0f27afb8602663c5723 + depends: + - vc14_runtime >=14.44.35208 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + size: 18249 + timestamp: 1753739241465 +- conda: https://prefix.dev/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_31.conda + sha256: af4b4b354b87a9a8d05b8064ff1ea0b47083274f7c30b4eb96bc2312c9b5f08f + md5: 603e41da40a765fd47995faa021da946 + depends: + - ucrt >=10.0.20348.0 + - vcomp14 14.44.35208 h818238b_31 + constrains: + - vs2015_runtime 14.44.35208.* *_31 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + size: 682424 + timestamp: 1753739239305 +- conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.44.35208-h818238b_31.conda + sha256: 67b317b64f47635415776718d25170a9a6f9a1218c0f5a6202bfd687e07b6ea4 + md5: a6b1d5c1fc3cb89f88f7179ee6a9afe3 + depends: + - ucrt >=10.0.20348.0 + constrains: + - vs2015_runtime 14.44.35208.* *_31 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + size: 113963 + timestamp: 1753739198723 +- conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c + md5: 0f2ca7906bf166247d1d760c3422cb8a + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: MIT + license_family: MIT + size: 330474 + timestamp: 1751817998141 +- conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + sha256: a5d4af601f71805ec67403406e147c48d6bad7aaeae92b0622b7e2396842d3fe + md5: 397a013c2dc5145a70737871aaa87e98 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.12,<2.0a0 + license: MIT + license_family: MIT + size: 392406 + timestamp: 1749375847832 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + sha256: 51909270b1a6c5474ed3978628b341b4d4472cd22610e5f22b506855a5e20f67 + md5: db038ce880f100acc74dba10302b5630 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.17.0,<2.0a0 + license: MIT + license_family: MIT + size: 835896 + timestamp: 1741901112627 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + sha256: ed10c9283974d311855ae08a16dfd7e56241fac632aec3b92e3cfe73cff31038 + md5: f6ebe2cb3f82ba6c057dde5d9debe4f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 14780 + timestamp: 1734229004433 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + sha256: 832f538ade441b1eee863c8c91af9e69b356cd3e9e1350fff4fe36cc573fc91a + md5: 2ccd714aa2242315acaf0a67faea780b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + size: 32533 + timestamp: 1730908305254 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + sha256: 6b250f3e59db07c2514057944a3ea2044d6a8cdde8a47b6497c254520fade1ee + md5: 8035c64cb77ed555e3f150b7b3972480 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + size: 19901 + timestamp: 1727794976192 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + sha256: da5dc921c017c05f38a38bd75245017463104457b63a1ce633ed41f214159c14 + md5: febbab7d15033c913d53c7a2c102309d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + size: 50060 + timestamp: 1727752228921 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + sha256: 2fef37e660985794617716eb915865ce157004a4d567ed35ec16514960ae9271 + md5: 4bdb303603e9821baf5fe5fdff1dc8f8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + size: 19575 + timestamp: 1727794961233 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + sha256: 044c7b3153c224c6cedd4484dd91b389d2d7fd9c776ad0f4a34f099b3389f4a1 + md5: 96d57aba173e878a2089d5638016dc5e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + size: 33005 + timestamp: 1734229037766 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxscrnsaver-1.2.4-hb9d3cd8_0.conda + sha256: 58e8fc1687534124832d22e102f098b5401173212ac69eb9fd96b16a3e2c8cb2 + md5: 303f7a0e9e0cd7d250bb6b952cecda90 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: MIT + license_family: MIT + size: 14412 + timestamp: 1727899730073 +- conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + sha256: a4166e3d8ff4e35932510aaff7aa90772f84b4d07e9f6f83c614cba7ceefe0eb + md5: 6432cb5d4ac0046c3ac0a8a0f95842f9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 567578 + timestamp: 1742433379869 diff --git a/examples/pixi-build/cpp-git-source/pixi.toml b/examples/pixi-build/cpp-git-source/pixi.toml new file mode 100644 index 0000000000..5468332679 --- /dev/null +++ b/examples/pixi-build/cpp-git-source/pixi.toml @@ -0,0 +1,28 @@ +[package.build.source] +git = "https://github.com/prefix-dev/pixi-build-testsuite.git" +# branch = "fix/logging_tests" +subdirectory = "tests/data/pixi_build/cpp-with-path-to-source/project" + +[package.build.backend] +channels = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", +] +name = "pixi-build-cmake" +version = "*" + +[package] +name = "sdl_example" +version = "0.1.0" + +[package.host-dependencies] +# This ensures that SDL2 is available at build time. +sdl2 = ">=2.26.5,<3.0" + +[workspace] +channels = ["https://prefix.dev/conda-forge"] +platforms = ["osx-arm64", "linux-64", "win-64"] +preview = ["pixi-build"] + +[dependencies] +sdl_example = { path = "." } diff --git a/schema/model.py b/schema/model.py index 56f6d5450b..d557e968d6 100644 --- a/schema/model.py +++ b/schema/model.py @@ -727,11 +727,11 @@ class SourceLocation(StrictBaseModel): # md5: Md5Sum | None = Field(None, description="The md5 hash of the source") # sha256: Sha256Sum | None = Field(None, description="The sha256 hash of the source") - # git: NonEmptyStr | None = Field(None, description="The git URL to the source repo") - # rev: NonEmptyStr | None = Field(None, description="A git SHA revision to use") - # tag: NonEmptyStr | None = Field(None, description="A git tag to use") - # branch: NonEmptyStr | None = Field(None, description="A git branch to use") - # subdirectory: NonEmptyStr | None = Field(None, description="A subdirectory to use in the repo") + git: NonEmptyStr | None = Field(None, description="The git URL to the source repo") + rev: NonEmptyStr | None = Field(None, description="A git SHA revision to use") + tag: NonEmptyStr | None = Field(None, description="A git tag to use") + branch: NonEmptyStr | None = Field(None, description="A git branch to use") + subdirectory: NonEmptyStr | None = Field(None, description="A subdirectory to use in the repo") class Build(StrictBaseModel): @@ -753,7 +753,14 @@ class Build(StrictBaseModel): source: SourceLocation | None = Field( None, description="The source from which to build the package", - examples=[{"path": "project"}], + examples=[ + {"path": "project"}, + { + "git": "https://github.com/user/repo.git", + "rev": "bd62770509b8afd792e98d20f8b458e2a7f19ec2", + "subdirectory": "subproject/src", + }, + ], ) diff --git a/schema/schema.json b/schema/schema.json index f8183cda88..640ed569d5 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -342,6 +342,11 @@ "examples": [ { "path": "project" + }, + { + "git": "https://github.com/user/repo.git", + "rev": "bd62770509b8afd792e98d20f8b458e2a7f19ec2", + "subdirectory": "subproject/src" } ] }, @@ -1702,11 +1707,41 @@ "type": "object", "additionalProperties": false, "properties": { + "branch": { + "title": "Branch", + "description": "A git branch to use", + "type": "string", + "minLength": 1 + }, + "git": { + "title": "Git", + "description": "The git URL to the source repo", + "type": "string", + "minLength": 1 + }, "path": { "title": "Path", "description": "The path to the source", "type": "string", "minLength": 1 + }, + "rev": { + "title": "Rev", + "description": "A git SHA revision to use", + "type": "string", + "minLength": 1 + }, + "subdirectory": { + "title": "Subdirectory", + "description": "A subdirectory to use in the repo", + "type": "string", + "minLength": 1 + }, + "tag": { + "title": "Tag", + "description": "A git tag to use", + "type": "string", + "minLength": 1 } } }, diff --git a/tests/integration_python/test_main_cli.py b/tests/integration_python/test_main_cli.py index f24babb173..07ce9829fe 100644 --- a/tests/integration_python/test_main_cli.py +++ b/tests/integration_python/test_main_cli.py @@ -3,6 +3,7 @@ import shutil import sys import tomllib +import tomli_w from pathlib import Path import pytest @@ -1191,6 +1192,55 @@ def test_frozen_no_install_invariant(pixi: Path, tmp_pixi_workspace: Path) -> No # Add bzip2 package to keep installation time low verify_cli_command([pixi, "add", "--manifest-path", manifest_path, "bzip2"]) + recipe_path = tmp_pixi_workspace / "recipe.yaml" + recipe_path.write_text( + """recipe: + name: frozen_no_install_build + version: "0.1.0" + +outputs: + - package: + name: frozen_no_install_build + build: + script: + - if: win + then: + - mkdir -p %PREFIX%\\bin + - echo @echo off > %PREFIX%\\bin\\frozen_no_install_build.bat + - echo echo Hello from frozen_no_install_build >> %PREFIX%\\bin\\frozen_no_install_build.bat + else: + - mkdir -p $PREFIX/bin + - echo "#!/usr/bin/env bash" > $PREFIX/bin/frozen_no_install_build + - echo "echo Hello from frozen_no_install_build" >> $PREFIX/bin/frozen_no_install_build + - chmod +x $PREFIX/bin/frozen_no_install_build +""" + ) + + manifest_data = tomllib.loads(manifest_path.read_text()) + workspace_table = manifest_data.setdefault("workspace", {}) + preview_list = workspace_table.setdefault("preview", []) + if "pixi-build" not in preview_list: + preview_list.append("pixi-build") + + dependencies = manifest_data.setdefault("dependencies", {}) + dependencies.pop("frozen_no_install_build", None) + + package_table = manifest_data.setdefault("package", {}) + package_table["name"] = "frozen_no_install_build" + package_table["version"] = "0.1.0" + build_table = package_table.setdefault("build", {}) + backend_table = build_table.setdefault("backend", {}) + backend_table["name"] = "pixi-build-rattler-build" + backend_table["version"] = "*" + backend_table["channels"] = [ + "https://prefix.dev/pixi-build-backends", + "https://prefix.dev/conda-forge", + ] + + manifest_path.write_text(tomli_w.dumps(manifest_data)) + + verify_cli_command([pixi, "lock", "--manifest-path", manifest_path]) + # Create a simple environment.yml file for import testing simple_env_yml = tmp_pixi_workspace / "simple_env.yml" simple_env_yml.write_text("""name: simple-env @@ -1250,6 +1300,8 @@ def check_invariants(command_name: str) -> None: ), # Upgrade commands (["upgrade"], [], "pixi upgrade"), + # Pixi build (can lock its source) + (["build"], [], "pixi build"), ] # This command needs to stay last so we always have something that requires a re-solve # Dont move this! From 964da164f6c922f9fd52c9f81d59b14f7318e38e Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Thu, 23 Oct 2025 15:41:59 +0300 Subject: [PATCH 03/10] Fix rebase --- Cargo.lock | 98 ++++++++----------- Cargo.toml | 25 ++++- crates/pixi_build_discovery/src/discovery.rs | 2 +- .../src/build_backend_metadata/mod.rs | 6 +- .../src/source_build/mod.rs | 14 +-- 5 files changed, 76 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d3d251ec1..8c50e03434 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,7 +1017,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e9d642a7e3a318e37c2c9427b5a6a48aa1ad55dcd986f3034ab2239045a645" dependencies = [ - "darling", + "darling 0.21.3", "ident_case", "prettyplease", "proc-macro2", @@ -1317,7 +1317,6 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "coalesced_map" version = "0.1.2" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "dashmap", "tokio", @@ -1611,8 +1610,22 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", ] [[package]] @@ -1629,13 +1642,24 @@ dependencies = [ "syn", ] +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn", +] + [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core", + "darling_core 0.21.3", "quote", "syn", ] @@ -2100,7 +2124,6 @@ dependencies = [ [[package]] name = "file_url" version = "0.2.6" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "itertools 0.14.0", "percent-encoding", @@ -2947,7 +2970,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2 0.5.10", "system-configuration", "tokio", "tower-service", @@ -4206,7 +4229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.45.0", ] [[package]] @@ -4300,7 +4323,6 @@ checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" [[package]] name = "path_resolver" version = "0.2.1" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "fs-err", "fxhash", @@ -4497,7 +4519,6 @@ dependencies = [ "reqwest", "reqwest-middleware", "rstest", - "serde_derive", "serde_json", "temp-env", "tempfile", @@ -5801,7 +5822,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.1", + "socket2 0.5.10", "thiserror 2.0.17", "tokio", "tracing", @@ -5838,7 +5859,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.5.10", "tracing", "windows-sys 0.60.2", ] @@ -5950,8 +5971,6 @@ dependencies = [ [[package]] name = "rattler" version = "0.38.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8abb6e11a8e0377010bca2f761102bbd9a944cf8a589c4e5726459499f0c48" dependencies = [ "anyhow", "clap", @@ -5995,8 +6014,6 @@ dependencies = [ [[package]] name = "rattler_cache" version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9eea243b0d877fe0bbb9a421fb9d8cace8039cfdfbda3d7c0384ff5818d382" dependencies = [ "anyhow", "dashmap", @@ -6028,8 +6045,6 @@ dependencies = [ [[package]] name = "rattler_conda_types" version = "0.40.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa6244d54b84269d3121d463db4e154c5664936e98817ef44e4fba1f575c3a" dependencies = [ "chrono", "core-foundation 0.10.1", @@ -6070,8 +6085,6 @@ dependencies = [ [[package]] name = "rattler_digest" version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886e9a6254e74a830c2b8555e14862d6b2f4cc498b43767d4adf1c71421a4796" dependencies = [ "blake2", "digest", @@ -6089,8 +6102,6 @@ dependencies = [ [[package]] name = "rattler_lock" version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0ba96eefd8186a3bd0a603b4b00bb7faa2d6488ea38eae0da198647fe4712" dependencies = [ "chrono", "file_url", @@ -6115,7 +6126,6 @@ dependencies = [ [[package]] name = "rattler_macros" version = "1.0.11" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "quote", "syn", @@ -6124,8 +6134,6 @@ dependencies = [ [[package]] name = "rattler_menuinst" version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2685a4f23eca7d46249d6775e534a7ff4adffc53af6e702eafe6168282ae0eeb" dependencies = [ "chrono", "configparser", @@ -6154,8 +6162,6 @@ dependencies = [ [[package]] name = "rattler_networking" version = "0.25.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de790ad7985f3ee85bae3175b203af2152c1c86d9efe1249ac8ff1863466d2e6" dependencies = [ "anyhow", "async-once-cell", @@ -6186,8 +6192,6 @@ dependencies = [ [[package]] name = "rattler_package_streaming" version = "0.23.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3dfb861d216425ddb768857b7d50bf548c2b1fe9421caa7071ca655b0423af" dependencies = [ "bzip2 0.6.1", "chrono", @@ -6209,15 +6213,13 @@ dependencies = [ "tokio-util", "tracing", "url", - "zip 4.0.0", + "zip 6.0.0", "zstd", ] [[package]] name = "rattler_pty" version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86a84e6b351c46c7588bb8f5c90994be23d5c3c31cf87f9ec903cd91d9fc4246" dependencies = [ "libc", "nix 0.30.1", @@ -6228,7 +6230,6 @@ dependencies = [ [[package]] name = "rattler_redaction" version = "0.1.12" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "reqwest", "reqwest-middleware", @@ -6238,8 +6239,6 @@ dependencies = [ [[package]] name = "rattler_repodata_gateway" version = "0.24.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b063b5db3804ea80d0cf991c69d27fd3b1f3be6f8ce4601731ec2583825bb73a" dependencies = [ "anyhow", "async-compression", @@ -6298,8 +6297,6 @@ dependencies = [ [[package]] name = "rattler_shell" version = "0.25.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3c4475de6e4e22fde5a29e0957622c1665231bc00f1a32be0b8404b412e66c" dependencies = [ "anyhow", "enum_dispatch", @@ -6319,8 +6316,6 @@ dependencies = [ [[package]] name = "rattler_solve" version = "3.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071ca80c7cf13b742f7b08c6199f441cb613db9acc92d5625efc1e4ce84e546d" dependencies = [ "chrono", "futures", @@ -6337,8 +6332,6 @@ dependencies = [ [[package]] name = "rattler_virtual_packages" version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f31e64364d38962c914d91ea00e1d735884dcad285da0082820ea18af611454" dependencies = [ "archspec", "libloading", @@ -7201,9 +7194,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ "base64 0.22.1", "chrono", @@ -7212,7 +7205,8 @@ dependencies = [ "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", - "serde_core", + "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -7220,11 +7214,11 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.15.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", "syn", @@ -7389,7 +7383,6 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_spawn_blocking" version = "1.1.0" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" dependencies = [ "tokio", ] @@ -10568,9 +10561,9 @@ dependencies = [ [[package]] name = "zip" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" dependencies = [ "arbitrary", "crc32fast", @@ -10663,8 +10656,3 @@ dependencies = [ "quote", "syn", ] - -[[patch.unused]] -name = "rattler_virtual_packages" -version = "2.2.0" -source = "git+https://github.com/remimimimimi/rattler?branch=feat%2Flock%2Fpackage_build_source%2Fpath#e9d77c11c0a79c62185351d76848aecaf0abcc5f" diff --git a/Cargo.toml b/Cargo.toml index 75d52897be..4c775ff65c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ clap = { version = "4.5.31", default-features = false } clap_complete = "4.5.46" clap_complete_nushell = "4.5.5" # Rattler crates -coalesced_map = "0.1.1" +coalesced_map = "0.1.2" concat-idents = "1.1.5" console = "0.15.10" console-subscriber = "0.4.1" @@ -122,12 +122,12 @@ rattler_conda_types = { version = "0.40.3", default-features = false, features = ] } rattler_digest = { version = "1.1.7", default-features = false } rattler_lock = { version = "0.25.3", default-features = false } -rattler_menuinst = { version = "0.2.23", default-features = false } +rattler_menuinst = { version = "0.2.29", default-features = false } rattler_networking = { version = "0.25.20", default-features = false, features = [ "dirs", "google-cloud-auth", ] } -rattler_package_streaming = { version = "0.23.11", default-features = false } +rattler_package_streaming = { version = "0.23.8", default-features = false } rattler_repodata_gateway = { version = "0.24.12", default-features = false } rattler_shell = { version = "0.25.5", default-features = false } rattler_solve = { version = "3.0.8", default-features = false } @@ -144,6 +144,7 @@ self-replace = "1.5.0" serde = "1.0.218" serde-untagged = "0.1.6" serde-value = "0.7.0" +serde_derive = "*" serde_ignored = "0.1.10" serde_json = "1.0.139" serde_with = "=3.14.0" @@ -212,6 +213,24 @@ reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" } version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "06ec5a5f59ffaeb6cf5079c6cb184467da06c9db" } +# pixi-rattler-patches - START +# pixi-rattler-original-versions: {"coalesced_map": "0.1.1", "file_url": "0.2.6", "rattler": "0.38.2", "rattler_cache": "0.3.41", "rattler_conda_types": "0.40.3", "rattler_digest": "1.1.7", "rattler_lock": "0.25.3", "rattler_menuinst": "0.2.23", "rattler_networking": "0.25.20", "rattler_package_streaming": "0.23.11", "rattler_repodata_gateway": "0.24.12", "rattler_shell": "0.25.5", "rattler_solve": "3.0.8", "rattler_virtual_packages": "2.2.4", "simple_spawn_blocking": "1.1.0"} +coalesced_map = { path = "../../rattler/main//crates/coalesced_map" } +file_url = { path = "../../rattler/main//crates/file_url" } +rattler = { path = "../../rattler/main//crates/rattler" } +rattler_cache = { path = "../../rattler/main//crates/rattler_cache" } +rattler_conda_types = { path = "../../rattler/main//crates/rattler_conda_types" } +rattler_digest = { path = "../../rattler/main//crates/rattler_digest" } +rattler_lock = { path = "../../rattler/main//crates/rattler_lock" } +rattler_menuinst = { path = "../../rattler/main//crates/rattler_menuinst" } +rattler_networking = { path = "../../rattler/main//crates/rattler_networking" } +rattler_package_streaming = { path = "../../rattler/main//crates/rattler_package_streaming" } +rattler_repodata_gateway = { path = "../../rattler/main//crates/rattler_repodata_gateway" } +rattler_shell = { path = "../../rattler/main//crates/rattler_shell" } +rattler_solve = { path = "../../rattler/main//crates/rattler_solve" } +rattler_virtual_packages = { path = "../../rattler/main//crates/rattler_virtual_packages" } +simple_spawn_blocking = { path = "../../rattler/main//crates/simple_spawn_blocking" } +# pixi-rattler-patches - END [profile.ci] codegen-units = 16 inherits = "release" diff --git a/crates/pixi_build_discovery/src/discovery.rs b/crates/pixi_build_discovery/src/discovery.rs index 946f7cf1fa..fbf205e1de 100644 --- a/crates/pixi_build_discovery/src/discovery.rs +++ b/crates/pixi_build_discovery/src/discovery.rs @@ -374,7 +374,7 @@ impl DiscoveredBackend { backend_spec: BackendSpec::JsonRpc(JsonRpcBackendSpec::default_ros_build(channels)), init_params: BackendInitializationParams { workspace_root: source_dir.clone(), - source: None, + build_source: None, source_anchor: source_dir, manifest_path: package_xml_absolute_path, project_model: Some(ProjectModelV1::default()), diff --git a/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs b/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs index 92771660db..03aeb1ca38 100644 --- a/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs +++ b/crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs @@ -185,7 +185,7 @@ impl BuildBackendMetadataSpec { metadata, cache_entry, manifest_source: manifest_source_checkout.pinned, - package_build_source, + build_source, }); } } else { @@ -212,7 +212,7 @@ impl BuildBackendMetadataSpec { .map_err_with(BuildBackendMetadataError::Initialize)?; // Call the conda_outputs method to get metadata. - let source = source_checkout.pinned.clone(); + let manifest_source = manifest_source_checkout.pinned.clone(); if !backend.capabilities().provides_conda_outputs() { return Err(CommandDispatcherError::Failed( BuildBackendMetadataError::BackendMissingCapabilities( @@ -228,7 +228,7 @@ impl BuildBackendMetadataSpec { let metadata = self .call_conda_outputs( command_dispatcher, - source_checkout, + build_source_checkout, backend, additional_glob_hash, ) diff --git a/crates/pixi_command_dispatcher/src/source_build/mod.rs b/crates/pixi_command_dispatcher/src/source_build/mod.rs index 27a622c92a..e499ac8b07 100644 --- a/crates/pixi_command_dispatcher/src/source_build/mod.rs +++ b/crates/pixi_command_dispatcher/src/source_build/mod.rs @@ -161,7 +161,7 @@ impl SourceBuildSpec { if !self.force { // If the build is up to date, we can return the cached build. tracing::debug!( - source = %self.source, + source = %self.manifest_source, package = ?cached_build.record.package_record.name, build = %cached_build.record.package_record.build, output = %cached_build.record.file_name, @@ -183,7 +183,7 @@ impl SourceBuildSpec { self.package.name.as_normalized() ); tracing::debug!( - source = %self.source, + source = %self.manifest_source, package = ?cached_build.record.package_record.name, build = %cached_build.record.package_record.build, output = %cached_build.record.file_name, @@ -199,7 +199,7 @@ impl SourceBuildSpec { match &*build_cache.cached_build.lock().await { CachedBuildStatus::Stale(existing) => { tracing::debug!( - source = %self.source, + source = %self.manifest_source, package = ?existing.record.package_record.name, build = %existing.record.package_record.build, "rebuilding stale source build", @@ -207,7 +207,7 @@ impl SourceBuildSpec { } CachedBuildStatus::Missing => { tracing::debug!( - source = %self.source, + source = %self.manifest_source, "no cached source build; starting fresh build", ); } @@ -304,7 +304,7 @@ impl SourceBuildSpec { ), }; tracing::debug!( - source = %self.source, + source = %self.manifest_source, work_directory = %work_directory.display(), backend = backend.identifier(), "using work directory for source build", @@ -320,7 +320,7 @@ impl SourceBuildSpec { } // Build the package using the v1 build method. - let source_for_logging = self.source.clone(); + let source_for_logging = self.manifest_source.clone(); let mut built_source = self .build_v1( command_dispatcher, @@ -413,7 +413,7 @@ impl SourceBuildSpec { // so on the next run we can distinguish between up to date ( was already saved from previous session) // and new that was just build now let cached_build = CachedBuild { - source: source_checkout + source: manifest_source_checkout .pinned .is_mutable() .then_some(built_source.metadata.clone()), From 354089baba14d0ac06ec888ab9627e54d5931dbd Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Mon, 27 Oct 2025 17:45:49 +0200 Subject: [PATCH 04/10] Fix path handling --- crates/pixi_cli/src/build.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/crates/pixi_cli/src/build.rs b/crates/pixi_cli/src/build.rs index 18d6bc5491..fd647e3ce8 100644 --- a/crates/pixi_cli/src/build.rs +++ b/crates/pixi_cli/src/build.rs @@ -116,31 +116,30 @@ pub async fn execute(args: Args) -> miette::Result<()> { manifest_path.display() ) })?; - // Store the manifest location relative to the workspace root when possible to + // Determine the directory that contains the manifest. + let manifest_dir_canonical = if manifest_path_canonical.is_file() { + manifest_path_canonical.parent().ok_or_else(|| { + miette::miette!( + "explicit manifest path: {} doesn't have a parent", + manifest_path.display() + ) + })? + } else { + manifest_path_canonical.as_path() + }; + + // Store the manifest directory relative to the workspace root when possible to // keep the pinned path relocatable and avoid double-prefixing during resolution. - let manifest_spec_path = pathdiff::diff_paths(&manifest_path_canonical, workspace.root()) - .unwrap_or(manifest_path_canonical.clone()); + let manifest_dir_spec = pathdiff::diff_paths(manifest_dir_canonical, workspace.root()) + .unwrap_or_else(|| manifest_dir_canonical.to_path_buf()); let channel_config = workspace.channel_config(); let channels = workspace .default_environment() .channel_urls(&channel_config) .into_diagnostic()?; - // Determine the source of the package. - let manifest_path_dir = if manifest_spec_path.is_file() { - if let Some(parent) = manifest_spec_path.parent() { - parent - } else { - miette::bail!( - "explicit manifest path: {} doesn't have a parent", - manifest_spec_path.display() - ); - } - } else { - manifest_spec_path.as_ref() - }; let manifest_source: PinnedSourceSpec = PinnedPathSpec { - path: manifest_path_dir.to_string_lossy().into_owned().into(), + path: manifest_dir_spec.to_string_lossy().into_owned().into(), } .into(); From 1129aaf9a0009bc9cf8da3f1ff62a6cc1a4fac15 Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Mon, 27 Oct 2025 17:51:24 +0200 Subject: [PATCH 05/10] Fix clippy --- crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs | 1 + .../src/solve_pixi/source_metadata_collector.rs | 1 + .../pixi_command_dispatcher/tests/integration/event_reporter.rs | 1 + crates/pixi_core/src/lock_file/update.rs | 2 +- crates/pixi_record/src/lib.rs | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs b/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs index cf10de7f3f..5523a8196b 100644 --- a/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs +++ b/crates/pixi_command_dispatcher/src/command_dispatcher/mod.rs @@ -223,6 +223,7 @@ pub(crate) struct SourceBuildCacheStatusId(pub usize); pub(crate) struct InstantiatedToolEnvId(pub usize); /// A message send to the dispatch task. +#[allow(clippy::large_enum_variant)] #[derive(derive_more::From)] pub(crate) enum ForegroundMessage { SolveCondaEnvironment(SolveCondaEnvironmentTask), diff --git a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs index c4e6b95efc..b9bd754651 100644 --- a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs +++ b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs @@ -69,6 +69,7 @@ pub enum CollectSourceMetadataError { } impl SourceMetadataCollector { + #[allow(clippy::too_many_arguments)] pub fn new( command_queue: CommandDispatcher, channel_urls: Vec, diff --git a/crates/pixi_command_dispatcher/tests/integration/event_reporter.rs b/crates/pixi_command_dispatcher/tests/integration/event_reporter.rs index 8fb6cf855e..13a509c03a 100644 --- a/crates/pixi_command_dispatcher/tests/integration/event_reporter.rs +++ b/crates/pixi_command_dispatcher/tests/integration/event_reporter.rs @@ -19,6 +19,7 @@ use pixi_command_dispatcher::{ use pixi_git::resolver::RepositoryReference; use serde::Serialize; +#[allow(clippy::large_enum_variant)] #[derive(Debug, Serialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum Event { diff --git a/crates/pixi_core/src/lock_file/update.rs b/crates/pixi_core/src/lock_file/update.rs index dfbe5ddb30..8451027361 100644 --- a/crates/pixi_core/src/lock_file/update.rs +++ b/crates/pixi_core/src/lock_file/update.rs @@ -30,7 +30,7 @@ use pixi_install_pypi::{ }; use pixi_manifest::{ChannelPriority, EnvironmentName, FeaturesExt}; use pixi_progress::global_multi_progress; -use pixi_record::{ParseLockFileError, PinnedSourceSpec, PixiRecord, SourceRecord}; +use pixi_record::{ParseLockFileError, PixiRecord}; use pixi_utils::{prefix::Prefix, variants::VariantConfig}; use pixi_uv_context::UvResolutionContext; use pixi_uv_conversions::{ diff --git a/crates/pixi_record/src/lib.rs b/crates/pixi_record/src/lib.rs index 48e4d7917b..7992cc29ea 100644 --- a/crates/pixi_record/src/lib.rs +++ b/crates/pixi_record/src/lib.rs @@ -17,6 +17,7 @@ use thiserror::Error; /// binary file or something that still requires building. /// /// This is basically a superset of a regular [`RepoDataRecord`]. +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Serialize)] #[serde(untagged)] pub enum PixiRecord { From c0f74291f48246b64e5e8f8ea173cfb814e3a2aa Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Thu, 30 Oct 2025 11:53:43 +0200 Subject: [PATCH 06/10] Remove reference to local rattler --- Cargo.toml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ac451654ab..35ec37edc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -216,24 +216,6 @@ reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "7650ed76215a962a96d94a79be71c27bffde7ab2" } version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "d8efd77673c9a90792da9da31b6c0da7ea8a324b" } -# pixi-rattler-patches - START -# pixi-rattler-original-versions: {"coalesced_map": "0.1.1", "file_url": "0.2.6", "rattler": "0.38.2", "rattler_cache": "0.3.41", "rattler_conda_types": "0.40.3", "rattler_digest": "1.1.7", "rattler_lock": "0.25.3", "rattler_menuinst": "0.2.23", "rattler_networking": "0.25.20", "rattler_package_streaming": "0.23.11", "rattler_repodata_gateway": "0.24.12", "rattler_shell": "0.25.5", "rattler_solve": "3.0.8", "rattler_virtual_packages": "2.2.4", "simple_spawn_blocking": "1.1.0"} -coalesced_map = { path = "../../rattler/main//crates/coalesced_map" } -file_url = { path = "../../rattler/main//crates/file_url" } -rattler = { path = "../../rattler/main//crates/rattler" } -rattler_cache = { path = "../../rattler/main//crates/rattler_cache" } -rattler_conda_types = { path = "../../rattler/main//crates/rattler_conda_types" } -rattler_digest = { path = "../../rattler/main//crates/rattler_digest" } -rattler_lock = { path = "../../rattler/main//crates/rattler_lock" } -rattler_menuinst = { path = "../../rattler/main//crates/rattler_menuinst" } -rattler_networking = { path = "../../rattler/main//crates/rattler_networking" } -rattler_package_streaming = { path = "../../rattler/main//crates/rattler_package_streaming" } -rattler_repodata_gateway = { path = "../../rattler/main//crates/rattler_repodata_gateway" } -rattler_shell = { path = "../../rattler/main//crates/rattler_shell" } -rattler_solve = { path = "../../rattler/main//crates/rattler_solve" } -rattler_virtual_packages = { path = "../../rattler/main//crates/rattler_virtual_packages" } -simple_spawn_blocking = { path = "../../rattler/main//crates/simple_spawn_blocking" } -# pixi-rattler-patches - END [profile.ci] codegen-units = 16 inherits = "release" From edb006518cc731f4c7cad34e803e02be095f14ac Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Thu, 30 Oct 2025 11:54:58 +0200 Subject: [PATCH 07/10] Update Cargo.lock --- Cargo.lock | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19af830d8d..b717df9bff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1317,6 +1317,8 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "coalesced_map" version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cf5a7a58a9d5b914bddb0a3a2bd920af2be897114dc8128af022af81fc43b8b" dependencies = [ "dashmap", "tokio", @@ -2160,6 +2162,8 @@ dependencies = [ [[package]] name = "file_url" version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765662dc0b26e038099a5a1529f5d48443111eea45377c312be892997651710e" dependencies = [ "itertools 0.14.0", "percent-encoding", @@ -3002,7 +3006,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -3022,7 +3026,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.59.0", + "windows-core 0.62.2", ] [[package]] @@ -4275,7 +4279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.61.2", ] [[package]] @@ -5718,7 +5722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.14.0", "proc-macro2", "quote", "syn", @@ -5875,7 +5879,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.1", "thiserror 2.0.17", "tokio", "tracing", @@ -5912,7 +5916,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.1", "tracing", "windows-sys 0.60.2", ] @@ -6144,6 +6148,8 @@ dependencies = [ [[package]] name = "rattler_digest" version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886e9a6254e74a830c2b8555e14862d6b2f4cc498b43767d4adf1c71421a4796" dependencies = [ "blake2", "digest", @@ -6187,6 +6193,8 @@ dependencies = [ [[package]] name = "rattler_macros" version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "988d5d7ace4fb1d7549008236cf08de95e8ea2f1f80754109324a08c31e6dc6a" dependencies = [ "quote", "syn", @@ -6287,6 +6295,8 @@ dependencies = [ [[package]] name = "rattler_pty" version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a84e6b351c46c7588bb8f5c90994be23d5c3c31cf87f9ec903cd91d9fc4246" dependencies = [ "libc", "nix 0.30.1", @@ -6297,6 +6307,8 @@ dependencies = [ [[package]] name = "rattler_redaction" version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa5057629aeb20861919e9ae56875985d58028f3c6f433a20b5ded086e1cec5" dependencies = [ "reqwest", "reqwest-middleware", @@ -7582,6 +7594,8 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_spawn_blocking" version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55c0b0b683828aa9d4f5c0e59b0c856a12c30a65b5f1ca4292664734d76fa9c2" dependencies = [ "tokio", ] @@ -7848,7 +7862,7 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows 0.59.0", + "windows 0.61.3", ] [[package]] From bd3a4270cf61a28b1738b8644eed237d4780b8d1 Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Thu, 30 Oct 2025 12:01:39 +0200 Subject: [PATCH 08/10] Fix cargo machete --- Cargo.lock | 2 -- crates/pixi_command_dispatcher/Cargo.toml | 4 +++- crates/pixi_global/Cargo.toml | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b717df9bff..123a855199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4843,7 +4843,6 @@ dependencies = [ "rattler", "rattler_conda_types", "rattler_digest", - "rattler_lock", "rattler_networking", "rattler_package_streaming", "rattler_repodata_gateway", @@ -5126,7 +5125,6 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with", "tempfile", "thiserror 2.0.17", "tokio", diff --git a/crates/pixi_command_dispatcher/Cargo.toml b/crates/pixi_command_dispatcher/Cargo.toml index c919d11632..8160eb2e95 100644 --- a/crates/pixi_command_dispatcher/Cargo.toml +++ b/crates/pixi_command_dispatcher/Cargo.toml @@ -41,7 +41,6 @@ xxhash-rust = { workspace = true, features = ["xxh3"] } rattler = { workspace = true } rattler_conda_types = { workspace = true } rattler_digest = { workspace = true } -rattler_lock = { workspace = true } rattler_networking = { workspace = true } rattler_package_streaming = { workspace = true } rattler_repodata_gateway = { workspace = true } @@ -75,3 +74,6 @@ tokio = { workspace = true, features = ["macros"] } [features] slow_integration_tests = [] + +[package.metadata.cargo-machete] +ignored = ["serde_with"] diff --git a/crates/pixi_global/Cargo.toml b/crates/pixi_global/Cargo.toml index 9c50a9be46..ea691d7874 100644 --- a/crates/pixi_global/Cargo.toml +++ b/crates/pixi_global/Cargo.toml @@ -48,7 +48,6 @@ rstest = { workspace = true } serde = { workspace = true } serde_derive = { workspace = true } serde_json = { workspace = true } -serde_with = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } From 70ed7ec7e841b2047c82220a9c6606b98d08ba9f Mon Sep 17 00:00:00 2001 From: remimimimimi Date: Thu, 30 Oct 2025 12:20:52 +0200 Subject: [PATCH 09/10] bump snapshot --- .../tests/snapshots/discovery__direct_package_xml.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pixi_build_discovery/tests/snapshots/discovery__direct_package_xml.snap b/crates/pixi_build_discovery/tests/snapshots/discovery__direct_package_xml.snap index a1471f9f8b..85a2ed2b32 100644 --- a/crates/pixi_build_discovery/tests/snapshots/discovery__direct_package_xml.snap +++ b/crates/pixi_build_discovery/tests/snapshots/discovery__direct_package_xml.snap @@ -14,7 +14,7 @@ backend-spec: - "https://prefix.dev/conda-forge" init-params: workspace-root: "file:///ros-package" - source: ~ + build-source: ~ source-anchor: "file:///ros-package" manifest-path: "file:///ros-package/package.xml" project-model: From 172072443b94039ec83ce757ab262bf4d571a0d6 Mon Sep 17 00:00:00 2001 From: Tim de Jager Date: Thu, 30 Oct 2025 10:27:38 +0100 Subject: [PATCH 10/10] fix: rename source fields, so that they make more sense feat: more renaming --- .../src/build/conversion.rs | 7 +++-- .../src/install_pixi/mod.rs | 4 +-- .../src/solve_conda/mod.rs | 4 +-- .../solve_pixi/source_metadata_collector.rs | 4 +-- .../src/source_build/mod.rs | 2 +- .../src/source_metadata/mod.rs | 28 +++++++++++-------- .../src/lock_file/satisfiability/mod.rs | 25 +++++------------ crates/pixi_core/src/lock_file/update.rs | 2 +- crates/pixi_record/src/source_record.rs | 20 +++++++------ 9 files changed, 46 insertions(+), 50 deletions(-) diff --git a/crates/pixi_command_dispatcher/src/build/conversion.rs b/crates/pixi_command_dispatcher/src/build/conversion.rs index 58c97ef20f..bea7b35a49 100644 --- a/crates/pixi_command_dispatcher/src/build/conversion.rs +++ b/crates/pixi_command_dispatcher/src/build/conversion.rs @@ -98,7 +98,8 @@ pub fn from_package_spec_v1(source: PackageSpecV1) -> pixi_spec::PixiSpec { } pub(crate) fn package_metadata_to_source_records( - source: &PinnedSourceSpec, + manifest_source: &PinnedSourceSpec, + build_source: Option<&PinnedSourceSpec>, packages: &[CondaPackageMetadata], package: &PackageName, input_hash: &Option, @@ -111,8 +112,8 @@ pub(crate) fn package_metadata_to_source_records( .map(|p| { SourceRecord { input_hash: input_hash.clone(), - source: source.clone(), - pinned_source_spec: None, + manifest_source: manifest_source.clone(), + build_source: build_source.cloned(), sources: p .sources .iter() diff --git a/crates/pixi_command_dispatcher/src/install_pixi/mod.rs b/crates/pixi_command_dispatcher/src/install_pixi/mod.rs index cd04f5cb07..98b6b1de63 100644 --- a/crates/pixi_command_dispatcher/src/install_pixi/mod.rs +++ b/crates/pixi_command_dispatcher/src/install_pixi/mod.rs @@ -215,7 +215,7 @@ impl InstallPixiEnvironmentSpec { .contains(&source_record.package_record.name); let built_source = command_dispatcher .source_build(SourceBuildSpec { - manifest_source: source_record.source.clone(), + manifest_source: source_record.manifest_source.clone(), package: source_record.into(), channel_config: self.channel_config.clone(), channels: self.channels.clone(), @@ -249,7 +249,7 @@ pub enum InstallPixiEnvironmentError { #[error("failed to build '{}' from '{}'", .0.package_record.name.as_source(), - .0.source)] + .0.manifest_source)] BuildSourceError( Box, #[diagnostic_source] diff --git a/crates/pixi_command_dispatcher/src/solve_conda/mod.rs b/crates/pixi_command_dispatcher/src/solve_conda/mod.rs index 08adc6ce6c..3617937f42 100644 --- a/crates/pixi_command_dispatcher/src/solve_conda/mod.rs +++ b/crates/pixi_command_dispatcher/src/solve_conda/mod.rs @@ -156,7 +156,7 @@ impl SolveCondaEnvironmentSpec { channel: None, }; let mut record = record.clone(); - record.pinned_source_spec = source_metadata.pinned_build_source.clone(); + record.build_source = source_metadata.build_source.clone(); url_to_source_package.insert(url, (record, repodata_record)); } } @@ -225,7 +225,7 @@ impl SolveCondaEnvironmentSpec { /// Generates a unique URL for a source record. fn unique_url(source: &SourceRecord) -> Url { - let mut url = source.source.identifiable_url(); + let mut url = source.manifest_source.identifiable_url(); // Add unique identifiers to the URL. url.query_pairs_mut() diff --git a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs index b9bd754651..d4d4faf33d 100644 --- a/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs +++ b/crates/pixi_command_dispatcher/src/solve_pixi/source_metadata_collector.rs @@ -127,7 +127,7 @@ impl SourceMetadataCollector { // Process transitive dependencies for record in &source_metadata.records { chain.push(record.package_record.name.clone()); - let anchor = SourceAnchor::from(SourceSpec::from(record.source.clone())); + let anchor = SourceAnchor::from(SourceSpec::from(record.manifest_source.clone())); for depend in &record.package_record.depends { if let Ok(spec) = MatchSpec::from_str(depend, ParseStrictness::Lenient) { if let Some((name, source_spec)) = spec.name.as_ref().and_then(|name| { @@ -230,7 +230,7 @@ impl SourceMetadataCollector { source_metadata.skipped_packages.clone(), ), name, - pinned_source: Box::new(source_metadata.source.clone()), + pinned_source: Box::new(source_metadata.manifest_source.clone()), }, )); } diff --git a/crates/pixi_command_dispatcher/src/source_build/mod.rs b/crates/pixi_command_dispatcher/src/source_build/mod.rs index b1947d98b6..7914bf8f3f 100644 --- a/crates/pixi_command_dispatcher/src/source_build/mod.rs +++ b/crates/pixi_command_dispatcher/src/source_build/mod.rs @@ -463,7 +463,7 @@ impl SourceBuildSpec { .expect("the source record should be present in the result sources"); BuildHostPackage { repodata_record, - source: Some(source.source), + source: Some(source.manifest_source), } } }) diff --git a/crates/pixi_command_dispatcher/src/source_metadata/mod.rs b/crates/pixi_command_dispatcher/src/source_metadata/mod.rs index 9d377d6c7f..cc6d01cfe0 100644 --- a/crates/pixi_command_dispatcher/src/source_metadata/mod.rs +++ b/crates/pixi_command_dispatcher/src/source_metadata/mod.rs @@ -46,9 +46,11 @@ pub struct SourceMetadataSpec { pub struct SourceMetadata { /// Information about the source checkout that was used to build the /// package. - pub source: PinnedSourceSpec, + pub manifest_source: PinnedSourceSpec, - pub pinned_build_source: Option, + /// The optional location of where the actual source code is located, + /// this is used mainly for out-of-tree builds + pub build_source: Option, /// All the source records for this particular package. pub records: Vec, @@ -85,17 +87,18 @@ impl SourceMetadataSpec { // Convert the metadata to source records. let records = conversion::package_metadata_to_source_records( &build_backend_metadata.manifest_source, + build_backend_metadata.build_source.as_ref(), packages, &self.package, &build_backend_metadata.metadata.input_hash, ); Ok(SourceMetadata { - source: build_backend_metadata.manifest_source.clone(), + manifest_source: build_backend_metadata.manifest_source.clone(), records, // As the GetMetadata kind returns all records at once and we don't solve them we can skip this. skipped_packages: Default::default(), - pinned_build_source: None, + build_source: build_backend_metadata.build_source.clone(), }) } MetadataKind::Outputs { outputs } => { @@ -111,15 +114,16 @@ impl SourceMetadataSpec { output, build_backend_metadata.metadata.input_hash.clone(), build_backend_metadata.manifest_source.clone(), + build_backend_metadata.build_source.clone(), reporter.clone(), )); } Ok(SourceMetadata { - source: build_backend_metadata.manifest_source.clone(), + manifest_source: build_backend_metadata.manifest_source.clone(), records: futures.try_collect().await?, skipped_packages, - pinned_build_source: build_backend_metadata.build_source.clone(), + build_source: build_backend_metadata.build_source.clone(), }) } } @@ -130,15 +134,17 @@ impl SourceMetadataSpec { command_dispatcher: &CommandDispatcher, output: &CondaOutput, input_hash: Option, - source: PinnedSourceSpec, + manifest_source: PinnedSourceSpec, + build_source: Option, reporter: Option>, ) -> Result> { - let source_anchor = SourceAnchor::from(SourceSpec::from(source.clone())); + let source_anchor = SourceAnchor::from(SourceSpec::from(manifest_source.clone())); // Solve the build environment for the output. let build_dependencies = output .build_dependencies .as_ref() + // TODO(tim): we need to check if this works for out-of-tree builds with source dependencies in the out-of-tree, this might be incorrectly anchored .map(|deps| Dependencies::new(deps, Some(source_anchor.clone()))) .transpose() .map_err(SourceMetadataError::from) @@ -294,8 +300,6 @@ impl SourceMetadataSpec { strong_constrains: binary_specs_to_match_spec(run_exports.strong_constrains)?, }; - let pinned_source_spec = None; - Ok(SourceRecord { package_record: PackageRecord { // We cannot now these values from the metadata because no actual package @@ -349,9 +353,9 @@ impl SourceMetadataSpec { // These are not important at this point. experimental_extra_depends: Default::default(), }, - source, + manifest_source, input_hash, - pinned_source_spec, + build_source, sources: sources .into_iter() .map(|(name, source)| (name.as_source().to_string(), source)) diff --git a/crates/pixi_core/src/lock_file/satisfiability/mod.rs b/crates/pixi_core/src/lock_file/satisfiability/mod.rs index 811d8afeef..29d7898f00 100644 --- a/crates/pixi_core/src/lock_file/satisfiability/mod.rs +++ b/crates/pixi_core/src/lock_file/satisfiability/mod.rs @@ -1325,9 +1325,9 @@ pub(crate) async fn verify_package_platform_satisfiability( Cow::Owned(format!( "{} @ {}", record.package_record.name.as_source(), - &record.source + &record.manifest_source )), - SourceSpec::from(record.source.clone()).into(), + SourceSpec::from(record.manifest_source.clone()).into(), ), }; @@ -1497,7 +1497,7 @@ pub(crate) async fn verify_package_platform_satisfiability( .iter() .filter_map(PixiRecord::as_source) { - let Some(path_record) = source_record.source.as_path() else { + let Some(path_record) = source_record.manifest_source.as_path() else { continue; }; @@ -1714,7 +1714,7 @@ fn find_matching_source_package( }; source_package - .source + .manifest_source .satisfies(&source_spec) .map_err(|e| PlatformUnsat::SourcePackageMismatch(name.as_source().to_string(), e))?; @@ -1882,11 +1882,7 @@ fn verify_build_source_matches_manifest( match requested_loc { pixi_spec::SourceLocationSpec::Url(url_spec) => { - let Some(locked_url) = src_record - .pinned_source_spec - .as_ref() - .and_then(|p| p.as_url()) - else { + let Some(locked_url) = src_record.build_source.as_ref().and_then(|p| p.as_url()) else { return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( src_record.package_record.name.as_source().to_string(), SourceMismatchError::SourceTypeMismatch, @@ -1900,11 +1896,7 @@ fn verify_build_source_matches_manifest( }) } pixi_spec::SourceLocationSpec::Git(mut git_spec) => { - let Some(locked_git) = src_record - .pinned_source_spec - .as_ref() - .and_then(|p| p.as_git()) - else { + let Some(locked_git) = src_record.build_source.as_ref().and_then(|p| p.as_git()) else { return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( src_record.package_record.name.as_source().to_string(), SourceMismatchError::SourceTypeMismatch, @@ -1928,10 +1920,7 @@ fn verify_build_source_matches_manifest( }) } pixi_spec::SourceLocationSpec::Path(path_spec) => { - let Some(locked_path) = src_record - .pinned_source_spec - .as_ref() - .and_then(|p| p.as_path()) + let Some(locked_path) = src_record.build_source.as_ref().and_then(|p| p.as_path()) else { return Err(Box::new(PlatformUnsat::PackageBuildSourceMismatch( src_record.package_record.name.as_source().to_string(), diff --git a/crates/pixi_core/src/lock_file/update.rs b/crates/pixi_core/src/lock_file/update.rs index 77c88e4ab1..27796fc072 100644 --- a/crates/pixi_core/src/lock_file/update.rs +++ b/crates/pixi_core/src/lock_file/update.rs @@ -1430,7 +1430,7 @@ impl<'p> UpdateContext<'p> { PixiRecord::Source(src) => { let name = src.package_record.name.clone(); if targets.contains(name.as_source()) { - src.pinned_source_spec.clone().map(|spec| (name, spec)) + src.build_source.clone().map(|spec| (name, spec)) } else { None } diff --git a/crates/pixi_record/src/source_record.rs b/crates/pixi_record/src/source_record.rs index 8f80f3ba79..68bf60c0b5 100644 --- a/crates/pixi_record/src/source_record.rs +++ b/crates/pixi_record/src/source_record.rs @@ -21,9 +21,11 @@ pub struct SourceRecord { pub package_record: PackageRecord, /// Exact definition of the source of the package. - pub source: PinnedSourceSpec, + pub manifest_source: PinnedSourceSpec, - pub pinned_source_spec: Option, + /// The optional pinned source where the build should be executed + /// This is used when the manifest is not in the same location ad + pub build_source: Option, /// The hash of the input that was used to build the metadata of the /// package. This can be used to verify that the metadata is still valid. @@ -55,7 +57,7 @@ pub struct InputHash { impl From for CondaPackageData { fn from(value: SourceRecord) -> Self { - let package_build_source = value.pinned_source_spec.map(|s| match s { + let package_build_source = value.build_source.map(|s| match s { PinnedSourceSpec::Url(pinned_url_spec) => PackageBuildSource::Url { url: pinned_url_spec.url, sha256: pinned_url_spec.sha256, @@ -88,7 +90,7 @@ impl From for CondaPackageData { }); CondaPackageData::Source(CondaSourceData { package_record: value.package_record, - location: value.source.clone().into(), + location: value.manifest_source.clone().into(), package_build_source, input: value.input_hash.map(|i| rattler_lock::InputHash { hash: i.hash, @@ -146,12 +148,12 @@ impl TryFrom for SourceRecord { }); Ok(Self { package_record: value.package_record, - source: value.location.try_into()?, + manifest_source: value.location.try_into()?, input_hash: value.input.map(|hash| InputHash { hash: hash.hash, globs: BTreeSet::from_iter(hash.globs), }), - pinned_source_spec, + build_source: pinned_source_spec, sources: value .sources .into_iter() @@ -230,8 +232,8 @@ mod tests { let record = SourceRecord { package_record, - source: pinned_source.clone(), - pinned_source_spec: Some(pinned_source.clone()), + manifest_source: pinned_source.clone(), + build_source: Some(pinned_source.clone()), input_hash: None, sources: Default::default(), }; @@ -262,7 +264,7 @@ mod tests { assert_eq!(rev, "0123456789abcdef0123456789abcdef01234567"); let roundtrip = SourceRecord::try_from(conda_source).expect("roundtrip should succeed"); - let Some(PinnedSourceSpec::Git(roundtrip_git)) = roundtrip.pinned_source_spec else { + let Some(PinnedSourceSpec::Git(roundtrip_git)) = roundtrip.build_source else { panic!("expected git pinned source"); }; assert_eq!(