Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions crates/pixi_core/src/lock_file/resolve/build_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//! needed.
use std::cell::Cell;
use std::collections::HashSet;
use std::sync::Arc;
use std::{collections::HashMap, path::Path};

use crate::environment::{CondaPrefixUpdated, CondaPrefixUpdater};
Expand Down Expand Up @@ -218,6 +219,10 @@ pub struct LazyBuildDispatch<'a> {
workspace_cache: WorkspaceCache,

pub ignore_packages: Option<HashSet<rattler_conda_types::PackageName>>,

/// Shared error holder for storing initialization errors that can be retrieved
/// after the LazyBuildDispatch is consumed (e.g., in catch_unwind scenarios)
pub last_error: Arc<OnceCell<LazyBuildDispatchError>>,
}

/// These are resources for the [`BuildDispatch`] that need to be lazily
Expand All @@ -242,8 +247,6 @@ pub struct LazyBuildDispatchDependencies {
extra_build_variables: OnceCell<ExtraBuildVariables>,
/// Package-specific configuration settings
package_config_settings: OnceCell<PackageConfigSettings>,
/// The last initialization error that occurred
last_error: OnceCell<LazyBuildDispatchError>,
}

#[derive(Debug, thiserror::Error, miette::Diagnostic)]
Expand Down Expand Up @@ -276,11 +279,6 @@ impl IsBuildBackendError for LazyBuildDispatchError {
}

impl<'a> LazyBuildDispatch<'a> {
/// Get the last initialization error if available
pub fn last_initialization_error(&self) -> Option<&LazyBuildDispatchError> {
self.lazy_deps.last_error.get()
}

/// Create a new `PixiBuildDispatch` instance.
#[allow(clippy::too_many_arguments)]
pub fn new(
Expand All @@ -293,6 +291,7 @@ impl<'a> LazyBuildDispatch<'a> {
lazy_deps: &'a LazyBuildDispatchDependencies,
ignore_packages: Option<HashSet<rattler_conda_types::PackageName>>,
disallow_install_conda_prefix: bool,
last_error: Arc<OnceCell<LazyBuildDispatchError>>,
) -> Self {
Self {
params,
Expand All @@ -307,6 +306,7 @@ impl<'a> LazyBuildDispatch<'a> {
disallow_install_conda_prefix,
workspace_cache: WorkspaceCache::default(),
ignore_packages,
last_error,
}
}

Expand Down Expand Up @@ -441,7 +441,7 @@ impl BuildContext for LazyBuildDispatch<'_> {
Ok(dispatch) => dispatch.interpreter().await,
Err(e) => {
// Store the error for later retrieval
let _ = self.lazy_deps.last_error.set(e);
let _ = self.last_error.set(e);
panic!("could not initialize build dispatch correctly")
}
}
Expand Down
69 changes: 40 additions & 29 deletions crates/pixi_core/src/lock_file/resolve/pypi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use std::{
sync::Arc,
};

use once_cell::sync::OnceCell;

use futures::FutureExt;

use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -230,6 +232,10 @@ pub enum SolveError {
#[error(transparent)]
#[diagnostic(transparent)]
LookAhead(Box<dyn miette::Diagnostic + Send + Sync + 'static>),

#[error(transparent)]
#[diagnostic(transparent)]
Locking(Box<dyn miette::Diagnostic + Send + Sync + 'static>),
}

/// Creates a custom `SolveError` from a `ResolveError`.
Expand Down Expand Up @@ -549,6 +555,7 @@ pub async fn resolve_pypi(
.with_concurrency(context.concurrency);

let lazy_build_dispatch_dependencies = LazyBuildDispatchDependencies::default();
let last_error = Arc::new(OnceCell::new());
let lazy_build_dispatch = LazyBuildDispatch::new(
build_params,
prefix_updater,
Expand All @@ -559,6 +566,7 @@ pub async fn resolve_pypi(
&lazy_build_dispatch_dependencies,
None,
disallow_install_conda_prefix,
Arc::clone(&last_error),
);

// Constrain the conda packages to the specific python packages
Expand Down Expand Up @@ -747,18 +755,45 @@ pub async fn resolve_pypi(
UvReporterOptions::new().with_existing(pb.clone()),
));

resolver
let resolution = resolver
.resolve()
.await
.map_err(|e| create_solve_error(e, &conda_python_packages))
.map_err(|e| create_solve_error(e, &conda_python_packages))?;

let resolution = Resolution::from(resolution);

// Print the overridden package requests
print_overridden_requests(package_requests.borrow().deref());

// Print any diagnostics
for diagnostic in resolution.diagnostics() {
tracing::warn!("{}", diagnostic.message());
}

let locked_packages = lock_pypi_packages(
conda_python_packages,
&lazy_build_dispatch,
&registry_client,
resolution,
&context.capabilities,
context.concurrency.downloads,
project_root,
&original_git_references,
)
.await
.map_err(|e| SolveError::Locking(e.into()))?;

let conda_task = lazy_build_dispatch.conda_task;

Ok::<_, SolveError>((locked_packages, conda_task))
});

// We try to distinguish between build dispatch panics and any other panics that occur
let resolution = match resolution_future.catch_unwind().await {
let (locked_packages, conda_task) = match resolution_future.catch_unwind().await {
Ok(result) => result?,
Err(panic_payload) => {
// Try to get the stored initialization error from the lazy build dispatch
if let Some(stored_error) = lazy_build_dispatch.last_initialization_error() {
// Try to get the stored initialization error from the last_error holder
if let Some(stored_error) = last_error.get() {
return Err(SolveError::BuildDispatchPanic {
message: format!("{stored_error}"),
}
Expand All @@ -780,30 +815,6 @@ pub async fn resolve_pypi(
}
}
};
let resolution = Resolution::from(resolution);

// Print the overridden package requests
print_overridden_requests(package_requests.borrow().deref());

// Print any diagnostics
for diagnostic in resolution.diagnostics() {
tracing::warn!("{}", diagnostic.message());
}

// Collect resolution into locked packages
let locked_packages = lock_pypi_packages(
conda_python_packages,
&lazy_build_dispatch,
&registry_client,
resolution,
&context.capabilities,
context.concurrency.downloads,
project_root,
&original_git_references,
)
.await?;

let conda_task = lazy_build_dispatch.conda_task;

Ok((locked_packages, conda_task))
}
Expand Down