Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: error on run if platform is not supported #878

Merged
merged 3 commits into from
Feb 29, 2024
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
5 changes: 3 additions & 2 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::consts;
use clap::Parser;
use dialoguer::theme::ColorfulTheme;
use itertools::Itertools;
use miette::{miette, Context, Diagnostic};
use miette::{miette, Context, Diagnostic, IntoDiagnostic};
use rattler_conda_types::Platform;

use crate::activation::get_environment_variables;
Expand Down Expand Up @@ -76,7 +76,8 @@ pub async fn execute(args: Args) -> miette::Result<()> {

// Verify that the current platform has the required virtual packages for the environment.
if let Some(ref explicit_environment) = explicit_environment {
verify_current_platform_has_required_virtual_packages(explicit_environment)?;
verify_current_platform_has_required_virtual_packages(explicit_environment)
.into_diagnostic()?;
}

// Ensure that the lock-file is up-to-date.
Expand Down
3 changes: 2 additions & 1 deletion src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ pub fn sanity_check_project(project: &Project) -> miette::Result<()> {
)?;

// Make sure the system requirements are met
verify_current_platform_has_required_virtual_packages(&project.default_environment())?;
verify_current_platform_has_required_virtual_packages(&project.default_environment())
.into_diagnostic()?;

// TODO: remove on a 1.0 release
// Check for old `env` folder as we moved to `envs` in 0.13.0
Expand Down
79 changes: 62 additions & 17 deletions src/project/virtual_packages.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use super::manifest::{LibCSystemRequirement, SystemRequirements};
use crate::project::errors::UnsupportedPlatformError;
use crate::project::Environment;
use itertools::Itertools;
use miette::IntoDiagnostic;
use miette::Diagnostic;
use rattler_conda_types::{GenericVirtualPackage, Platform, Version};
use rattler_virtual_packages::{Archspec, Cuda, LibC, Linux, Osx, VirtualPackage};
use rattler_virtual_packages::{
Archspec, Cuda, DetectVirtualPackageError, LibC, Linux, Osx, VirtualPackage,
};
use std::collections::HashMap;
use thiserror::Error;

/// The default GLIBC version to use. This is used when no system requirements are specified.
pub fn default_glibc_version() -> Version {
Expand Down Expand Up @@ -99,24 +103,56 @@ impl Environment<'_> {
}
}

