diff --git a/crates/rattler_conda_types/src/match_spec/parse.rs b/crates/rattler_conda_types/src/match_spec/parse.rs index 7ab06807e..72bd4c35a 100644 --- a/crates/rattler_conda_types/src/match_spec/parse.rs +++ b/crates/rattler_conda_types/src/match_spec/parse.rs @@ -1276,7 +1276,10 @@ mod tests { channel.unwrap(), Channel::from_str(expected_channel.unwrap(), &channel_config()).unwrap() ); - assert_eq!(subdir, expected_subdir.map(|s| s.to_string())); + assert_eq!( + subdir, + expected_subdir.map(std::string::ToString::to_string) + ); } } } diff --git a/crates/rattler_conda_types/src/package/about.rs b/crates/rattler_conda_types/src/package/about.rs index ffc75b8b7..0fdd8d437 100644 --- a/crates/rattler_conda_types/src/package/about.rs +++ b/crates/rattler_conda_types/src/package/about.rs @@ -1,10 +1,13 @@ +use std::collections::BTreeMap; use std::{io::Error, path::Path}; use crate::{ package::PackageFile, utils::serde::{LossyUrl, MultiLineString, VecSkipNone}, }; + use serde::{Deserialize, Serialize}; +use serde_json::Value; use serde_with::{serde_as, skip_serializing_none, OneOrMany, Same}; use url::Url; @@ -41,6 +44,10 @@ pub struct AboutJson { )] pub doc_url: Vec, + /// Extra metadata that was passed during the build + #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] + pub extra: BTreeMap, + /// URL to the homepage of the package #[serde(skip_serializing_if = "Vec::is_empty", default)] #[serde_as( @@ -77,6 +84,13 @@ impl PackageFile for AboutJson { #[cfg(test)] mod test { + + use std::collections::BTreeMap; + + use insta::assert_snapshot; + use serde_json::json; + use url::Url; + use super::{AboutJson, PackageFile}; #[test] @@ -113,4 +127,59 @@ mod test { insta::assert_yaml_snapshot!(AboutJson::from_package_directory(&package_dir).unwrap()); } + + #[test] + fn test_extra_field_is_recorded_when_present() { + // Define a sample AboutJson instance with extra field populated + let mut extra_metadata = BTreeMap::default(); + extra_metadata.insert("flow_id".to_string(), json!("2024.08.13".to_string())); + extra_metadata.insert("some_values".to_string(), json!({ "an": "object" })); + + let about = AboutJson { + channels: vec!["conda-forge".to_string()], + description: Some("A sample package".to_string()), + dev_url: vec![], + doc_url: vec![], + extra: extra_metadata.clone(), + home: vec![], + license: Some("MIT".to_string()), + license_family: Some("MIT".to_string()), + source_url: Some(Url::parse("https://github.com/some-user/sample").unwrap()), + summary: Some("This is a test package".to_string()), + }; + + // Serialize the AboutJson instance to JSON + let serialized = serde_json::to_string(&about).expect("Serialization failed"); + + // Deserialize the JSON back to an AboutJson instance + let deserialized: AboutJson = + serde_json::from_str(&serialized).expect("Deserialization failed"); + + // Verify that the deserialized instance matches the original + assert_snapshot!(serialized); + assert_eq!(about, deserialized); + } + + #[test] + fn test_extra_field_is_skipped() { + // Define a sample AboutJson instance with extra field populated + let about = AboutJson { + channels: vec!["conda-forge".to_string()], + description: Some("A sample package".to_string()), + dev_url: vec![], + doc_url: vec![], + extra: BTreeMap::default(), + home: vec![], + license: Some("MIT".to_string()), + license_family: Some("MIT".to_string()), + source_url: Some(Url::parse("https://github.com/some-user/sample").unwrap()), + summary: Some("This is a test package".to_string()), + }; + + // Serialize the AboutJson instance to JSON + let serialized = serde_json::to_string(&about).expect("Serialization failed"); + + // Verify that the deserialized instance matches the original + assert_snapshot!(serialized); + } } diff --git a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_recorded_when_present.snap b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_recorded_when_present.snap new file mode 100644 index 000000000..c9e4d4dbf --- /dev/null +++ b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_recorded_when_present.snap @@ -0,0 +1,5 @@ +--- +source: crates/rattler_conda_types/src/package/about.rs +expression: serialized +--- +{"channels":["conda-forge"],"description":"A sample package","extra":{"flow_id":"2024.08.13","some_values":{"an":"object"}},"license":"MIT","license_family":"MIT","source_url":"https://github.com/some-user/sample","summary":"This is a test package"} diff --git a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_skipped.snap b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_skipped.snap new file mode 100644 index 000000000..72a417752 --- /dev/null +++ b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__extra_field_is_skipped.snap @@ -0,0 +1,5 @@ +--- +source: crates/rattler_conda_types/src/package/about.rs +expression: serialized +--- +{"channels":["conda-forge"],"description":"A sample package","license":"MIT","license_family":"MIT","source_url":"https://github.com/some-user/sample","summary":"This is a test package"} diff --git a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json.snap b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json.snap index 43553dc61..573c4d64d 100644 --- a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json.snap +++ b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json.snap @@ -7,7 +7,22 @@ channels: description: "Conda is an open source package management system and environment management system for installing multiple versions of software packages and their dependencies and switching easily between them. It works on Linux, OS X and Windows, and was created for Python programs but can package and distribute any software.\n" dev_url: "https://github.com/conda/conda" doc_url: "https://docs.conda.io/projects/conda/en/stable/" +extra: + copy_test_source_files: true + final: true + recipe-maintainers: + - isuruf + - jakirkham + - kalefranz + - mingwandroid + - msarahan + - mwcraig + - ocefpaf + - patricksnape + - pelson + - scopatz + - mbargull + - jezdez home: "https://conda.io/" license: BSD-3-Clause summary: "OS-agnostic, system-level binary package and environment manager." - diff --git a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json_mamba.snap b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json_mamba.snap index 6b75c9c7d..e00bb1f82 100644 --- a/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json_mamba.snap +++ b/crates/rattler_conda_types/src/package/snapshots/rattler_conda_types__package__about__test__reconstruct_about_json_mamba.snap @@ -6,6 +6,19 @@ channels: - "https://conda.anaconda.org/conda-forge" description: "\n[![Build Status](https://github.com/mamba-org/mamba/workflows/CI/badge.svg)](https://github.com/mamba-org/mamba/actions)\n[![Join the Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mamba-org/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n[![docs](https://readthedocs.org/projects/mamba/badge/?version=latest&style=flat)](https://mamba.readthedocs.io/en/latest)\n\n`mamba` is a reimplementation of the conda package manager in C++.\n\n- parallel downloading of repository data and package files using multi-threading\n- libsolv for much faster dependency solving, a state of the art library used in the RPM package manager of Red Hat, Fedora and OpenSUSE\n- core parts of `mamba` are implemented in C++ for maximum efficiency\n\nAt the same time, `mamba` utilizes the same command line parser, package installation and deinstallation code and transaction verification routines as `conda` to stay as compatible as possible.\n\nMamba is part of a bigger ecosystem to make scientific packaging more sustainable. You can read our [announcement blog post](https://medium.com/@QuantStack/open-software-packaging-for-science-61cecee7fc23).\nThe ecosystem also consists of `quetz`, an open source `conda` package server and `boa`, a fast `conda` package builder.\n\n\nPlease refer to the [`mamba` and `micromamba` installation guide](https://mamba.readthedocs.io/en/latest/installation.html) in the documentation.\n\n\n`mamba` and `micromamba` come with features on top of stock `conda`.\n\n\nTo efficiently query repositories and query package dependencies you can use `mamba repoquery` or `micromamba repoquery`.\nSee the [repoquery documentation](https://mamba.readthedocs.io/en/latest/user_guide/mamba.html#repoquery) for details.\n\n\n`micromamba` can be used to install lock files generated by [conda-lock](https://conda-incubator.github.io/conda-lock/) without having to install `conda-lock`. Simply invoke e.g. `micromamba create -n my-env -f conda-lock.yml` with an environment lockfile named `*-lock.yml` or `*-lock.yaml`.\n" dev_url: "https://github.com/mamba-org/mamba" +extra: + copy_test_source_files: true + final: true + parent_recipe: + name: mamba-split + path: "D:\\a\\1\\s\\recipe" + version: "" + recipe-maintainers: + - adriendelsalle + - SylvainCorlay + - JohanMabille + - wolfv + - ericmjl home: "https://github.com/mamba-org/mamba" license: BSD-3-Clause license_family: BSD diff --git a/crates/rattler_conda_types/src/repo_data/mod.rs b/crates/rattler_conda_types/src/repo_data/mod.rs index 20a957937..fdbca1c5a 100644 --- a/crates/rattler_conda_types/src/repo_data/mod.rs +++ b/crates/rattler_conda_types/src/repo_data/mod.rs @@ -6,7 +6,7 @@ pub mod sharded; mod topological_sort; use std::{ - collections::{BTreeMap, BTreeSet}, + collections::BTreeSet, fmt::{Display, Formatter}, path::Path, }; @@ -19,6 +19,7 @@ use serde_with::{serde_as, skip_serializing_none, OneOrMany}; use thiserror::Error; use url::Url; +use crate::utils::serde::sort_map_alphabetically; use crate::utils::url::add_trailing_slash; use crate::{ build_spec::BuildNumber, @@ -423,16 +424,6 @@ impl PackageRecord { } } -fn sort_map_alphabetically( - value: &FxHashMap, - serializer: S, -) -> Result { - value - .iter() - .collect::>() - .serialize(serializer) -} - fn sort_set_alphabetically( value: &FxHashSet, serializer: S, diff --git a/crates/rattler_conda_types/src/utils/serde.rs b/crates/rattler_conda_types/src/utils/serde.rs index 376855ec2..3a2788fc7 100644 --- a/crates/rattler_conda_types/src/utils/serde.rs +++ b/crates/rattler_conda_types/src/utils/serde.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use fxhash::FxHashMap; use itertools::Itertools; use serde::de::Error as _; use serde::ser::Error; @@ -6,7 +7,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_with::de::DeserializeAsWrap; use serde_with::ser::SerializeAsWrap; use serde_with::{DeserializeAs, SerializeAs}; -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; use std::hash::{BuildHasher, Hash}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; @@ -200,3 +201,14 @@ impl> SerializeAs> for Ordered { /// A helper struct to deserialize types from a string without checking the string. pub struct DeserializeFromStrUnchecked; + +/// A helper function used to sort map alphabetically when serializing. +pub(crate) fn sort_map_alphabetically( + value: &FxHashMap, + serializer: S, +) -> Result { + value + .iter() + .collect::>() + .serialize(serializer) +}