diff --git a/crates/rattler_lock/src/conda.rs b/crates/rattler_lock/src/conda.rs index a116eceb3..245e643cd 100644 --- a/crates/rattler_lock/src/conda.rs +++ b/crates/rattler_lock/src/conda.rs @@ -1,6 +1,7 @@ use std::{cmp::Ordering, hash::Hash}; use rattler_conda_types::{PackageRecord, RepoDataRecord}; +use rattler_digest::Sha256Hash; use url::Url; use crate::UrlOrPath; @@ -21,6 +22,20 @@ pub struct CondaPackageData { /// The channel of the package if this cannot be derived from the url. pub channel: Option, + + /// The input hash of the package (only valid for source packages) + pub input: Option, +} + +/// A record of input files that were used to define the metadata of the +/// package. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct InputHash { + /// The hash of all input files combined. + pub hash: Sha256Hash, + + /// The globs that were used to define the input files. + pub globs: Vec, } impl AsRef for CondaPackageData { @@ -58,6 +73,7 @@ impl From for CondaPackageData { file_name: Some(value.file_name), channel: Url::parse(&value.channel).ok(), location, + input: None, } } } diff --git a/crates/rattler_lock/src/lib.rs b/crates/rattler_lock/src/lib.rs index cc11d65cf..e0282e95e 100644 --- a/crates/rattler_lock/src/lib.rs +++ b/crates/rattler_lock/src/lib.rs @@ -96,7 +96,7 @@ mod utils; pub use builder::LockFileBuilder; pub use channel::Channel; -pub use conda::{CondaPackageData, ConversionError}; +pub use conda::{CondaPackageData, ConversionError, InputHash}; pub use file_format_version::FileFormatVersion; pub use hash::PackageHashes; pub use parse::ParseCondaLockError; diff --git a/crates/rattler_lock/src/parse/models/v5/conda_package_data.rs b/crates/rattler_lock/src/parse/models/v5/conda_package_data.rs index 9a559c86b..165e2c3ae 100644 --- a/crates/rattler_lock/src/parse/models/v5/conda_package_data.rs +++ b/crates/rattler_lock/src/parse/models/v5/conda_package_data.rs @@ -93,6 +93,7 @@ impl<'a> From> for CondaPackageData { let (derived_arch, derived_platform) = derive_arch_and_platform(&subdir); Self { + input: None, package_record: PackageRecord { build: value.build.into_owned(), build_number: value.build_number, diff --git a/crates/rattler_lock/src/parse/models/v6/conda_package_data.rs b/crates/rattler_lock/src/parse/models/v6/conda_package_data.rs index fbd13f92a..36b38ad56 100644 --- a/crates/rattler_lock/src/parse/models/v6/conda_package_data.rs +++ b/crates/rattler_lock/src/parse/models/v6/conda_package_data.rs @@ -9,6 +9,7 @@ use serde_with::serde_as; use url::Url; use crate::{ + conda::InputHash, utils::{derived_fields, derived_fields::LocationDerivedFields}, CondaPackageData, ConversionError, UrlOrPath, }; @@ -62,6 +63,9 @@ pub(crate) struct CondaPackageDataModel<'a> { #[serde_as(as = "Option>")] pub md5: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde_as(as = "Option>")] + pub hash: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option>")] pub legacy_bz2_md5: Option, @@ -103,6 +107,9 @@ pub(crate) struct CondaPackageDataModel<'a> { #[serde(default, skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option")] pub timestamp: Option>, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub input: Option>>, } impl<'a> TryFrom> for CondaPackageData { @@ -135,7 +142,17 @@ impl<'a> TryFrom> for CondaPackageData { ); let (derived_arch, derived_platform) = derived_fields::derive_arch_and_platform(&subdir); + let input_hash = if value.hash.is_some() || value.input.is_some() { + Some(InputHash { + hash: value.hash.unwrap_or_default(), + globs: value.input.map_or_else(Vec::new, Cow::into_owned), + }) + } else { + None + }; + Ok(Self { + input: input_hash, package_record: PackageRecord { build, build_number, @@ -234,6 +251,8 @@ impl<'a> From<&'a CondaPackageData> for CondaPackageDataModel<'a> { track_features: Cow::Borrowed(&value.package_record.track_features), license: Cow::Borrowed(&value.package_record.license), license_family: Cow::Borrowed(&value.package_record.license_family), + hash: value.input.as_ref().map(|r| r.hash), + input: value.input.as_ref().map(|r| Cow::Borrowed(&r.globs)), } } } diff --git a/crates/rattler_lock/src/parse/v3.rs b/crates/rattler_lock/src/parse/v3.rs index 4686feae8..dadd3409e 100644 --- a/crates/rattler_lock/src/parse/v3.rs +++ b/crates/rattler_lock/src/parse/v3.rs @@ -186,6 +186,7 @@ pub fn parse_v3_or_lower( let deduplicated_idx = conda_packages .insert_full(CondaPackageData { + input: None, package_record: PackageRecord { arch: value.arch.or(derived_arch), build,