Skip to content

Commit 94bb543

Browse files
authored
feat: refactor into traits (#91)
1 parent e393f8a commit 94bb543

File tree

16 files changed

+606
-377
lines changed

16 files changed

+606
-377
lines changed

crates/pixi-build-backend/src/build_types_ext.rs

Lines changed: 0 additions & 111 deletions
This file was deleted.

crates/pixi-build-backend/src/cli.rs

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::path::{Path, PathBuf};
33
use clap::{Parser, Subcommand};
44
use clap_verbosity_flag::{InfoLevel, Verbosity};
55
use miette::{Context, IntoDiagnostic};
6-
use pixi_build_type_conversions::to_project_model_v1;
76
use pixi_build_types::{
87
procedures::{
98
conda_build::CondaBuildParams,
@@ -12,7 +11,6 @@ use pixi_build_types::{
1211
negotiate_capabilities::NegotiateCapabilitiesParams,
1312
},
1413
BackendCapabilities, ChannelConfiguration, FrontendCapabilities, PlatformAndVirtualPackages,
15-
ProjectModelV1,
1614
};
1715
use rattler_build::console_utils::{get_default_env_filter, LoggingOutputHandler};
1816
use rattler_conda_types::{ChannelConfig, GenericVirtualPackage, Platform};
@@ -22,6 +20,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
2220

2321
use crate::{
2422
consts,
23+
project::to_project_model,
2524
protocol::{Protocol, ProtocolInstantiator},
2625
server::Server,
2726
};
@@ -68,6 +67,7 @@ async fn run_server<T: ProtocolInstantiator>(port: Option<u16>, protocol: T) ->
6867
if let Some(port) = port {
6968
server.run_over_http(port)
7069
} else {
70+
// running over stdin/stdout
7171
server.run().await
7272
}
7373
}
@@ -123,27 +123,11 @@ pub async fn main<T: ProtocolInstantiator, F: FnOnce(LoggingOutputHandler) -> T>
123123
}
124124
}
125125

