Skip to content
Open
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_cli/src/publish/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
env_ref: env_ref.clone(),
inline: None,
installed_source_hints: Default::default(),
workspace_sources: Default::default(),
};
let records = command_dispatcher
.engine()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ pub struct ResolveSourcePackageSpec {
/// solves with the previous resolution's `build_packages` /
/// `host_packages`; all other hints flow through for deeper layers.
pub installed_source_hints: PtrArc<InstalledSourceHints>,
/// Source dependencies declared across the workspace, forwarded to nested
/// build/host environment solves.
pub workspace_sources: Arc<BTreeMap<PackageName, SourceLocationSpec>>,
}

/// Compute-engine Key returning every variant's assembled
Expand Down Expand Up @@ -178,6 +181,7 @@ async fn resolve_source_package_inner(
let preferred = Arc::clone(&spec.preferred_build_source);
let env_ref = spec.env_ref.clone();
let source_hints = spec.installed_source_hints.clone();
let workspace_sources = Arc::clone(&spec.workspace_sources);
// Fold the inline definition's content hash into each assembled record's
// identifier so editing the inline table changes the lock entry.
let inline_content_hash = spec.inline.as_ref().map(|inline| inline.content_hash);
Expand All @@ -191,6 +195,7 @@ async fn resolve_source_package_inner(
&env_ref,
&source_hints,
inline_content_hash,
&workspace_sources,
)
.await
},
Expand Down
67 changes: 54 additions & 13 deletions crates/pixi_command_dispatcher/src/keys/resolve_source_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use pixi_compute_reporters::OperationId;
use pixi_record::{
FullSourceRecordData, PinnedSourceSpec, PixiRecord, SourceRecord, UnresolvedPixiRecord,
};
use pixi_spec::{BinarySpec, PixiSpec, SourceAnchor, SourceLocationSpec};
use pixi_spec::{
BinarySpec, MatchspecFields, PixiSpec, SourceAnchor, SourceLocationSpec, SourceSpec,
};
use pixi_spec_containers::DependencyMap;
use pixi_variant::VariantValue;
use rattler_conda_types::{PackageName, PackageRecord, Platform, package::RunExportsJson};
Expand Down Expand Up @@ -48,6 +50,7 @@ use pixi_manifest::InlineContentHash;
/// in the subtree remain visible.
///
/// Reports progress via `Arc<dyn SourceRecordReporter>` set on the engine `DataStore`, if any.
#[allow(clippy::too_many_arguments)]
pub(super) async fn assemble_source_record(
ctx: &mut ComputeCtx,
source: &PinnedSourceCodeLocation,
Expand All @@ -56,6 +59,7 @@ pub(super) async fn assemble_source_record(
env_ref: &EnvironmentRef,
installed_source_hints: &PtrArc<InstalledSourceHints>,
inline_content_hash: Option<InlineContentHash>,
workspace_sources: &Arc<BTreeMap<PackageName, SourceLocationSpec>>,
) -> Result<Arc<SourceRecord>, SourceRecordError> {
// Reporter lifecycle for this variant's source-record assembly.
// Build a `SourceRecordReporterSpec` from the data flowing through here so
Expand Down Expand Up @@ -101,14 +105,15 @@ pub(super) async fn assemble_source_record(
env_ref,
installed_source_hints,
inline_content_hash,
workspace_sources,
);
match active_id {
Some(id) => id.scope_active(work).await,
None => work.await,
}
}

#[allow(clippy::result_large_err)]
#[allow(clippy::result_large_err, clippy::too_many_arguments)]
async fn assemble_source_record_inner(
ctx: &mut ComputeCtx,
source: &PinnedSourceCodeLocation,
Expand All @@ -117,6 +122,7 @@ async fn assemble_source_record_inner(
env_ref: &EnvironmentRef,
installed_source_hints: &PtrArc<InstalledSourceHints>,
inline_content_hash: Option<InlineContentHash>,
workspace_sources: &Arc<BTreeMap<PackageName, SourceLocationSpec>>,
) -> Result<Arc<SourceRecord>, SourceRecordError> {
let source_location = SourceLocationSpec::from(source.manifest_source().clone());
let source_anchor = SourceAnchor::from(source_location.clone());
Expand Down Expand Up @@ -157,6 +163,7 @@ async fn assemble_source_record_inner(
build_dependencies.clone(),
Arc::clone(&installed_build_packages),
installed_source_hints,
workspace_sources,
)
.await?;

Expand Down Expand Up @@ -201,6 +208,7 @@ async fn assemble_source_record_inner(
host_dependencies.clone(),
Arc::clone(&installed_host_packages),
installed_source_hints,
workspace_sources,
)
.await?;

Expand Down Expand Up @@ -343,12 +351,21 @@ async fn assemble_source_record_inner(
let implied_location = match withspec.value.clone().into_source_or_binary() {
Either::Left(source) if withspec.source.is_some() => Some(source.location),
Either::Left(_) => None,
Either::Right(_) => compatibility_map.get(&name).and_then(|r| match r {
PixiRecord::Source(source) => {
Some(SourceLocationSpec::from(source.manifest_source().clone()))
}
PixiRecord::Binary(_) => None,
}),
Either::Right(_) => compatibility_map
.get(&name)
.and_then(|r| match r {
PixiRecord::Source(source) => {
Some(SourceLocationSpec::from(source.manifest_source().clone()))
}
PixiRecord::Binary(_) => None,
})
.or_else(|| {
if name != pkg_name {
workspace_sources.get(&name).cloned()
} else {
None
}
}),
};
if let Some(location) =
implied_location.and_then(|loc| source_anchor.relativize_location(loc))
Expand Down Expand Up @@ -516,6 +533,7 @@ async fn nested_solve(
dependencies: Dependencies,
installed: Arc<[UnresolvedPixiRecord]>,
installed_source_hints: &PtrArc<InstalledSourceHints>,
workspace_sources: &Arc<BTreeMap<PackageName, SourceLocationSpec>>,
) -> Result<Vec<PixiRecord>, SourceRecordError> {
if dependencies.dependencies.is_empty() {
return Ok(vec![]);
Expand All @@ -534,13 +552,35 @@ async fn nested_solve(
.await
.host_platform;
let installed = installed_records_for_platform(installed, host_platform);
let channel_config = ctx.compute(&ChannelConfigKey).await;

let mapped_dependencies: DependencyMap<PackageName, PixiSpec> = dependencies
.dependencies
.into_specs()
.map(|(name, withspec)| {
let spec = match withspec.value.into_source_or_binary() {
Either::Right(binary)
if &name != pkg_name
&& let Some(source_location) = workspace_sources.get(&name) =>
{
let matchspec = binary
.try_into_nameless_match_spec(&channel_config)
.map(|nameless| MatchspecFields::from_nameless_match_spec(&nameless))
.unwrap_or_default();
PixiSpec::from(SourceSpec {
location: source_location.clone(),
matchspec,
})
}
Either::Left(source) => PixiSpec::from(source),
Either::Right(binary) => PixiSpec::from(binary),
};
(name, spec)
})
.collect();

let nested_spec = SolvePixiEnvironmentSpec {
dependencies: dependencies
.dependencies
.into_specs()
.map(|(name, withspec)| (name, withspec.value))
.collect(),
dependencies: mapped_dependencies,
constraints: dependencies
.constraints
.into_specs()
Expand All @@ -560,6 +600,7 @@ async fn nested_solve(
// A nested build/host env solves binary/source build deps; inline
// definitions apply only to the consumer's direct dependencies.
inline_packages: Default::default(),
workspace_sources: Arc::clone(workspace_sources),
};

// Wrap the nested SolvePixiEnvironmentKey call in a cycle
Expand Down
37 changes: 35 additions & 2 deletions crates/pixi_command_dispatcher/src/keys/solve_pixi_environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ pub struct SolvePixiEnvironmentSpec {
/// instead of discovering one on disk. Their content hashes are part of the
/// key identity.
pub inline_packages: Arc<BTreeMap<PackageName, InlinePackage>>,
/// Source dependencies declared across the workspace. When a nested
/// build/host solve encounters a required package whose name matches an entry
/// here, it resolves it from source rather than searching remote conda channels.
pub workspace_sources: Arc<BTreeMap<PackageName, SourceLocationSpec>>,
}

impl Hash for SolvePixiEnvironmentSpec {
Expand All @@ -145,6 +149,7 @@ impl Hash for SolvePixiEnvironmentSpec {
preferred_build_source,
env_ref,
inline_packages,
workspace_sources,
} = self;
dependencies.hash(state);
constraints.hash(state);
Expand All @@ -155,6 +160,7 @@ impl Hash for SolvePixiEnvironmentSpec {
preferred_build_source.hash(state);
env_ref.hash(state);
inline_packages.hash(state);
workspace_sources.hash(state);
}
}

Expand All @@ -170,6 +176,7 @@ impl PartialEq for SolvePixiEnvironmentSpec {
&& self.preferred_build_source == other.preferred_build_source
&& self.env_ref == other.env_ref
&& self.inline_packages == other.inline_packages
&& self.workspace_sources == other.workspace_sources
}
}

Expand Down Expand Up @@ -342,6 +349,19 @@ async fn compute_inner(
)
.collect();

let workspace_sources = if spec.workspace_sources.is_empty() {
let mut map = BTreeMap::new();
for (name, spec) in source_specs.iter_specs() {
map.insert(name.clone(), spec.location.clone());
}
for (name, dev_spec) in spec.dev_sources.iter() {
map.insert(name.clone(), dev_spec.source.clone());
}
Arc::new(map)
} else {
Arc::clone(&spec.workspace_sources)
};

// Source-record hints for this solve. Keyed on
// `(PackageName, SourceLocationSpec)`; the same `Arc` flows
// through every nested solve so a given source package gets the
Expand All @@ -355,6 +375,7 @@ async fn compute_inner(
&spec.env_ref,
&spec.preferred_build_source,
&spec.installed_source_hints,
&workspace_sources,
)
.await?;
tracing::debug!(
Expand Down Expand Up @@ -485,6 +506,7 @@ async fn walk_and_resolve(
env_ref: &EnvironmentRef,
preferred_build_source: &Arc<BTreeMap<PackageName, PinnedSourceSpec>>,
installed_source_hints: &PtrArc<InstalledSourceHints>,
workspace_sources: &Arc<BTreeMap<PackageName, SourceLocationSpec>>,
) -> Result<Vec<Arc<pixi_record::SourceRecord>>, SolvePixiEnvironmentError> {
let mut all_records: Vec<Arc<pixi_record::SourceRecord>> = Vec::new();
let mut seen_sources: HashSet<(PackageName, SourceLocationSpec)> = HashSet::new();
Expand Down Expand Up @@ -522,6 +544,7 @@ async fn walk_and_resolve(
env_ref: env_ref.clone(),
inline,
installed_source_hints: installed_source_hints.clone(),
workspace_sources: Arc::clone(workspace_sources),
});
pending.push(p.compute(async move |sub_ctx: &mut ComputeCtx| {
// Per-push cycle guard. `sub_ctx` has a branch-local
Expand Down Expand Up @@ -621,8 +644,18 @@ async fn walk_and_resolve(
let PackageNameMatcher::Exact(child_name) = name_matcher else {
continue;
};
if let Some(source_location) = record.sources().get(child_name.as_normalized()) {
let resolved_location = anchor.resolve_location(source_location.clone());
let maybe_location = record
.sources()
.get(child_name.as_normalized())
.map(|source_location| anchor.resolve_location(source_location.clone()))
.or_else(|| {
if child_name != parent_pkg {
workspace_sources.get(&child_name).cloned()
} else {
None
}
});
if let Some(resolved_location) = maybe_location {
push(
&mut p,
&mut pending,
Expand Down
Loading
Loading