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

feat: add pixi-build behind preview feature #2514

Merged
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
1 change: 1 addition & 0 deletions crates/pixi_build_frontend/tests/basic/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ channels = ["conda-forge"]
description = "Add a short description here"
name = "basic"
platforms = ["osx-arm64"]
preview = ["pixi-build"]
version = "0.1.0"

[tasks]
Expand Down
1 change: 1 addition & 0 deletions crates/pixi_build_frontend/tests/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ async fn test_missing_backend() {
name = "project"
platforms = []
channels = []
preview = ['pixi-build']

[build-system]
dependencies = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expression: snapshot
---
Globs:
- tests/data/satisfiability/source-dependency/**/*
Hash: 218e03654fe6ebe41d9488d62e24584d118e8bbc06aa054d6b64d2538abc6d01
Hash: bcec5beb36091c68ee58f72f1f4d33f3658b98732912f2cbe5827898d8a666f9
Matched files:
- tests/data/satisfiability/source-dependency/child-package/pixi.toml
- tests/data/satisfiability/source-dependency/pixi.lock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ expression: snapshot
Globs:
- tests/data/satisfiability/source-dependency/**/*
- !tests/data/satisfiability/source-dependency/**/*.lock
Hash: d0ddcb9b7cb2d9174875232dfa29e52f6e1b8e43cdcae03fea11af0177c4c2d7
Hash: c0506e1c483578c78217015a4b19e90826c005bfe2ed9a59c83bc2054d4b5d4a
Matched files:
- tests/data/satisfiability/source-dependency/child-package/pixi.toml
- tests/data/satisfiability/source-dependency/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ expression: snapshot
---
Globs:
- tests/data/satisfiability/source-dependency/pixi.toml
Hash: 3fd25b6fc88a942ba43885b4b561385b819d879ffe28fc64a06beec4fa87a757
Hash: 0acde3549cf146ff910d07405f8146dea0659c19b25d6292048da9f2d47e667e
Matched files:
- tests/data/satisfiability/source-dependency/pixi.toml
68 changes: 66 additions & 2 deletions crates/pixi_manifest/src/manifests/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -733,8 +733,8 @@ impl Manifest {
}

/// Returns the preview field of the project
pub fn preview(&self) -> Option<&Preview> {
self.workspace.workspace.preview.as_ref()
pub fn preview(&self) -> &Preview {
&self.workspace.workspace.preview
}

/// Return the build section from the parsed manifest
Expand Down Expand Up @@ -2355,4 +2355,68 @@ bar = "*"
.collect();
assert_eq!(channels, vec!["pytorch", "conda-forge", "bioconda"]);
}

#[test]
fn test_validation_failure_source_dependency() {
let toml = r#"
[project]
name = "test"
channels = ['conda-forge']
platforms = ['linux-64']

[dependencies]
foo = { path = "./foo" }
"#;

let manifest = Manifest::from_str(Path::new("pixi.toml"), toml);
let err = manifest.unwrap_err();
insta::assert_snapshot!(err, @"source dependencies are used in the feature 'default', but the `pixi-build` preview feature is not enabled");
}

#[test]
fn test_validation_failure_build_section() {
let toml = r#"
[project]
name = "test"
channels = ['conda-forge']
platforms = ['linux-64']

[build-system]
build-backend = "pixi-build-cmake"
channels = [
"https://prefix.dev/pixi-build-backends",
"https://prefix.dev/conda-forge",
]
dependencies = ["pixi-build-cmake"]
"#;

let manifest = Manifest::from_str(Path::new("pixi.toml"), toml);
let err = manifest.unwrap_err();
insta::assert_snapshot!(err, @"the build-system is defined, but the `pixi-build` preview feature is not enabled");
}

#[test]
fn test_validation_succeed_build() {
let toml = r#"
[project]
name = "test"
channels = ['conda-forge']
platforms = ['linux-64']
preview = ["pixi-build"]

[build-system]
build-backend = "pixi-build-cmake"
channels = [
"https://prefix.dev/pixi-build-backends",
"https://prefix.dev/conda-forge",
]
dependencies = ["pixi-build-cmake"]

[dependencies]
foo = { path = "./foo" }
"#;

let manifest = Manifest::from_str(Path::new("pixi.toml"), toml);
manifest.unwrap();
}
}
9 changes: 8 additions & 1 deletion crates/pixi_manifest/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ pub enum Preview {
Features(Vec<PreviewFeature>), // For `preview = ["feature"]`
}

impl Default for Preview {
fn default() -> Self {
Self::Features(Vec::new())
}
}

