Skip to content

Commit fbd8ab6

Browse files
fix: diagnostic source of solve error was not propagated (#4417)
Co-authored-by: Tim de Jager <[email protected]>
1 parent a79cdce commit fbd8ab6

File tree

2 files changed

+73
-47
lines changed

2 files changed

+73
-47
lines changed

crates/pixi_core/src/lock_file/update.rs

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,26 @@
1-
use super::{
2-
CondaPrefixUpdater, PixiRecordsByName, PypiRecordsByName, UvResolutionContext,
3-
outdated::OutdatedEnvironments, utils::IoConcurrencyLimit,
4-
};
5-
use crate::{
6-
Workspace,
7-
activation::CurrentEnvVarBehavior,
8-
environment::{
9-
CondaPrefixUpdated, EnvironmentFile, LockFileUsage, LockedEnvironmentHash,
10-
PerEnvironmentAndPlatform, PerGroup, PerGroupAndPlatform, PythonStatus,
11-
read_environment_file, write_environment_file,
12-
},
13-
install_pypi::{PyPIBuildConfig, PyPIContextConfig, PyPIEnvironmentUpdater, PyPIUpdateConfig},
14-
lock_file::{
15-
self, PypiRecord, reporter::SolveProgressBar,
16-
virtual_packages::validate_system_meets_environment_requirements,
17-
},
18-
workspace::{
19-
Environment, EnvironmentVars, HasWorkspaceRef, get_activated_environment_variables,
20-
grouped_environment::{GroupedEnvironment, GroupedEnvironmentName},
21-
},
1+
use std::{
2+
cmp::PartialEq,
3+
collections::{HashMap, HashSet, hash_map::Entry},
4+
future::{Future, ready},
5+
iter,
6+
path::PathBuf,
7+
str::FromStr,
8+
sync::Arc,
9+
time::{Duration, Instant},
2210
};
11+
2312
use barrier_cell::BarrierCell;
2413
use dashmap::DashMap;
2514
use fancy_display::FancyDisplay;
26-
use futures::{FutureExt, StreamExt, stream::FuturesUnordered};
15+
use futures::{FutureExt, StreamExt, TryFutureExt, stream::FuturesUnordered};
2716
use indexmap::{IndexMap, IndexSet};
2817
use indicatif::ProgressBar;
2918
use itertools::{Either, Itertools};
3019
use miette::{Diagnostic, IntoDiagnostic, MietteDiagnostic, Report, WrapErr};
31-
use pixi_command_dispatcher::{BuildEnvironment, CommandDispatcher, PixiEnvironmentSpec};
20+
use pixi_command_dispatcher::{
21+
BuildEnvironment, CommandDispatcher, CommandDispatcherError, PixiEnvironmentSpec,
22+
SolvePixiEnvironmentError,
23+
};
3224
use pixi_consts::consts;
3325
use pixi_glob::GlobHashCache;
3426
use pixi_manifest::{ChannelPriority, EnvironmentName, FeaturesExt};
@@ -42,24 +34,36 @@ use pixi_uv_conversions::{
4234
use pypi_mapping::{self, MappingClient};
4335
use pypi_modifiers::pypi_marker_env::determine_marker_environment;
4436
use rattler::package_cache::PackageCache;
45-
use rattler_conda_types::{Arch, GenericVirtualPackage, PackageName, Platform};
37+
use rattler_conda_types::{Arch, GenericVirtualPackage, PackageName, ParseChannelError, Platform};
4638
use rattler_lock::{LockFile, LockedPackageRef, ParseCondaLockError};
47-
use std::collections::hash_map::Entry;
48-
use std::{
49-
cmp::PartialEq,
50-
collections::{HashMap, HashSet},
51-
future::{Future, ready},
52-
iter,
53-
path::PathBuf,
54-
str::FromStr,
55-
sync::Arc,
56-
time::{Duration, Instant},
57-
};
5839
use thiserror::Error;
5940
use tokio::sync::Semaphore;
6041
use tracing::Instrument;
6142
use uv_normalize::ExtraName;
6243

44+
use super::{
45+
CondaPrefixUpdater, PixiRecordsByName, PypiRecordsByName, UvResolutionContext,
46+
outdated::OutdatedEnvironments, utils::IoConcurrencyLimit,
47+
};
48+
use crate::{
49+
Workspace,
50+
activation::CurrentEnvVarBehavior,
51+
environment::{
52+
CondaPrefixUpdated, EnvironmentFile, LockFileUsage, LockedEnvironmentHash,
53+
PerEnvironmentAndPlatform, PerGroup, PerGroupAndPlatform, PythonStatus,
54+
read_environment_file, write_environment_file,
55+
},
56+
install_pypi::{PyPIBuildConfig, PyPIContextConfig, PyPIEnvironmentUpdater, PyPIUpdateConfig},
57+
lock_file::{
58+
self, PypiRecord, reporter::SolveProgressBar,
59+
virtual_packages::validate_system_meets_environment_requirements,
60+
},
61+
workspace::{
62+
Environment, EnvironmentVars, HasWorkspaceRef, get_activated_environment_variables,
63+
grouped_environment::{GroupedEnvironment, GroupedEnvironmentName},
64+
},
65+
};
66+
6367
impl Workspace {
6468
/// Ensures that the lock-file is up-to-date with the project.
6569
///
@@ -207,6 +211,25 @@ enum UpdateError {
207211
ParseLockFileError(#[from] ParseLockFileError),
208212
}
209213

214+
#[derive(Debug, Error, Diagnostic)]
215+
pub enum SolveCondaEnvironmentError {
216+
#[error("failed to solve requirements of environment '{}' for platform '{}'", .environment_name.fancy_display(), .platform)]
217+
SolveFailed {
218+
environment_name: GroupedEnvironmentName,
219+
platform: Platform,
220+
#[source]
221+
#[diagnostic_source]
222+
source: CommandDispatcherError<SolvePixiEnvironmentError>,
223+
},
224+
225+
#[error(transparent)]
226+
#[diagnostic(transparent)]
227+
PypiMappingFailed(Box<dyn Diagnostic + Send + Sync + 'static>),
228+
229+
#[error(transparent)]
230+
ParseChannels(#[from] ParseChannelError),
231+
}
232+
210233
/// Options to pass to [`Workspace::update_lock_file`].
211234
#[derive(Default)]
212235
pub struct UpdateLockFileOptions {
@@ -1326,6 +1349,7 @@ impl<'p> UpdateContext<'p> {
13261349
channel_priority,
13271350
self.command_dispatcher.clone(),
13281351
)
1352+
.map_err(Report::new)
13291353
.boxed_local();
13301354

13311355
// Store the task so we can poll it later.
@@ -1828,7 +1852,7 @@ async fn spawn_solve_conda_environment_task(
18281852
platform: Platform,
18291853
channel_priority: ChannelPriority,
18301854
command_dispatcher: CommandDispatcher,
1831-
) -> miette::Result<TaskResult> {
1855+
) -> Result<TaskResult, SolveCondaEnvironmentError> {
18321856
// Get the dependencies for this platform
18331857
let dependencies = group.combined_dependencies(Some(platform));
18341858

@@ -1859,7 +1883,11 @@ async fn spawn_solve_conda_environment_task(
18591883
let has_pypi_dependencies = group.has_pypi_dependencies();
18601884

18611885
// Whether we should use custom mapping location
1862-
let pypi_name_mapping_location = group.workspace().pypi_name_mapping_source()?.clone();
1886+
let pypi_name_mapping_location = group
1887+
.workspace()
1888+
.pypi_name_mapping_source()
1889+
.map_err(|err| SolveCondaEnvironmentError::PypiMappingFailed(err.into()))?
1890+
.clone();
18631891

18641892
// Get the channel configuration
18651893
let channel_config = group.workspace().channel_config();
@@ -1868,8 +1896,7 @@ async fn spawn_solve_conda_environment_task(
18681896
let channels = channels
18691897
.iter()
18701898
.map(|c| c.clone().into_base_url(&channel_config))
1871-
.collect::<Result<Vec<_>, _>>()
1872-
.into_diagnostic()?;
1899+
.collect::<Result<Vec<_>, _>>()?;
18731900

18741901
// Determine the build variants
18751902
let variants = group.workspace().variants(platform);
@@ -1893,12 +1920,10 @@ async fn spawn_solve_conda_environment_task(
18931920
enabled_protocols: Default::default(),
18941921
})
18951922
.await
1896-
.with_context(|| {
1897-
format!(
1898-
"failed to solve requirements of environment '{}' for platform '{}'",
1899-
group.name().fancy_display(),
1900-
platform
1901-
)
1923+
.map_err(|source| SolveCondaEnvironmentError::SolveFailed {
1924+
environment_name: group_name.clone(),
1925+
platform,
1926+
source,
19021927
})?;
19031928

19041929
// Add purl's for the conda packages that are also available as pypi packages if
@@ -1911,7 +1936,8 @@ async fn spawn_solve_conda_environment_task(
19111936
records.iter_mut().filter_map(PixiRecord::as_binary_mut),
19121937
None,
19131938
)
1914-
.await?;
1939+
.await
1940+
.map_err(|err| SolveCondaEnvironmentError::PypiMappingFailed(err.into()))?;
19151941
}
19161942

19171943
// Turn the records into a map by name

crates/pixi_core/src/workspace/grouped_environment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl<'p> HasFeaturesIter<'p> for GroupedEnvironment<'p> {
149149
}
150150

151151
/// A name of a [`GroupedEnvironment`].
152-
#[derive(Clone)]
152+
#[derive(Debug, Clone)]
153153
pub enum GroupedEnvironmentName {
154154
Group(String),
155155
Environment(EnvironmentName),

0 commit comments

Comments
 (0)