126-
/// Convert manifest to project model
127-
fn project_model_v1(
128-
manifest_path: &Path,
129-
channel_config: &ChannelConfig,
130-
) -> miette::Result<Option<ProjectModelV1>> {
131-
// Load the manifest
132-
let manifest =
133-
pixi_manifest::Manifests::from_workspace_manifest_path(manifest_path.to_path_buf())?;
134-
let package = manifest.value.package.as_ref();
135-
// This can be null in the rattler-build backend
136-
Ok(package.map(|manifest| {
137-
to_project_model_v1(&manifest.value, channel_config)
138-
.expect("failed to convert manifest to project model")
139-
}))
140-
}
141-
142126
/// Negotiate the capabilities of the backend and initialize the backend.
143127
async fn initialize<T: ProtocolInstantiator>(
144128
factory: T,
145129
manifest_path: &Path,
146-
) -> miette::Result<T::ProtocolEndpoint> {
130+
) -> miette::Result<Box<dyn Protocol + Send + Sync + 'static>> {
147131
// Negotiate the capabilities of the backend.
148132
let capabilities = capabilities::<T>().await?;
149133
let channel_config = ChannelConfig::default_with_root_dir(
@@ -152,7 +136,11 @@ async fn initialize<T: ProtocolInstantiator>(
152136
.expect("manifest should always reside in a directory")
153137
.to_path_buf(),
154138
);
155-
let project_model = project_model_v1(manifest_path, &channel_config)?;
139+
let project_model = to_project_model(
140+
manifest_path,
141+
&channel_config,
142+
capabilities.highest_supported_project_model,
143+
)?;
156144

157145
// Check if the project model is required
158146
// and if it is not present, return an error.
@@ -189,6 +177,7 @@ async fn conda_get_metadata<T: ProtocolInstantiator>(
189177
);
190178

191179
let protocol = initialize(factory, manifest_path).await?;
180+
192181
let virtual_packages: Vec<_> = VirtualPackage::detect(&VirtualPackageOverrides::from_env())
193182
.into_diagnostic()?
194183
.into_iter()

crates/pixi-build-backend/src/dependencies.rs

Lines changed: 16 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rattler_conda_types::{
1414
ChannelConfig, MatchSpec, NamelessMatchSpec, PackageName, ParseStrictness::Strict,
1515
};
1616

17-
use crate::{build_types_ext::BinarySpecExt, variants::can_be_used_as_variant};
17+
use crate::traits::PackageSpec;
1818

1919
/// A helper struct to extract match specs from a manifest.
2020
pub struct MatchspecExtractor<'a> {
@@ -28,7 +28,7 @@ pub struct MatchspecExtractor<'a> {
2828
///
2929
/// May return an error if the path is prefixed with `~` and the home
3030
/// directory is undefined.
31-
fn resolve_path(path: &Path, root_dir: impl AsRef<Path>) -> Option<PathBuf> {
31+
pub(crate) fn resolve_path(path: &Path, root_dir: impl AsRef<Path>) -> Option<PathBuf> {
3232
if path.is_absolute() {
3333
Some(PathBuf::from(path))
3434
} else if let Ok(user_path) = path.strip_prefix("~/") {
@@ -65,16 +65,19 @@ impl<'a> MatchspecExtractor<'a> {
6565
}
6666

6767
/// Extracts match specs from the given set of dependencies.
68-
pub fn extract<'b>(
68+
pub fn extract<'b, S>(
6969
&self,
70-
dependencies: impl IntoIterator<Item = (&'b pbt::SourcePackageName, &'b pbt::PackageSpecV1)>,
71-
) -> miette::Result<Vec<MatchSpec>> {
70+
dependencies: impl IntoIterator<Item = (&'b pbt::SourcePackageName, &'b S)>,
71+
) -> miette::Result<Vec<MatchSpec>>
72+
where
73+
S: PackageSpec + 'b,
74+
{
7275
let root_dir = &self.channel_config.root_dir;
7376
let mut specs = Vec::new();
7477
for (name, spec) in dependencies.into_iter() {
7578
let name = PackageName::from_str(name.as_str()).into_diagnostic()?;
7679
// If we have a variant override, we should use that instead of the spec.
77-
if can_be_used_as_variant(spec) {
80+
if spec.can_be_used_as_variant() {
7881
if let Some(variant_value) = self
7982
.variant
8083
.as_ref()
@@ -94,47 +97,7 @@ impl<'a> MatchspecExtractor<'a> {
9497
}
9598

9699
// Match on supported packages
97-
let match_spec = match spec {
98-
pbt::PackageSpecV1::Binary(binary_spec) => {
99-
let match_spec = if binary_spec.version == Some("*".parse().unwrap()) {
100-
// Skip dependencies with wildcard versions.
101-
name.as_normalized()
102-
.to_string()
103-
.parse::<MatchSpec>()
104-
.into_diagnostic()
105-
} else {
106-
Ok(MatchSpec::from_nameless(
107-
binary_spec.to_nameless(),
108-
Some(name),
109-
))
110-
};
111-
match_spec
112-
}
113-
pbt::PackageSpecV1::Source(source_spec) => match source_spec {
114-
pbt::SourcePackageSpecV1::Path(path) => {
115-
let path =
116-
resolve_path(Path::new(&path.path), root_dir).ok_or_else(|| {
117-
miette::miette!("failed to resolve home dir for: {}", path.path)
118-
})?;
119-
if self.ignore_self && path.as_path() == root_dir.as_path() {
120-
// Skip source dependencies that point to the root directory. That would
121-
// be a self reference.
122-
continue;
123-
} else {
124-
// All other source dependencies are not yet supported.
125-
return Err(miette::miette!(
126-
"recursive source dependencies are not yet supported"
127-
));
128-
}
129-
}
130-
_ => {
131-
// All other source dependencies are not yet supported.
132-
return Err(miette::miette!(
133-
"recursive source dependencies are not yet supported"
134-
));
135-
}
136-
},
137-
}?;
100+
let match_spec = spec.to_match_spec(name, root_dir, self.ignore_self)?;
138101

139102
specs.push(match_spec);
140103
}
@@ -143,11 +106,14 @@ impl<'a> MatchspecExtractor<'a> {
143106
}
144107
}
145108

146-
pub fn extract_dependencies<'a>(
109+
pub fn extract_dependencies<'a, T>(
147110
channel_config: &ChannelConfig,
148-
dependencies: impl IntoIterator<Item = (&'a pbt::SourcePackageName, &'a pbt::PackageSpecV1)>,
111+
dependencies: impl IntoIterator<Item = (&'a pbt::SourcePackageName, &'a T)>,
149112
variant: &BTreeMap<NormalizedKey, Variable>,
150-
) -> miette::Result<Vec<Dependency>> {
113+
) -> miette::Result<Vec<Dependency>>
114+
where
115+
T: PackageSpec + 'a,
116+
{
151117
Ok(MatchspecExtractor::new(channel_config)
152118
.with_ignore_self(true)
153119
.with_variant(variant)

crates/pixi-build-backend/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ pub mod cli;
22
pub mod protocol;
33
pub mod server;
44

5-
mod build_types_ext;
65
mod consts;
76
pub mod dependencies;
7+
pub mod project;
88
pub mod source;
99
pub mod tools;
10+
pub mod traits;
1011
pub mod utils;
1112
pub mod variants;
1213

13-
pub use build_types_ext::{AnyVersion, TargetExt, TargetSelectorExt};
14+
pub use traits::{PackageSpec, ProjectModel, TargetSelector, Targets};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use std::path::Path;
2+
3+
use miette::IntoDiagnostic;
4+
use pixi_build_type_conversions::to_project_model_v1;
5+
use pixi_build_types::VersionedProjectModel;
6+
use rattler_conda_types::ChannelConfig;
7+
8+
/// Convert manifest to project model
9+
pub fn to_project_model(
10+
manifest_path: &Path,
11+
channel_config: &ChannelConfig,
12+
highest_supported_project_model: Option<u32>,
13+
) -> miette::Result<Option<VersionedProjectModel>> {
14+
// Load the manifest
15+
let manifest =
16+
pixi_manifest::Manifests::from_workspace_manifest_path(manifest_path.to_path_buf())?;
17+
let package = manifest.value.package.as_ref();
18+
19+
// Determine which project model version to use
20+
let version_to_use = match highest_supported_project_model {
21+
// If a specific version is requested, use it (or fail if it's higher than what we support)
22+
Some(requested_version) => {
23+
let our_highest = VersionedProjectModel::highest_version();
24+
if requested_version > our_highest {
25+
miette::bail!(
26+
"Requested project model version {} is higher than our highest supported version {}",
27+
requested_version,
28+
our_highest
29+
);
30+
}
31+
// Use the requested version
32+
requested_version
33+
}
34+
// If no specific version is requested, use our highest supported version
35+
None => VersionedProjectModel::highest_version(),
36+
};
37+
38+
// This can be null in the rattler-build backend
39+
let versioned = package
40+
.map(|manifest| {
41+
let result = match version_to_use {
42+
1 => to_project_model_v1(&manifest.value, channel_config).into_diagnostic()?,
43+
_ => {
44+
miette::bail!(
45+
"Unsupported project model version: {}",
46+
VersionedProjectModel::highest_version()
47+
);
48+
}
49+
};
50+
Ok(VersionedProjectModel::from(result))
51+
})
52+
.transpose()?;
53+
54+
Ok(versioned)
55+
}

crates/pixi-build-backend/src/protocol.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ use pixi_build_types::procedures::{
99
/// and endpoint that can handle the RPC calls.
1010
#[async_trait::async_trait]
1111
pub trait ProtocolInstantiator: Send + Sync + 'static {
12-
/// The endpoint implements the protocol RPC methods
13-
type ProtocolEndpoint: Protocol + Send + Sync + 'static;
14-
1512
/// Called when negotiating capabilities with the client.
1613
/// This is determine how the rest of the initialization will proceed.
1714
async fn negotiate_capabilities(
@@ -23,7 +20,7 @@ pub trait ProtocolInstantiator: Send + Sync + 'static {
2320
async fn initialize(
2421
&self,
2522
params: InitializeParams,
26-
) -> miette::Result<(Self::ProtocolEndpoint, InitializeResult)>;
23+
) -> miette::Result<(Box<dyn Protocol + Send + Sync + 'static>, InitializeResult)>;
2724
}
2825

2926
/// A trait that defines the protocol for a pixi build backend.

0 commit comments

Comments
 (0)