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: serialize system requirements #2753

Merged
merged 3 commits into from
Dec 20, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: crates/pixi_manifest/src/system_requirements.rs
expression: serialized
snapshot_kind: text
---
macos = "10.15"
linux = "5.11"
cuda = "12.2"
libc = "2.12"
archspec = "x86_64"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: crates/pixi_manifest/src/system_requirements.rs
expression: serialized
snapshot_kind: text
---
macos = "10.15"
linux = "5.11"
cuda = "12.2"
archspec = "x86_64"

[libc]
family = "glibc"
version = "2.12"
76 changes: 73 additions & 3 deletions crates/pixi_manifest/src/system_requirements.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use miette::Diagnostic;
use rattler_conda_types::Version;
use rattler_virtual_packages::{Cuda, LibC, Linux, Osx, VirtualPackage};
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use serde_value::Value;
use serde_with::{serde_as, DisplayFromStr};
use std::collections::BTreeMap;
use std::str::FromStr;
use thiserror::Error;

const GLIBC_FAMILY: &str = "glibc";

/// Describes the minimal system requirements to be able to run a certain environment.
#[serde_as]
#[derive(Debug, Clone, Deserialize, Default, PartialEq, Eq)]
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct SystemRequirements {
/// Dictates the minimum version of macOS required.
Expand Down Expand Up @@ -124,6 +126,15 @@ impl SystemRequirements {
archspec,
})
}

/// Returns true if the system requirements are empty, meaning that no requirements were specified.
pub fn is_empty(&self) -> bool {
self.linux.is_none()
&& self.cuda.is_none()
&& self.macos.is_none()
&& self.libc.is_none()
&& self.archspec.is_none()
}
}

#[derive(Debug, Clone, Error, Diagnostic)]
Expand Down Expand Up @@ -183,8 +194,33 @@ impl LibCSystemRequirement {
}
}

impl Serialize for LibCSystemRequirement {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
LibCSystemRequirement::GlibC(version) => serializer.serialize_str(&version.to_string()),
LibCSystemRequirement::OtherFamily(LibCFamilyAndVersion { family, version }) => {
let mut map = BTreeMap::new(); // Initialize the BTreeMap
if let Some(fam) = family {
map.insert(
Value::String("family".to_string()),
Value::String(fam.clone()),
);
}
map.insert(
Value::String("version".to_string()),
Value::String(version.to_string()),
);
Value::Map(map).serialize(serializer) // Wrap the map in Value::Map
}
}
}
}

#[serde_as]
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LibCFamilyAndVersion {
/// The libc family, e.g. glibc
Expand Down Expand Up @@ -225,6 +261,7 @@ mod tests {
use rattler_virtual_packages::{Cuda, LibC, Linux, Osx, VirtualPackage};
use serde::Deserialize;
use std::str::FromStr;
use toml_edit::ser::to_string_pretty;

#[test]
fn system_requirements_works() {
Expand Down Expand Up @@ -471,4 +508,37 @@ mod tests {

assert_matches!(eglibc_2_17.union(&glibc_2_12).unwrap_err(), SystemRequirementsUnionError::DifferentLibcFamilies(fam_a, fam_b) if fam_a == "eglibc" && fam_b == "glibc");
}

#[test]
fn test_serialization() {
let system_requirements = SystemRequirements {
macos: Some(Version::from_str("10.15").unwrap()),
linux: Some(Version::from_str("5.11").unwrap()),
cuda: Some(Version::from_str("12.2").unwrap()),
libc: Some(LibCSystemRequirement::GlibC(
Version::from_str("2.12").unwrap(),
)),
archspec: Some("x86_64".to_string()),
};

let serialized = to_string_pretty(&system_requirements).unwrap();
assert_snapshot!(serialized);
}

#[test]
fn test_serialization_other_family() {
let system_requirements = SystemRequirements {
macos: Some(Version::from_str("10.15").unwrap()),
linux: Some(Version::from_str("5.11").unwrap()),
cuda: Some(Version::from_str("12.2").unwrap()),
libc: Some(LibCSystemRequirement::OtherFamily(LibCFamilyAndVersion {
family: Some("glibc".to_string()),
version: Version::from_str("2.12").unwrap(),
})),
archspec: Some("x86_64".to_string()),
};

let serialized = to_string_pretty(&system_requirements).unwrap();
assert_snapshot!(serialized);
}
}
31 changes: 27 additions & 4 deletions src/cli/info.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::{fmt::Display, path::PathBuf};

use crate::cli::cli_config::ProjectConfig;
use chrono::{DateTime, Local};
use clap::Parser;
use itertools::Itertools;
use miette::IntoDiagnostic;
use pixi_config;
use pixi_consts::consts;
use pixi_manifest::{EnvironmentName, FeatureName};
use pixi_manifest::{EnvironmentName, FeatureName, SystemRequirements};
use pixi_manifest::{FeaturesExt, HasFeaturesIter};
use pixi_progress::await_in_progress;
use rattler_conda_types::{GenericVirtualPackage, Platform};
Expand All @@ -15,8 +16,7 @@ use rattler_virtual_packages::{VirtualPackage, VirtualPackageOverrides};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr};
use tokio::task::spawn_blocking;

use crate::cli::cli_config::ProjectConfig;
use toml_edit::ser::to_string;

use crate::{
global,
Expand All @@ -26,7 +26,7 @@ use crate::{
};
use fancy_display::FancyDisplay;

static WIDTH: usize = 18;
static WIDTH: usize = 19;

/// Information about the system, project and environments for the current
/// machine.
Expand Down Expand Up @@ -65,6 +65,7 @@ pub struct EnvironmentInfo {
tasks: Vec<TaskName>,
channels: Vec<String>,
prefix: PathBuf,
system_requirements: SystemRequirements,
}

impl Display for EnvironmentInfo {
Expand Down Expand Up @@ -145,6 +146,27 @@ impl Display for EnvironmentInfo {
platform_list
)?;
}

if !self.system_requirements.is_empty() {
let serialized = to_string(&self.system_requirements).unwrap();
let indented = serialized
.lines()
.enumerate()
.map(|(i, line)| {
if i == 0 {
// First line includes the label
format!("{:>WIDTH$}: {}", bold.apply_to("System requirements"), line)
} else {
// Subsequent lines are indented to align
format!("{:>WIDTH$} {}", "", line)
}
})
.collect::<Vec<_>>()
.join("\n");

writeln!(f, "{}", indented)?;
}

if !self.tasks.is_empty() {
let tasks_list = self
.tasks
Expand Down Expand Up @@ -403,6 +425,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
.map(|(name, _p)| name.as_source().to_string())
.collect(),
platforms: env.platforms().into_iter().collect(),
system_requirements: env.system_requirements().clone(),
channels: env.channels().into_iter().map(|c| c.to_string()).collect(),
prefix: env.dir(),
tasks,
Expand Down
Loading