From 66235f684f2cd546161165cfcaeefb5b600b103e Mon Sep 17 00:00:00 2001 From: Bas Zalmstra Date: Thu, 23 Nov 2023 15:30:12 +0100 Subject: [PATCH] feat: add purl to PackageRecord and lockfile --- crates/rattler_conda_types/Cargo.toml | 3 ++- crates/rattler_conda_types/src/lib.rs | 3 +++ crates/rattler_conda_types/src/repo_data/mod.rs | 9 ++++++++- crates/rattler_lock/src/builder.rs | 16 +++++++++++++++- crates/rattler_lock/src/conda.rs | 9 +++++++-- crates/rattler_solve/tests/backends.rs | 1 + 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/rattler_conda_types/Cargo.toml b/crates/rattler_conda_types/Cargo.toml index 400aa3719..32a987497 100644 --- a/crates/rattler_conda_types/Cargo.toml +++ b/crates/rattler_conda_types/Cargo.toml @@ -32,11 +32,12 @@ url = { version = "2.4.1", features = ["serde"] } rattler_digest = { version = "0.12.3", path = "../rattler_digest", features = ["serde"] } rattler_macros = { version = "0.12.3", path = "../rattler_macros" } glob = "0.3.1" +purl = { version = "0.1.2", features = ["serde"] } [dev-dependencies] rand = "0.8.5" insta = { version = "1.33.0", features = ["yaml", "redactions", "toml"] } -rattler_package_streaming = { path = "../rattler_package_streaming", default-features = false, features=["rustls-tls"] } +rattler_package_streaming = { path = "../rattler_package_streaming", default-features = false, features = ["rustls-tls"] } tempfile = "3.8.0" rstest = "0.18.2" assert_matches = "1.5.0" diff --git a/crates/rattler_conda_types/src/lib.rs b/crates/rattler_conda_types/src/lib.rs index a5a290f2b..11d1b8506 100644 --- a/crates/rattler_conda_types/src/lib.rs +++ b/crates/rattler_conda_types/src/lib.rs @@ -50,6 +50,9 @@ pub use version_spec::VersionSpec; #[cfg(test)] use std::path::{Path, PathBuf}; +/// An package identifier that can be used to identify packages across package ecosystems. +pub type PackageUrl = purl::GenericPurl; + #[cfg(test)] pub(crate) fn get_test_data_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("../../test-data") diff --git a/crates/rattler_conda_types/src/repo_data/mod.rs b/crates/rattler_conda_types/src/repo_data/mod.rs index b8c7fdaf7..25714fda2 100644 --- a/crates/rattler_conda_types/src/repo_data/mod.rs +++ b/crates/rattler_conda_types/src/repo_data/mod.rs @@ -21,7 +21,7 @@ use rattler_macros::sorted; use crate::{ build_spec::BuildNumber, package::IndexJson, utils::serde::DeserializeFromStrUnchecked, - Channel, NoArchType, PackageName, Platform, RepoDataRecord, VersionWithSource, + Channel, NoArchType, PackageName, PackageUrl, Platform, RepoDataRecord, VersionWithSource, }; /// [`RepoData`] is an index of package binaries available on in a subdirectory of a Conda channel. @@ -125,6 +125,11 @@ pub struct PackageRecord { /// Optionally the platform the package supports pub platform: Option, // Note that this does not match the [`Platform`] enum.. + /// Package identifiers of packages that are equivalent to this package but from other + /// ecosystems. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub purls: Vec, + /// Optionally a SHA256 hash of the package archive #[serde_as(as = "Option>")] pub sha256: Option, @@ -279,6 +284,7 @@ impl PackageRecord { timestamp: None, track_features: vec![], version: version.into(), + purls: vec![], } } @@ -393,6 +399,7 @@ impl PackageRecord { timestamp: index.timestamp, track_features: index.track_features, version: index.version, + purls: vec![], }) } } diff --git a/crates/rattler_lock/src/builder.rs b/crates/rattler_lock/src/builder.rs index e21d25171..afbc7de22 100644 --- a/crates/rattler_lock/src/builder.rs +++ b/crates/rattler_lock/src/builder.rs @@ -7,7 +7,7 @@ use crate::{ PackageHashes, PackageName, PipLockedDependency, Platform, RepoDataRecord, TimeMeta, }; use fxhash::{FxHashMap, FxHashSet}; -use rattler_conda_types::NamelessMatchSpec; +use rattler_conda_types::{NamelessMatchSpec, PackageUrl}; use std::collections::HashSet; use url::Url; @@ -174,6 +174,7 @@ impl LockedPackagesBuilder { noarch: locked_package.noarch, size: locked_package.size, timestamp: locked_package.timestamp, + purls: locked_package.purls, } .into(), }, @@ -248,6 +249,9 @@ pub struct CondaLockedDependencyBuilder { /// Experimental: The date this entry was created. pub timestamp: Option>, + + /// Experimental: Defines that the package is an alias for a package from another ecosystem. + pub purls: Vec, } impl TryFrom<&RepoDataRecord> for CondaLockedDependencyBuilder { @@ -286,6 +290,7 @@ impl TryFrom for CondaLockedDependencyBuilder { noarch: record.package_record.noarch, size: record.package_record.size, timestamp: record.package_record.timestamp, + purls: record.package_record.purls, }) } } @@ -401,6 +406,12 @@ impl CondaLockedDependencyBuilder { self.timestamp = Some(timestamp); self } + + /// Adds a PackageUrl to the package + pub fn add_purl(mut self, purl: PackageUrl) -> Self { + self.purls.push(purl); + self + } } pub struct PipLockedDependencyBuilder { @@ -472,6 +483,9 @@ mod tests { noarch: NoArchType::python(), size: Some(12000), timestamp: Some(Utc::now()), + purls: vec![ + "pkg:deb/debian/python@3.11.0?arch=x86_64".parse().unwrap(), + ] })) .build().unwrap(); diff --git a/crates/rattler_lock/src/conda.rs b/crates/rattler_lock/src/conda.rs index 9cda2361d..494c9fd8a 100644 --- a/crates/rattler_lock/src/conda.rs +++ b/crates/rattler_lock/src/conda.rs @@ -3,8 +3,8 @@ use crate::{ PackageHashes::{Md5, Md5Sha256, Sha256}, }; use rattler_conda_types::{ - InvalidPackageNameError, NoArchType, PackageName, PackageRecord, ParseMatchSpecError, - ParseVersionError, RepoDataRecord, + InvalidPackageNameError, NoArchType, PackageName, PackageRecord, PackageUrl, + ParseMatchSpecError, ParseVersionError, RepoDataRecord, }; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, skip_serializing_none, OneOrMany}; @@ -67,6 +67,10 @@ pub struct CondaLockedDependency { /// Experimental: The date this entry was created. #[serde_as(as = "Option")] pub timestamp: Option>, + + /// Experimental: Defines that the package is an alias for a package from another ecosystem. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub purls: Vec, } impl TryFrom<&LockedDependency> for RepoDataRecord { @@ -136,6 +140,7 @@ impl TryFrom for RepoDataRecord { timestamp: value.timestamp, track_features: value.track_features, version, + purls: value.purls, }, file_name, url: value.url, diff --git a/crates/rattler_solve/tests/backends.rs b/crates/rattler_solve/tests/backends.rs index dd12b5440..32cefd9a7 100644 --- a/crates/rattler_solve/tests/backends.rs +++ b/crates/rattler_solve/tests/backends.rs @@ -104,6 +104,7 @@ fn installed_package( timestamp: None, legacy_bz2_size: None, legacy_bz2_md5: None, + purls: Vec::new(), }, } }