Skip to content

Commit

Permalink
feat: sort extras by name and urls by filename (#540)
Browse files Browse the repository at this point in the history
Sorts the extras according to name for consistency.

Also sorts the urls slightly different. Instead of sorting by the
complete url, now its first sorted by filename followed by the entire
url. This causes the urls to be sorted by package name most of the time
which reduces the diff if versions change.

Fixes prefix-dev/pixi#791
  • Loading branch information
baszalmstra authored Feb 26, 2024
1 parent 517fbbc commit 53a29c6
Show file tree
Hide file tree
Showing 12 changed files with 1,649 additions and 1,600 deletions.
4 changes: 2 additions & 2 deletions crates/rattler_lock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
use fxhash::FxHashMap;
use pep508_rs::Requirement;
use rattler_conda_types::{MatchSpec, PackageRecord, Platform, RepoDataRecord};
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeSet, HashMap};
use std::sync::Arc;
use std::{borrow::Cow, io::Read, path::Path, str::FromStr};
use url::Url;
Expand Down Expand Up @@ -550,7 +550,7 @@ impl PypiPackage {
}

/// Returns the extras enabled for this package
pub fn extras(&self) -> &HashSet<String> {
pub fn extras(&self) -> &BTreeSet<String> {
&self.environment_data().extras
}

Expand Down
71 changes: 60 additions & 11 deletions crates/rattler_lock/src/parse/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ use crate::{Channel, EnvironmentPackageData, LockFile, PypiPackageData};
use itertools::Itertools;
use rattler_conda_types::Platform;
use serde::{Serialize, Serializer};
use std::{
cmp::Ordering,
collections::{BTreeMap, HashSet},
};
use std::collections::{BTreeSet, HashSet};
use std::{cmp::Ordering, collections::BTreeMap};
use url::Url;

#[derive(Serialize)]
Expand All @@ -31,16 +29,16 @@ enum SerializablePackageData<'a> {
Pypi(&'a PypiPackageData),
}

#[derive(Serialize)]
#[derive(Serialize, Eq, PartialEq)]
#[serde(untagged, rename_all = "snake_case")]
enum SerializablePackageSelector<'a> {
Conda {
conda: &'a Url,
},
Pypi {
pypi: &'a Url,
#[serde(skip_serializing_if = "HashSet::is_empty")]
extras: &'a HashSet<String>,
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
extras: &'a BTreeSet<String>,
},
}

Expand All @@ -53,6 +51,60 @@ impl<'a> SerializablePackageSelector<'a> {
}
}

impl<'a> PartialOrd for SerializablePackageSelector<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl<'a> Ord for SerializablePackageSelector<'a> {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(
SerializablePackageSelector::Conda { .. },
SerializablePackageSelector::Pypi { .. },
) => {
// Sort conda packages before pypi packages
Ordering::Less
}
(
SerializablePackageSelector::Pypi { .. },
SerializablePackageSelector::Conda { .. },
) => {
// Sort Pypi packages after conda packages
Ordering::Greater
}
(
SerializablePackageSelector::Conda { conda: a },
SerializablePackageSelector::Conda { conda: b },
)
| (
SerializablePackageSelector::Pypi { pypi: a, .. },
SerializablePackageSelector::Pypi { pypi: b, .. },
) => {
// First sort packages just by their filename. Since most of the time the urls end
// in the packages filename this causes the urls to be sorted by package name.
if let (Some(a), Some(b)) = (
a.path_segments()
.and_then(Iterator::last)
.map(str::to_lowercase),
b.path_segments()
.and_then(Iterator::last)
.map(str::to_lowercase),
) {
match a.cmp(&b) {
Ordering::Equal => {}
ordering => return ordering,
}
}

// Otherwise just sort by their full URL
a.cmp(b)
}
}
}
}

impl<'a> SerializablePackageData<'a> {
fn name(&self) -> &str {
match self {
Expand Down Expand Up @@ -149,10 +201,7 @@ impl Serialize for LockFile {
}
}
})
.sorted_by_key(|p| match p {
SerializablePackageSelector::Conda { conda } => *conda,
SerializablePackageSelector::Pypi { pypi, .. } => *pypi,
})
.sorted()
.collect(),
)
})
Expand Down
6 changes: 3 additions & 3 deletions crates/rattler_lock/src/pypi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use pep508_rs::Requirement;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, skip_serializing_none};
use std::cmp::Ordering;
use std::collections::HashSet;
use std::collections::BTreeSet;
use url::Url;

/// A pinned Pypi package
Expand Down Expand Up @@ -37,8 +37,8 @@ pub struct PypiPackageData {
/// the same pypi package but with different extras enabled.
#[derive(Clone, Debug, Default)]
pub struct PypiPackageEnvironmentData {
/// The extras enabled for the package. Note that the order doesn't matter.
pub extras: HashSet<String>,
/// The extras enabled for the package. Note that the order doesn't matter here but it does matter for serialization.
pub extras: BTreeSet<String>,
}

impl PartialOrd for PypiPackageData {
Expand Down
Loading

0 comments on commit 53a29c6

Please sign in to comment.