Skip to content

Commit 1a4df75

Browse files
authored
feat: use command dispatcher for pixi build (#4156)
1 parent d5e6c45 commit 1a4df75

File tree

30 files changed

+604
-535
lines changed

30 files changed

+604
-535
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,6 @@ pixi_allocator = { workspace = true, optional = true }
301301
pixi_build_discovery = { workspace = true }
302302
pixi_build_frontend = { workspace = true }
303303
pixi_build_type_conversions = { workspace = true }
304-
pixi_build_types = { workspace = true }
305304
pixi_command_dispatcher = { workspace = true }
306305
pixi_config = { workspace = true }
307306
pixi_consts = { workspace = true }

crates/pixi_command_dispatcher/src/backend_source_build/mod.rs

Lines changed: 51 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ use pixi_build_types::{
2020
},
2121
},
2222
};
23-
use pixi_record::SourceRecord;
23+
use pixi_record::PinnedSourceSpec;
2424
use rattler_conda_types::{ChannelConfig, ChannelUrl, Platform, Version};
2525
use serde::Serialize;
2626
use thiserror::Error;
2727

28-
use crate::{BuildEnvironment, CommandDispatcher, CommandDispatcherError, build::WorkDirKey};
28+
use crate::{BuildEnvironment, CommandDispatcherError, PackageIdentifier};
2929

3030
/// The `BackendSourceBuildSpec` struct is used to define the specifications for
3131
/// building a source package using a pre-instantiated backend. This task
@@ -40,10 +40,16 @@ pub struct BackendSourceBuildSpec {
4040
pub backend: Backend,
4141

4242
/// The package that we are building.
43-
pub record: SourceRecord,
43+
pub package: PackageIdentifier,
44+
45+
/// The source location of the package that we are building.
46+
pub source: PinnedSourceSpec,
4447

4548
/// The method to use for building the source package.
4649
pub method: BackendSourceBuildMethod,
50+
51+
/// The working directory to use for the build.
52+
pub work_directory: PathBuf,
4753
}
4854

