use crate::{
CondaPackageData, UrlOrPath,
conda::{CondaBinaryData, CondaSourceData, PackageBuildSource, SourceMetadata, VariantValue},
source::SourceLocation,
};
use rattler_conda_types::{ChannelUrl, PackageRecord, package::DistArchiveIdentifier};
use std::{borrow::Cow, collections::BTreeMap};
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub(crate) enum LegacyCondaPackageData {
Binary(LegacyCondaBinaryData),
Source(LegacyCondaSourceData),
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub(crate) struct LegacyCondaBinaryData {
pub package_record: PackageRecord,
pub location: UrlOrPath,
pub file_name: String,
pub channel: Option<ChannelUrl>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub(crate) struct LegacyCondaSourceData {
pub package_record: PackageRecord,
pub location: UrlOrPath,
pub variants: BTreeMap<String, VariantValue>,
pub package_build_source: Option<PackageBuildSource>,
pub sources: BTreeMap<String, SourceLocation>,
}
impl LegacyCondaPackageData {
pub fn location(&self) -> &UrlOrPath {
match self {
Self::Binary(data) => &data.location,
Self::Source(data) => &data.location,
}
}
pub fn record(&self) -> &PackageRecord {
match self {
Self::Binary(data) => &data.package_record,
Self::Source(data) => &data.package_record,
}
}
pub fn merge(&self, other: &Self) -> Cow<'_, Self> {
match (self, other) {
(Self::Binary(left), Self::Binary(right)) if left.location == right.location => {
if let Cow::Owned(merged) =
merge_package_record(&left.package_record, &right.package_record)
{
return Cow::Owned(Self::Binary(LegacyCondaBinaryData {
package_record: merged,
location: left.location.clone(),
file_name: left.file_name.clone(),
channel: left.channel.clone(),
}));
}
}
(Self::Source(left), Self::Source(right)) if left.location == right.location => {
let record_merge =
merge_package_record(&left.package_record, &right.package_record);
let build_source_merge = merge_package_build_source(
&left.package_build_source,
&right.package_build_source,
);
if matches!(record_merge, Cow::Owned(_))
|| matches!(build_source_merge, Cow::Owned(_))
{
return Cow::Owned(Self::Source(LegacyCondaSourceData {
package_record: record_merge.into_owned(),
location: left.location.clone(),
variants: left.variants.clone(),
package_build_source: build_source_merge.into_owned(),
sources: left.sources.clone(),
}));
}
}
_ => {}
}
Cow::Borrowed(self)
}
}
impl From<LegacyCondaPackageData> for CondaPackageData {
fn from(value: LegacyCondaPackageData) -> Self {
match value {
LegacyCondaPackageData::Binary(data) => {
let file_id = DistArchiveIdentifier::try_from_filename(&data.file_name)
.expect("This file name must be valid here");
CondaPackageData::Binary(Box::new(CondaBinaryData {
package_record: data.package_record,
location: data.location,
file_name: file_id,
channel: data.channel,
}))
}
LegacyCondaPackageData::Source(data) => {
CondaPackageData::Source(Box::new(CondaSourceData {
location: data.location,
package_build_source: data.package_build_source,
variants: data.variants,
identifier_hash: None,
sources: data.sources,
source_data: crate::SourceData::default(),
metadata: SourceMetadata::Full(Box::new(data.package_record)),
}))
}
}
}
}
fn merge_package_record<'a>(
left: &'a PackageRecord,
right: &PackageRecord,
) -> Cow<'a, PackageRecord> {
let needs_purls = left.purls.is_none() && right.purls.is_some();
let needs_run_exports = left.run_exports.is_none() && right.run_exports.is_some();
let needs_md5 = left.md5.is_none() && right.md5.is_some();
let needs_sha256 = left.sha256.is_none() && right.sha256.is_some();
if !needs_purls && !needs_run_exports && !needs_md5 && !needs_sha256 {
return Cow::Borrowed(left);
}
let mut merged = left.clone();
if needs_purls {
merged.purls.clone_from(&right.purls);
}
if needs_run_exports {
merged.run_exports.clone_from(&right.run_exports);
}
if needs_md5 {
merged.md5 = right.md5;
}
if needs_sha256 {
merged.sha256 = right.sha256;
}
Cow::Owned(merged)
}
fn merge_package_build_source<'a>(
left: &'a Option<PackageBuildSource>,
right: &Option<PackageBuildSource>,
) -> Cow<'a, Option<PackageBuildSource>> {
if left == right {
Cow::Borrowed(left)
} else if let Some(right_source) = right {
Cow::Owned(Some(right_source.clone()))
} else {
Cow::Borrowed(left)
}
}