impl Preview {
/// Returns true if all preview features are enabled
pub fn all_enabled(&self) -> bool {
Expand Down Expand Up @@ -92,7 +98,8 @@ impl PartialEq<KnownPreviewFeature> for PreviewFeature {
#[serde(rename_all = "kebab-case")]
/// Currently supported preview features are listed here
pub enum KnownPreviewFeature {
// Add known features here
/// Build feature, to enable conda source builds
PixiBuild,
}

impl<'de> Deserialize<'de> for PreviewFeature {
Expand Down
82 changes: 69 additions & 13 deletions crates/pixi_manifest/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use std::{

use super::pypi::pypi_options::PypiOptions;
use crate::{
Environment, Feature, FeatureName, SystemRequirements, TargetSelector, WorkspaceManifest,
Environment, Feature, FeatureName, KnownPreviewFeature, SystemRequirements, TargetSelector,
WorkspaceManifest,
};

impl WorkspaceManifest {
Expand Down Expand Up @@ -133,18 +134,47 @@ impl WorkspaceManifest {
}

// Warn on any unknown preview features
if let Some(preview) = self.workspace.preview.as_ref() {
let preview = preview.unknown_preview_features();
if !preview.is_empty() {
let are = if preview.len() > 1 { "are" } else { "is" };
let s = if preview.len() > 1 { "s" } else { "" };
let preview_array = if preview.len() == 1 {
format!("{:?}", preview)
} else {
format!("[{:?}]", preview.iter().format(", "))
};
tracing::warn!(
"The preview feature{s}: {preview_array} {are} defined in the manifest but un-used pixi");
let preview = self.workspace.preview.unknown_preview_features();
if !preview.is_empty() {
let are = if preview.len() > 1 { "are" } else { "is" };
let s = if preview.len() > 1 { "s" } else { "" };
let preview_array = if preview.len() == 1 {
format!("{:?}", preview)
} else {
format!("[{:?}]", preview.iter().format(", "))
};
tracing::warn!(
"The preview feature{s}: {preview_array} {are} defined in the manifest but un-used pixi");
}

// Check if the pixi build feature is enabled
let build_enabled = self
.workspace
.preview
.is_enabled(KnownPreviewFeature::PixiBuild);

// Error any conda source dependencies are used and is not set
if !build_enabled {
let supported_platforms = self.workspace.platforms.as_ref();
// Check all features for source dependencies
for feature in self.features.values() {
if is_using_source_deps(feature, supported_platforms.iter()) {
return Err(miette::miette!(
help = "enable the `pixi-build` preview feature to use source dependencies",
"source dependencies are used in the feature '{}', but the `pixi-build` preview feature is not enabled",
feature.name
));
}
}

if self.build_system.is_some() {
// Check if we have enabled the build feature if we have a build section
if !build_enabled {
return Err(miette::miette!(
help = "enable the `pixi-build` preview feature to use the build-system section by setting `preview = [\"pixi-build\"]",
"the build-system is defined, but the `pixi-build` preview feature is not enabled"
));
}
}
}

Expand Down Expand Up @@ -244,6 +274,32 @@ impl WorkspaceManifest {
}
}

/// Check if any feature is making use of conda source dependencies
fn is_using_source_deps<'a>(
feature: &Feature,
supported_platforms: impl IntoIterator<Item = &'a Platform>,
) -> bool {
// List all spec types
let spec_types = [
crate::SpecType::Build,
crate::SpecType::Run,
crate::SpecType::Host,
];
// Check if any of the spec types have source dependencies
for platform in supported_platforms {
for spec in spec_types {
let deps = feature.dependencies(spec, Some(*platform));
if let Some(deps) = deps {
if deps.iter().any(|(_, spec)| spec.is_source()) {
return true;
}
}
}
}

false
}

// Create an error report for using a platform that is not supported by the
// project.
fn create_unsupported_platform_report(
Expand Down
6 changes: 3 additions & 3 deletions crates/pixi_manifest/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use serde_with::{serde_as, DisplayFromStr};
use url::Url;

use super::pypi::pypi_options::PypiOptions;
use crate::preview::Preview;
use crate::utils::PixiSpanned;
use crate::{preview::Preview, utils::PixiSpanned};

/// Describes the contents of the `[package]` section of the project manifest.
#[serde_as]
Expand Down Expand Up @@ -67,5 +66,6 @@ pub struct Workspace {
pub pypi_options: Option<PypiOptions>,

/// Preview features
pub preview: Option<Preview>,
#[serde(default)]
pub preview: Preview,
}
8 changes: 4 additions & 4 deletions examples/cpp-sdl/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/cpp-sdl/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ channels = ["https://fast.prefix.dev/conda-forge"]
description = "Showcases how to create a simple C++ executable with Pixi"
name = "sdl_example"
platforms = ["win-64", "linux-64", "osx-arm64", "osx-64"]
preview = ["pixi-build"]

[build-system]
build-backend = "pixi-build-cmake"
Expand Down
Loading
Loading