4955
#[derive(Debug, Serialize)]
@@ -115,27 +121,28 @@ pub struct BackendBuiltSource {
115121
impl BackendSourceBuildSpec {
116122
pub async fn build(
117123
self,
118-
command_dispatcher: CommandDispatcher,
119124
log_sink: UnboundedSender<String>,
120125
) -> Result<BackendBuiltSource, CommandDispatcherError<BackendSourceBuildError>> {
121126
match self.method {
122127
BackendSourceBuildMethod::BuildV0(params) => {
123128
Self::build_v0(
124129
self.backend,
125-
self.record,
130+
self.package,
131+
self.source,
126132
params,
133+
self.work_directory,
127134
log_sink,
128-
command_dispatcher,
129135
)
130136
.await
131137
}
132138
BackendSourceBuildMethod::BuildV1(params) => {
133139
Self::build_v1(
134140
self.backend,
135-
self.record,
141+
self.package,
142+
self.source,
136143
params,
144+
self.work_directory,
137145
log_sink,
138-
command_dispatcher,
139146
)
140147
.await
141148
}
@@ -144,10 +151,11 @@ impl BackendSourceBuildSpec {
144151

145152
async fn build_v0(
146153
backend: Backend,
147-
record: SourceRecord,
154+
record: PackageIdentifier,
155+
source: PinnedSourceSpec,
148156
params: BackendSourceBuildV0Method,
157+
work_directory: PathBuf,
149158
mut log_sink: UnboundedSender<String>,
150-
command_dispatcher: CommandDispatcher,
151159
) -> Result<BackendBuiltSource, CommandDispatcherError<BackendSourceBuildError>> {
152160
// Use the backend to build the source package.
153161
let mut build_result = backend
@@ -161,29 +169,22 @@ impl BackendSourceBuildSpec {
161169
base_url: params.channel_config.channel_alias.clone(),
162170
},
163171
outputs: Some(BTreeSet::from_iter([CondaOutputIdentifier {
164-
name: Some(record.package_record.name.as_normalized().to_string()),
165-
version: Some(record.package_record.version.to_string()),
166-
build: Some(record.package_record.build.clone()),
167-
subdir: Some(record.package_record.subdir.clone()),
172+
name: Some(record.name.as_normalized().to_string()),
173+
version: Some(record.version.to_string()),
174+
build: Some(record.build.clone()),
175+
subdir: Some(record.subdir.clone()),
168176
}])),
169177
variant_configuration: params
170178
.variants
171179
.map(|variants| variants.into_iter().collect()),
172-
work_directory: command_dispatcher.cache_dirs().working_dirs().join(
173-
WorkDirKey {
174-
source: Box::new(record.clone()).into(),
175-
host_platform: params.build_environment.host_platform,
176-
build_backend: backend.identifier().to_string(),
177-
}
178-
.key(),
179-
),
180+
work_directory,
180181
host_platform: Some(PlatformAndVirtualPackages {
181182
platform: params.build_environment.host_platform,
182183
virtual_packages: Some(
183184
params.build_environment.host_virtual_packages.clone(),
184185
),
185186
}),
186-
editable: !record.source.is_immutable(),
187+
editable: source.is_mutable(),
187188
},
188189
move |line| {
189190
let _err = futures::executor::block_on(log_sink.send(line));
@@ -206,8 +207,8 @@ impl BackendSourceBuildSpec {
206207
});
207208
tracing::warn!(
208209
"While building {} for {}, the build backend returned more packages than expected: {pkgs}. Only the package matching the source record will be used.",
209-
record.source,
210-
record.package_record.subdir,
210+
source,
211+
record.subdir,
211212
);
212213
}
213214

@@ -221,10 +222,10 @@ impl BackendSourceBuildSpec {
221222
} else {
222223
return Err(CommandDispatcherError::Failed(
223224
BackendSourceBuildError::UnexpectedPackage(UnexpectedPackageError {
224-
subdir: record.package_record.subdir.clone(),
225-
name: record.package_record.name.as_normalized().to_string(),
226-
version: record.package_record.version.to_string(),
227-
build: record.package_record.build.clone(),
225+
subdir: record.subdir.clone(),
226+
name: record.name.as_normalized().to_string(),
227+
version: record.version.to_string(),
228+
build: record.build.clone(),
228229
packages: build_result
229230
.packages
230231
.iter()
@@ -250,20 +251,12 @@ impl BackendSourceBuildSpec {
250251

251252
async fn build_v1(
252253
backend: Backend,
253-
record: SourceRecord,
254+
record: PackageIdentifier,
255+
source: PinnedSourceSpec,
254256
params: BackendSourceBuildV1Method,
257+
work_directory: PathBuf,
255258
mut log_sink: UnboundedSender<String>,
256-
command_dispatcher: CommandDispatcher,
257259
) -> Result<BackendBuiltSource, CommandDispatcherError<BackendSourceBuildError>> {
258-
let work_directory = command_dispatcher.cache_dirs().working_dirs().join(
259-
WorkDirKey {
260-
source: Box::new(record.clone()).into(),
261-
host_platform: params.host_prefix.platform,
262-
build_backend: backend.identifier().to_string(),
263-
}
264-
.key(),
265-
);
266-
267260
let built_package = backend
268261
.conda_build_v1(
269262
CondaBuildV1Params {
@@ -276,19 +269,18 @@ impl BackendSourceBuildSpec {
276269
platform: params.host_prefix.platform,
277270
}),
278271
output: CondaBuildV1Output {
279-
name: record.package_record.name.clone(),
280-
version: Some(record.package_record.version.clone()),
281-
build: Some(record.package_record.build.clone()),
272+
name: record.name.clone(),
273+
version: Some(record.version.clone()),
274+
build: Some(record.build.clone()),
282275
subdir: record
283-
.package_record
284276
.subdir
285277
.parse()
286278
.expect("found a package record with an unparsable subdir"),
287279
variant: params.variant,
288280
},
289281
work_directory,
290282
output_directory: params.output_directory,
291-
editable: Some(!record.source.is_immutable()),
283+
editable: Some(source.is_mutable()),
292284
},
293285
move |line| {
294286
let _err = futures::executor::block_on(log_sink.send(line));
@@ -302,10 +294,10 @@ impl BackendSourceBuildSpec {
302294
if v1_built_package_matches_requested(&built_package, &record) {
303295
return Err(CommandDispatcherError::Failed(
304296
BackendSourceBuildError::UnexpectedPackage(UnexpectedPackageError {
305-
subdir: record.package_record.subdir.clone(),
306-
name: record.package_record.name.as_normalized().to_string(),
307-
version: record.package_record.version.to_string(),
308-
build: record.package_record.build.clone(),
297+
subdir: record.subdir.clone(),
298+
name: record.name.as_normalized().to_string(),
299+
version: record.version.to_string(),
300+
build: record.build.clone(),
309301
packages: vec![format!(
310302
"{}/{}={}={}",
311303
built_package.subdir,
@@ -326,23 +318,23 @@ impl BackendSourceBuildSpec {
326318

327319
/// Returns true if the requested package matches the one that was built by a
328320
/// backend.
329-
fn v0_built_package_matches_request(record: &SourceRecord, pkg: &&CondaBuiltPackage) -> bool {
330-
pkg.name == record.package_record.name
331-
&& Version::from_str(&pkg.version).ok().as_ref() == Some(&record.package_record.version)
332-
&& pkg.build == record.package_record.build
333-
&& pkg.subdir == record.package_record.subdir
321+
fn v0_built_package_matches_request(record: &PackageIdentifier, pkg: &&CondaBuiltPackage) -> bool {
322+
pkg.name == record.name
323+
&& Version::from_str(&pkg.version).ok().as_ref() == Some(&record.version)
324+
&& pkg.build == record.build
325+
&& pkg.subdir == record.subdir
334326
}
335327

336328
/// Returns true if the requested package matches the one that was built by a
337329
/// backend.
338330
fn v1_built_package_matches_requested(
339331
built_package: &CondaBuildV1Result,
340-
record: &SourceRecord,
332+
record: &PackageIdentifier,
341333
) -> bool {
342-
built_package.name != record.package_record.name.as_normalized()
343-
|| built_package.version != record.package_record.version
344-
|| built_package.build != record.package_record.build
345-
|| built_package.subdir.as_str() != record.package_record.subdir
334+
built_package.name != record.name.as_normalized()
335+
|| built_package.version != record.version
336+
|| built_package.build != record.build
337+
|| built_package.subdir.as_str() != record.subdir
346338
}
347339

348340
#[derive(Debug, thiserror::Error, Diagnostic)]

crates/pixi_command_dispatcher/src/build/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use dependencies::{Dependencies, DependenciesError, PixiRunExports};
1919
pub(crate) use move_file::{MoveError, move_file};
2020
use pixi_record::PinnedSourceSpec;
2121
use url::Url;
22-
pub use work_dir_key::WorkDirKey;
22+
pub use work_dir_key::{SourceRecordOrCheckout, WorkDirKey};
2323
use xxhash_rust::xxh3::Xxh3;
2424

2525
const KNOWN_SUFFIXES: [&str; 3] = [".git", ".tar.gz", ".zip"];

crates/pixi_command_dispatcher/src/build/source_metadata_cache.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
1515
use thiserror::Error;
1616
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
1717

18-
use crate::{BuildEnvironment, build::source_checkout_cache_key};
18+
use crate::{BuildEnvironment, PackageIdentifier, build::source_checkout_cache_key};
1919

2020
/// A cache for caching the metadata of a source checkout.
2121
///
@@ -231,3 +231,30 @@ pub enum MetadataKind {
231231
/// The result of calling `conda/outputs` on a build backend.
232232
Outputs { outputs: Vec<CondaOutput> },
233233
}
234+
235+
impl CachedCondaMetadata {
236+
/// Returns the unique package identifiers for the packages in this
237+
/// metadata.
238+
pub fn outputs(&self) -> Vec<PackageIdentifier> {
239+
match &self.metadata {
240+
MetadataKind::GetMetadata { packages } => packages
241+
.iter()
242+
.map(|pkg| PackageIdentifier {
243+
name: pkg.name.clone(),
244+
version: pkg.version.clone(),
245+
build: pkg.build.clone(),
246+
subdir: pkg.subdir.to_string(),
247+
})
248+
.collect(),
249+
MetadataKind::Outputs { outputs } => outputs
250+
.iter()
251+
.map(|output| PackageIdentifier {
252+
name: output.metadata.name.clone(),
253+
version: output.metadata.version.clone(),
254+
build: output.metadata.build.clone(),
255+
subdir: output.metadata.subdir.to_string(),
256+
})
257+
.collect(),
258+
}
259+
}
260+
}

crates/pixi_command_dispatcher/src/build/work_dir_key.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@ use std::{
66
};
77

88
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
9-
use pixi_record::{PinnedSourceSpec, SourceRecord};
10-
use rattler_conda_types::Platform;
9+
use pixi_record::PinnedSourceSpec;
10+
use rattler_conda_types::{PackageName, Platform};
1111
use xxhash_rust::xxh3::Xxh3;
1212

1313
use crate::SourceCheckout;
1414

1515
#[derive(derive_more::From)]
1616
pub enum SourceRecordOrCheckout {
1717
/// A source record that has not been checked out yet.
18-
Record(Box<SourceRecord>),
18+
Record {
19+
pinned: PinnedSourceSpec,
20+
package_name: PackageName,
21+
},
1922

2023
/// A source checkout that has already been checked out.
21-
Checkout(Box<SourceCheckout>),
24+
Checkout { checkout: SourceCheckout },
2225
}
2326

2427
impl SourceRecordOrCheckout {
2528
pub fn pinned(&self) -> &PinnedSourceSpec {
2629
match self {
27-
SourceRecordOrCheckout::Record(record) => &record.source,
28-
SourceRecordOrCheckout::Checkout(checkout) => &checkout.pinned,
30+
SourceRecordOrCheckout::Record { pinned, .. } => pinned,
31+
SourceRecordOrCheckout::Checkout { checkout } => &checkout.pinned,
2932
}
3033
}
3134
}
@@ -55,10 +58,10 @@ impl WorkDirKey {
5558
let unique_key = URL_SAFE_NO_PAD.encode(hasher.finish().to_ne_bytes());
5659

5760
let name = match &self.source {
58-
SourceRecordOrCheckout::Record(record) => {
59-
Some(record.package_record.name.as_normalized())
61+
SourceRecordOrCheckout::Record { package_name, .. } => {
62+
Some(package_name.as_normalized())
6063
}
61-
SourceRecordOrCheckout::Checkout(checkout) => {
64+
SourceRecordOrCheckout::Checkout { checkout } => {
6265
checkout.path.file_name().and_then(OsStr::to_str)
6366
}
6467
};

0 commit comments

Comments
 (0)