Skip to content

Commit

Permalink
Merge branch 'main' into feature/configurable-pixi-home
Browse files Browse the repository at this point in the history
  • Loading branch information
ruben-arts authored Jan 9, 2024
2 parents c496416 + f642df3 commit fd0a8ae
Show file tree
Hide file tree
Showing 4 changed files with 369 additions and 16 deletions.
63 changes: 62 additions & 1 deletion src/project/manifest/environment.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::consts;
use crate::utils::spanned::PixiSpanned;
use serde::{self, Deserialize, Deserializer};

/// The name of an environment. This is either a string or default for the default environment.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
Expand All @@ -18,6 +20,18 @@ impl EnvironmentName {
}
}

impl<'de> Deserialize<'de> for EnvironmentName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
match String::deserialize(deserializer)? {
name if name == consts::DEFAULT_ENVIRONMENT_NAME => Ok(EnvironmentName::Default),
name => Ok(EnvironmentName::Named(name)),
}
}
}

/// An environment describes a set of features that are available together.
///
/// Individual features cannot be used directly, instead they are grouped together into
Expand All @@ -33,10 +47,57 @@ pub struct Environment {
/// environment.
pub features: Vec<String>,

/// The optional location of where the features are defined in the manifest toml.
/// The optional location of where the features of the environment are defined in the manifest toml.
pub features_source_loc: Option<std::ops::Range<usize>>,

/// An optional solver-group. Multiple environments can share the same solve-group. All the
/// dependencies of the environment that share the same solve-group will be solved together.
pub solve_group: Option<String>,
}

/// Helper struct to deserialize the environment from TOML.
/// The environment description can only hold these values.
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
pub(super) struct TomlEnvironment {
pub features: PixiSpanned<Vec<String>>,
pub solve_group: Option<String>,
}

pub(super) enum TomlEnvironmentMapOrSeq {
Map(TomlEnvironment),
Seq(Vec<String>),
}
impl TomlEnvironmentMapOrSeq {
pub fn into_environment(self, name: EnvironmentName) -> Environment {
match self {
TomlEnvironmentMapOrSeq::Map(TomlEnvironment {
features,
solve_group,
}) => Environment {
name,
features: features.value,
features_source_loc: features.span,
solve_group,
},
TomlEnvironmentMapOrSeq::Seq(features) => Environment {
name,
features,
features_source_loc: None,
solve_group: None,
},
}
}
}
impl<'de> Deserialize<'de> for TomlEnvironmentMapOrSeq {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
serde_untagged::UntaggedEnumVisitor::new()
.map(|map| map.deserialize().map(TomlEnvironmentMapOrSeq::Map))
.seq(|seq| seq.deserialize().map(TomlEnvironmentMapOrSeq::Seq))
.expecting("either a map or a sequence")
.deserialize(deserializer)
}
}
80 changes: 77 additions & 3 deletions src/project/manifest/feature.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use super::SystemRequirements;
use super::{Activation, PyPiRequirement, SystemRequirements, Target, TargetSelector};
use crate::project::manifest::target::Targets;
use crate::project::SpecType;
use crate::task::Task;
use crate::utils::spanned::PixiSpanned;
use rattler_conda_types::{Channel, Platform};
use indexmap::IndexMap;
use rattler_conda_types::{Channel, NamelessMatchSpec, PackageName, Platform};
use serde::de::Error;
use serde::Deserialize;
use serde::{Deserialize, Deserializer};
use serde_with::{serde_as, DisplayFromStr, PickFirst};
use std::collections::HashMap;

/// The name of a feature. This is either a string or default for the default feature.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -64,3 +69,72 @@ pub struct Feature {
/// Target specific configuration.
pub targets: Targets,
}

impl<'de> Deserialize<'de> for Feature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[serde_as]
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct FeatureInner {
#[serde(default)]
platforms: Option<PixiSpanned<Vec<Platform>>>,
#[serde_as(deserialize_as = "Option<Vec<super::serde::ChannelStr>>")]
channels: Option<Vec<Channel>>,
#[serde(default)]
system_requirements: SystemRequirements,
#[serde(default)]
target: IndexMap<PixiSpanned<TargetSelector>, Target>,

#[serde(default)]
#[serde_as(as = "IndexMap<_, PickFirst<(DisplayFromStr, _)>>")]
dependencies: IndexMap<PackageName, NamelessMatchSpec>,

#[serde(default)]
#[serde_as(as = "Option<IndexMap<_, PickFirst<(DisplayFromStr, _)>>>")]
host_dependencies: Option<IndexMap<PackageName, NamelessMatchSpec>>,

#[serde(default)]
#[serde_as(as = "Option<IndexMap<_, PickFirst<(DisplayFromStr, _)>>>")]
build_dependencies: Option<IndexMap<PackageName, NamelessMatchSpec>>,

#[serde(default)]
pypi_dependencies: Option<IndexMap<rip::types::PackageName, PyPiRequirement>>,

/// Additional information to activate an environment.
#[serde(default)]
activation: Option<Activation>,

/// Target specific tasks to run in the environment
#[serde(default)]
tasks: HashMap<String, Task>,
}

let inner = FeatureInner::deserialize(deserializer)?;

let mut dependencies = HashMap::from_iter([(SpecType::Run, inner.dependencies)]);
if let Some(host_deps) = inner.host_dependencies {
dependencies.insert(SpecType::Host, host_deps);
}
if let Some(build_deps) = inner.build_dependencies {
dependencies.insert(SpecType::Build, build_deps);
}

let default_target = Target {
dependencies,
pypi_dependencies: inner.pypi_dependencies,
activation: inner.activation,
tasks: inner.tasks,
};

Ok(Feature {
name: FeatureName::Default,
platforms: inner.platforms,
channels: inner.channels,
system_requirements: inner.system_requirements,
targets: Targets::from_default_and_user_defined(default_target, inner.target),
})
}
}
Loading

0 comments on commit fd0a8ae

Please sign in to comment.