Skip to content

Commit d60fc64

Browse files
committed
refactor(update): Centralize "what is a change"
This is prep for consolidating a lot of code *and* tracking more information so we can have a richer output.
1 parent 88d8ace commit d60fc64

File tree

1 file changed

+133
-51
lines changed

1 file changed

+133
-51
lines changed

src/cargo/ops/cargo_update.rs

Lines changed: 133 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::util::{style, OptVersionReq};
1717
use crate::util::{CargoResult, VersionExt};
1818
use anyhow::Context as _;
1919
use cargo_util_schemas::core::PartialVersion;
20+
use indexmap::IndexMap;
2021
use itertools::Itertools;
2122
use semver::{Op, Version, VersionReq};
2223
use std::cmp::Ordering;
@@ -491,16 +492,16 @@ fn print_lockfile_generation(
491492
resolve: &Resolve,
492493
registry: &mut PackageRegistry<'_>,
493494
) -> CargoResult<()> {
494-
let diff: Vec<_> = PackageDiff::new(&resolve).collect();
495-
let num_pkgs: usize = diff.iter().map(|d| d.added.len()).sum();
495+
let changes = PackageChange::new(resolve);
496+
let num_pkgs: usize = changes.iter().filter(|change| change.kind.is_new()).count();
496497
if num_pkgs <= 1 {
497498
// just ourself, nothing worth reporting
498499
return Ok(());
499500
}
500501
status_locking(ws, num_pkgs)?;
501502

502-
for diff in diff {
503-
let possibilities = if let Some(query) = diff.alternatives_query() {
503+
for change in changes {
504+
let possibilities = if let Some(query) = change.alternatives_query() {
504505
loop {
505506
match registry.query_vec(&query, QueryKind::Exact) {
506507
std::task::Poll::Ready(res) => {
@@ -513,12 +514,14 @@ fn print_lockfile_generation(
513514
vec![]
514515
};
515516

516-
for package_id in diff.added {
517+
{
518+
let package_id = change.package_id;
517519
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
518520
let latest = report_latest(&possibilities, package_id);
519521
let note = required_rust_version.or(latest);
520522

521523
if let Some(note) = note {
524+
assert_eq!(change.kind, PackageChangeKind::Added);
522525
ws.gctx().shell().status_with_color(
523526
"Adding",
524527
format!("{package_id}{note}"),
@@ -537,15 +540,15 @@ fn print_lockfile_sync(
537540
resolve: &Resolve,
538541
registry: &mut PackageRegistry<'_>,
539542
) -> CargoResult<()> {
540-
let diff: Vec<_> = PackageDiff::diff(&previous_resolve, &resolve).collect();
541-
let num_pkgs: usize = diff.iter().map(|d| d.added.len()).sum();
543+
let changes = PackageChange::diff(previous_resolve, resolve);
544+
let num_pkgs: usize = changes.iter().filter(|change| change.kind.is_new()).count();
542545
if num_pkgs == 0 {
543546
return Ok(());
544547
}
545548
status_locking(ws, num_pkgs)?;
546549

547-
for diff in diff {
548-
let possibilities = if let Some(query) = diff.alternatives_query() {
550+
for change in changes {
551+
let possibilities = if let Some(query) = change.alternatives_query() {
549552
loop {
550553
match registry.query_vec(&query, QueryKind::Exact) {
551554
std::task::Poll::Ready(res) => {
@@ -558,7 +561,8 @@ fn print_lockfile_sync(
558561
vec![]
559562
};
560563

561-
if let Some((previous_id, package_id)) = diff.change() {
564+
let package_id = change.package_id;
565+
if let Some(previous_id) = change.previous_id {
562566
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
563567
let latest = report_latest(&possibilities, package_id);
564568
let note = required_rust_version.or(latest).unwrap_or_default();
@@ -572,11 +576,7 @@ fn print_lockfile_sync(
572576
format!("{previous_id} -> v{}{note}", package_id.version())
573577
};
574578

575-
// If versions differ only in build metadata, we call it an "update"
576-
// regardless of whether the build metadata has gone up or down.
577-
// This metadata is often stuff like git commit hashes, which are
578-
// not meaningfully ordered.
579-
if previous_id.version().cmp_precedence(package_id.version()) == Ordering::Greater {
579+
if change.kind == PackageChangeKind::Downgraded {
580580
ws.gctx()
581581
.shell()
582582
.status_with_color("Downgrading", msg, &style::WARN)?;
@@ -586,7 +586,7 @@ fn print_lockfile_sync(
586586
.status_with_color("Updating", msg, &style::GOOD)?;
587587
}
588588
} else {
589-
for package_id in diff.added {
589+
if change.kind == PackageChangeKind::Added {
590590
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
591591
let latest = report_latest(&possibilities, package_id);
592592
let note = required_rust_version.or(latest).unwrap_or_default();
@@ -610,15 +610,15 @@ fn print_lockfile_updates(
610610
precise: bool,
611611
registry: &mut PackageRegistry<'_>,
612612
) -> CargoResult<()> {
613-
let diff: Vec<_> = PackageDiff::diff(&previous_resolve, &resolve).collect();
614-
let num_pkgs: usize = diff.iter().map(|d| d.added.len()).sum();
613+
let changes = PackageChange::diff(previous_resolve, resolve);
614+
let num_pkgs: usize = changes.iter().filter(|change| change.kind.is_new()).count();
615615
if !precise {
616616
status_locking(ws, num_pkgs)?;
617617
}
618618

619619
let mut unchanged_behind = 0;
620-
for diff in diff {
621-
let possibilities = if let Some(query) = diff.alternatives_query() {
620+
for change in changes {
621+
let possibilities = if let Some(query) = change.alternatives_query() {
622622
loop {
623623
match registry.query_vec(&query, QueryKind::Exact) {
624624
std::task::Poll::Ready(res) => {
@@ -631,7 +631,8 @@ fn print_lockfile_updates(
631631
vec![]
632632
};
633633

634-
if let Some((previous_id, package_id)) = diff.change() {
634+
let package_id = change.package_id;
635+
if let Some(previous_id) = change.previous_id {
635636
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
636637
let latest = report_latest(&possibilities, package_id);
637638
let note = required_rust_version.or(latest).unwrap_or_default();
@@ -645,11 +646,7 @@ fn print_lockfile_updates(
645646
format!("{previous_id} -> v{}{note}", package_id.version())
646647
};
647648

648-
// If versions differ only in build metadata, we call it an "update"
649-
// regardless of whether the build metadata has gone up or down.
650-
// This metadata is often stuff like git commit hashes, which are
651-
// not meaningfully ordered.
652-
if previous_id.version().cmp_precedence(package_id.version()) == Ordering::Greater {
649+
if change.kind == PackageChangeKind::Downgraded {
653650
ws.gctx()
654651
.shell()
655652
.status_with_color("Downgrading", msg, &style::WARN)?;
@@ -659,14 +656,13 @@ fn print_lockfile_updates(
659656
.status_with_color("Updating", msg, &style::GOOD)?;
660657
}
661658
} else {
662-
for package_id in diff.removed {
659+
if change.kind == PackageChangeKind::Removed {
663660
ws.gctx().shell().status_with_color(
664661
"Removing",
665662
format!("{package_id}"),
666663
&style::ERROR,
667664
)?;
668-
}
669-
for package_id in diff.added {
665+
} else if change.kind == PackageChangeKind::Added {
670666
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
671667
let latest = report_latest(&possibilities, package_id);
672668
let note = required_rust_version.or(latest).unwrap_or_default();
@@ -678,7 +674,7 @@ fn print_lockfile_updates(
678674
)?;
679675
}
680676
}
681-
for package_id in diff.unchanged {
677+
if change.kind == PackageChangeKind::Unchanged {
682678
let required_rust_version = report_required_rust_version(ws, resolve, package_id);
683679
let latest = report_latest(&possibilities, package_id);
684680
let note = required_rust_version.as_deref().or(latest.as_deref());
@@ -818,6 +814,113 @@ fn fill_with_deps<'a>(
818814
}
819815
}
820816

817+
#[derive(Clone, Debug)]
818+
struct PackageChange {
819+
package_id: PackageId,
820+
previous_id: Option<PackageId>,
821+
kind: PackageChangeKind,
822+
}
823+
824+
impl PackageChange {
825+
pub fn new(resolve: &Resolve) -> Vec<Self> {
826+
let diff = PackageDiff::new(resolve);
827+
Self::with_diff(diff)
828+
}
829+
830+
pub fn diff(previous_resolve: &Resolve, resolve: &Resolve) -> Vec<Self> {
831+
let diff = PackageDiff::diff(previous_resolve, resolve);
832+
Self::with_diff(diff)
833+
}
834+
835+
fn with_diff(diff: impl Iterator<Item = PackageDiff>) -> Vec<Self> {
836+
let mut changes = IndexMap::new();
837+
for diff in diff {
838+
if let Some((previous_id, package_id)) = diff.change() {
839+
// If versions differ only in build metadata, we call it an "update"
840+
// regardless of whether the build metadata has gone up or down.
841+
// This metadata is often stuff like git commit hashes, which are
842+
// not meaningfully ordered.
843+
let kind = if previous_id.version().cmp_precedence(package_id.version())
844+
== Ordering::Greater
845+
{
846+
PackageChangeKind::Downgraded
847+
} else {
848+
PackageChangeKind::Upgraded
849+
};
850+
let change = Self {
851+
package_id,
852+
previous_id: Some(previous_id),
853+
kind,
854+
};
855+
changes.insert(change.package_id, change);
856+
} else {
857+
for package_id in diff.removed {
858+
let kind = PackageChangeKind::Removed;
859+
let change = Self {
860+
package_id,
861+
previous_id: None,
862+
kind,
863+
};
864+
changes.insert(change.package_id, change);
865+
}
866+
for package_id in diff.added {
867+
let kind = PackageChangeKind::Added;
868+
let change = Self {
869+
package_id,
870+
previous_id: None,
871+
kind,
872+
};
873+
changes.insert(change.package_id, change);
874+
}
875+
}
876+
for package_id in diff.unchanged {
877+
let kind = PackageChangeKind::Unchanged;
878+
let change = Self {
879+
package_id,
880+
previous_id: None,
881+
kind,
882+
};
883+
changes.insert(change.package_id, change);
884+
}
885+
}
886+
887+
changes.into_values().collect()
888+
}
889+
890+
/// For querying [`PackageRegistry`] for alternative versions to report to the user
891+
fn alternatives_query(&self) -> Option<crate::core::dependency::Dependency> {
892+
if !self.package_id.source_id().is_registry() {
893+
return None;
894+
}
895+
896+
let query = crate::core::dependency::Dependency::parse(
897+
self.package_id.name(),
898+
None,
899+
self.package_id.source_id(),
900+
)
901+
.expect("already a valid dependency");
902+
Some(query)
903+
}
904+
}
905+
906+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
907+
enum PackageChangeKind {
908+
Added,
909+
Removed,
910+
Upgraded,
911+
Downgraded,
912+
Unchanged,
913+
}
914+
915+
impl PackageChangeKind {
916+
pub fn is_new(&self) -> bool {
917+
match self {
918+
Self::Added | Self::Upgraded | Self::Downgraded => true,
919+
Self::Removed | Self::Unchanged => false,
920+
}
921+
}
922+
}
923+
821924
/// All resolved versions of a package name within a [`SourceId`]
822925
#[derive(Default, Clone, Debug)]
823926
pub struct PackageDiff {
@@ -931,25 +1034,4 @@ impl PackageDiff {
9311034
None
9321035
}
9331036
}
934-
935-
/// For querying [`PackageRegistry`] for alternative versions to report to the user
936-
pub fn alternatives_query(&self) -> Option<crate::core::dependency::Dependency> {
937-
let package_id = [
938-
self.added.iter(),
939-
self.unchanged.iter(),
940-
self.removed.iter(),
941-
]
942-
.into_iter()
943-
.flatten()
944-
.next()
945-
// Limit to registry as that is the only source with meaningful alternative versions
946-
.filter(|s| s.source_id().is_registry())?;
947-
let query = crate::core::dependency::Dependency::parse(
948-
package_id.name(),
949-
None,
950-
package_id.source_id(),
951-
)
952-
.expect("already a valid dependency");
953-
Some(query)
954-
}
9551037
}

0 commit comments

Comments
 (0)