/// An error that occurs when the current platform does not satisfy the minimal virtual package
/// requirements.
#[derive(Debug, Error, Diagnostic)]
pub enum VerifyCurrentPlatformError {
#[error("The current platform does not satisfy the minimal virtual package requirements")]
UnsupportedPlatform(#[from] Box<UnsupportedPlatformError>),

#[error(transparent)]
DetectionVirtualPackagesError(#[from] DetectVirtualPackageError),

#[error("The current system has a mismatching virtual package. The project requires '{required}' to be on build '{required_build_string}' but the system has build '{local_build_string}'")]
MismatchingBuildString {
required: String,
required_build_string: String,
local_build_string: String,
},

#[error("The current system has a mismatching virtual package. The project requires '{required}' to be at least version '{required_version}' but the system has version '{local_version}'")]
MismatchingVersion {
required: String,
required_version: Box<Version>,
local_version: Box<Version>,
},

#[error("The platform you are running on should at least have the virtual package {required} on version {required_version}, build_string: {required_build_string}")]
MissingVirtualPackage {
required: String,
required_version: Box<Version>,
required_build_string: String,
},
}

/// Verifies if the current platform satisfies the minimal virtual package requirements.
pub fn verify_current_platform_has_required_virtual_packages(
environment: &Environment<'_>,
) -> miette::Result<()> {
) -> Result<(), VerifyCurrentPlatformError> {
let current_platform = Platform::current();

// Is the current platform in the list of supported platforms?
if !environment.platforms().contains(&current_platform) {
return Err(miette::miette!(
"The current platform '{}' is not supported by the `{}` environment. Supported platforms: {}",
current_platform,
environment.name(),
environment.platforms().iter().map(|plat| plat.as_str()).join(", ")
));
return Err(VerifyCurrentPlatformError::from(Box::new(
UnsupportedPlatformError {
environments_platforms: environment.platforms().into_iter().collect_vec(),
platform: current_platform,
environment: environment.name().clone(),
},
)));
}

let system_virtual_packages = VirtualPackage::current()
.into_diagnostic()?
let system_virtual_packages = VirtualPackage::current()?
.iter()
.cloned()
.map(GenericVirtualPackage::from)
Expand All @@ -128,18 +164,27 @@ pub fn verify_current_platform_has_required_virtual_packages(
for req_pkg in required_pkgs {
if let Some(local_vpkg) = system_virtual_packages.get(&req_pkg.name) {
if req_pkg.build_string != local_vpkg.build_string {
miette::bail!("The current system has a mismatching virtual package. The project requires '{}' to be on build '{}' but the system has build '{}'", req_pkg.name.as_source(), req_pkg.build_string, local_vpkg.build_string);
return Err(VerifyCurrentPlatformError::MismatchingBuildString {
required: req_pkg.name.as_source().to_string(),
required_build_string: req_pkg.build_string.clone(),
local_build_string: local_vpkg.build_string.clone(),
});
}

if req_pkg.version > local_vpkg.version {
// This case can simply happen because the default system requirements in get_minimal_virtual_packages() is higher than required.
miette::bail!("The current system has a mismatching virtual package. The project requires '{}' to be at least version '{}' but the system has version '{}'\n\n\
Try setting the following in your pixi.toml:\n\
[system-requirements]\n\
{} = \"{}\"", req_pkg.name.as_source(), req_pkg.version, local_vpkg.version, req_pkg.name.as_normalized().strip_prefix("__").unwrap_or(local_vpkg.name.as_normalized()), local_vpkg.version);
return Err(VerifyCurrentPlatformError::MismatchingVersion {
required: req_pkg.name.as_source().to_string(),
required_version: Box::from(req_pkg.version),
local_version: Box::from(local_vpkg.version.clone()),
});
}
} else {
miette::bail!("The platform you are running on should at least have the virtual package {} on version {}, build_string: {}", req_pkg.name.as_source(), req_pkg.version, req_pkg.build_string)
return Err(VerifyCurrentPlatformError::MissingVirtualPackage {
required: req_pkg.name.as_source().to_string(),
required_version: Box::from(req_pkg.version),
required_build_string: req_pkg.build_string.clone(),
});
}
}

Expand Down
23 changes: 15 additions & 8 deletions src/task/task_graph.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use crate::project::virtual_packages::{
verify_current_platform_has_required_virtual_packages, VerifyCurrentPlatformError,
};
use crate::project::Environment;
use crate::task::error::AmbiguousTaskError;
use crate::task::task_environment::{FindTaskError, FindTaskSource, SearchEnvironments};
Expand Down Expand Up @@ -131,7 +134,6 @@ impl<'p> TaskGraph<'p> {
Some(explicit_env) if task_env.is_default() => explicit_env,
_ => task_env,
};

return Self::from_root(
project,
search_envs,
Expand All @@ -152,6 +154,7 @@ impl<'p> TaskGraph<'p> {
.explicit_environment
.clone()
.unwrap_or_else(|| project.default_environment());
verify_current_platform_has_required_virtual_packages(&run_environment)?;
Self::from_root(
project,
search_envs,
Expand Down Expand Up @@ -286,6 +289,10 @@ pub enum TaskGraphError {
#[error(transparent)]
#[diagnostic(transparent)]
AmbiguousTask(AmbiguousTaskError),

#[error(transparent)]
#[diagnostic(transparent)]
UnsupportedPlatform(#[from] VerifyCurrentPlatformError),
}

#[cfg(test)]
Expand Down Expand Up @@ -330,7 +337,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]
[tasks]
root = "echo root"
task1 = {cmd="echo task1", depends_on=["root"]}
Expand All @@ -353,7 +360,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]
[tasks]
root = {cmd="echo root", depends_on=["task1"]}
task1 = {cmd="echo task1", depends_on=["root"]}
Expand All @@ -376,7 +383,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]
[tasks]
root = "echo root"
task1 = {cmd="echo task1", depends_on=["root"]}
Expand All @@ -401,7 +408,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]
"#,
&["echo bla"],
None,
Expand All @@ -419,7 +426,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]

[feature.build.tasks]
build = "echo build"
Expand All @@ -443,7 +450,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]

[tasks]
start = "hello world"
Expand All @@ -470,7 +477,7 @@ mod test {
[project]
name = "pixi"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-64", "win-64", "osx-arm64"]

[tasks]
train = "python train.py"
Expand Down
Loading