Skip to content

Commit 0352a76

Browse files
andholpil
authored andcommitted
refactor: move major version check into a separate testable unit ♻️
1 parent 47551ef commit 0352a76

File tree

2 files changed

+148
-120
lines changed

2 files changed

+148
-120
lines changed

compiler-cli/src/dependencies.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -418,32 +418,16 @@ pub fn download<Telem: Telemetry>(
418418
}
419419
LocalPackages::from_manifest(&manifest).write_to_disc(paths)?;
420420

421-
let versions = manifest
422-
.packages
423-
.iter()
424-
.map(|manifest_pkg| (manifest_pkg.name.to_string(), manifest_pkg.version.clone()))
425-
.filter(|(name, _)| {
426-
manifest
427-
.requirements
428-
.iter()
429-
.any(|(required_pkg, _)| name == required_pkg)
430-
})
431-
.collect();
432-
let major_versions_available = dependency::resolve_major_versions(
433-
PackageFetcher::boxed(runtime.handle().clone()),
434-
versions,
435-
);
436-
421+
let package_fetcher = PackageFetcher::boxed(runtime.handle().clone());
422+
let major_versions_available =
423+
dependency::check_for_major_version_updates(&manifest, package_fetcher);
437424
if !major_versions_available.is_empty() {
438-
// print to stderr instead of because this is not part of the standard output of this
425+
// print to stderr instead of stdout because this is not part of the standard output of this
439426
// command
440-
eprintln!("Hint: the following dependencies have new major versions available...");
441-
442-
major_versions_available
443-
.iter()
444-
.for_each(|(name, (v1, v2))| {
445-
eprintln!("{}@{} -> {}@{}", name, v1, name, v2);
446-
});
427+
eprintln!("\nHint: the following dependencies have new major versions available...\n");
428+
for (name, (v1, v2)) in major_versions_available {
429+
eprintln!("{}@{} -> {}@{}", name, v1, name, v2);
430+
}
447431
}
448432

449433
Ok(manifest)

compiler-core/src/dependency.rs

Lines changed: 140 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{borrow::Borrow, cell::RefCell, collections::HashMap, error::Error as StdError};
22

3-
use crate::{Error, Result};
3+
use crate::{manifest, Error, Result};
44

55
use ecow::EcoString;
66
use hexpm::{
@@ -69,14 +69,7 @@ where
6969
*/
7070
pub type PackageVersionDiffs = HashMap<String, (Version, Version)>;
7171

72-
/**
73-
* This is a preliminary implementation to get to first implementation.
74-
* It is unoptimal as it makes a request for each hex package.
75-
* Alternative is to create a package config with all direct dependencies
76-
* with "*" but I'm not sure if we will get correct resolution that way as
77-
* dependencies might cause the package to not return the latest major version.
78-
*/
79-
pub fn resolve_major_versions(
72+
fn resolve_major_versions(
8073
package_fetcher: Box<dyn PackageFetcher>,
8174
versions: PackageVersions,
8275
) -> PackageVersionDiffs {
@@ -107,6 +100,29 @@ pub fn resolve_major_versions(
107100
.collect()
108101
}
109102

103+
/// Check for major version updates for direct dependencies that are being blocked by some version
104+
/// constraints.
105+
pub fn check_for_major_version_updates(
106+
manifest: &manifest::Manifest,
107+
package_fetcher: Box<dyn PackageFetcher>,
108+
) -> HashMap<String, (Version, Version)> {
109+
// get the resolved versions of the direct dependencies to check for major
110+
// version updates.
111+
let versions = manifest
112+
.packages
113+
.iter()
114+
.map(|manifest_pkg| (manifest_pkg.name.to_string(), manifest_pkg.version.clone()))
115+
.filter(|(name, _)| {
116+
manifest
117+
.requirements
118+
.iter()
119+
.any(|(required_pkg, _)| name == required_pkg)
120+
})
121+
.collect();
122+
123+
resolve_major_versions(package_fetcher, versions)
124+
}
125+
110126
// If the string would parse to an exact version then return the version
111127
fn parse_exact_version(ver: &str) -> Option<Version> {
112128
let version = ver.trim();
@@ -337,6 +353,11 @@ impl pubgrub::solver::DependencyProvider<PackageName, Version> for DependencyPro
337353

338354
#[cfg(test)]
339355
mod tests {
356+
use crate::{
357+
manifest::{Base16Checksum, ManifestPackage, ManifestPackageSource},
358+
requirement,
359+
};
360+
340361
use super::*;
341362

342363
struct Remote {
@@ -515,91 +536,72 @@ mod tests {
515536
},
516537
);
517538

518-
let _ = deps.insert(
519-
"core_package".into(),
520-
hexpm::Package {
521-
name: "core_package".into(),
522-
repository: "hexpm".into(),
523-
releases: vec![
524-
Release {
525-
version: Version::try_from("0.1.0").unwrap(),
526-
requirements: [(
527-
"gleam_stdlib".into(),
528-
Dependency {
529-
app: None,
530-
optional: true,
531-
repository: None,
532-
requirement: Range::new(">= 0.1.0 and < 0.3.0".into()),
533-
},
534-
)]
535-
.into(),
536-
retirement_status: None,
537-
outer_checksum: vec![1, 2, 3],
538-
meta: (),
539-
},
540-
Release {
541-
version: Version::try_from("1.0.0").unwrap(),
542-
requirements: [(
543-
"gleam_stdlib".into(),
544-
Dependency {
545-
app: None,
546-
optional: true,
547-
repository: None,
548-
requirement: Range::new(">= 0.1.0 and < 0.3.0".into()),
549-
},
550-
)]
551-
.into(),
552-
retirement_status: None,
553-
outer_checksum: vec![1, 2, 3],
554-
meta: (),
555-
},
556-
Release {
557-
version: Version::try_from("1.1.0").unwrap(),
558-
requirements: [(
559-
"gleam_stdlib".into(),
560-
Dependency {
561-
app: None,
562-
optional: true,
563-
repository: None,
564-
requirement: Range::new(">= 0.1.0 and < 0.3.0".into()),
565-
},
566-
)]
567-
.into(),
568-
retirement_status: None,
569-
outer_checksum: vec![1, 2, 3],
570-
meta: (),
571-
},
539+
let simple_deps_for_major_version_check = vec![
540+
(
541+
"direct_pkg_with_major_version",
542+
vec![
543+
("0.1.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
544+
("1.0.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
545+
("1.1.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
572546
],
573-
},
574-
);
547+
),
548+
(
549+
"this_pkg_depends_on_indirect_pkg",
550+
vec![("0.1.0", vec![("indirect_pkg_with_major_version", ">= 0.1.0 and < 1.0.0")])],
551+
),
552+
(
553+
"indirect_pkg_with_major_version",
554+
vec![
555+
("0.1.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
556+
("1.0.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
557+
("1.1.0", vec![("gleam_stdlib", ">= 0.1.0 and < 0.3.0")]),
558+
],
559+
),
560+
];
575561

576-
let _ = deps.insert(
577-
"package_depends_on_core".into(),
578-
hexpm::Package {
579-
name: "package_depends_on_core".into(),
580-
repository: "hexpm".into(),
581-
releases: vec![Release {
582-
version: Version::try_from("0.1.0").unwrap(),
583-
requirements: [(
584-
"core_package".into(),
585-
Dependency {
586-
app: None,
587-
optional: true,
588-
repository: None,
589-
requirement: Range::new(">= 0.1.0 and < 1.0.0".into()),
590-
},
591-
)]
592-
.into(),
593-
retirement_status: None,
594-
outer_checksum: vec![1, 2, 3],
595-
meta: (),
596-
}],
597-
},
598-
);
562+
insert_simplified_deps(simple_deps_for_major_version_check, &mut deps);
599563

600564
Box::new(Remote { deps })
601565
}
602566

567+
fn insert_simplified_deps(
568+
simple_deps: Vec<(&str, Vec<(&str, Vec<(&str, &str)>)>)>,
569+
deps: &mut HashMap<String, hexpm::Package>,
570+
) {
571+
for (name, releases) in simple_deps {
572+
let _ = deps.insert(
573+
name.to_string(),
574+
hexpm::Package {
575+
name: name.to_string(),
576+
repository: "hexpm".into(),
577+
releases: releases
578+
.into_iter()
579+
.map(|(version, requirements)| Release {
580+
version: Version::try_from(version).unwrap(),
581+
requirements: requirements
582+
.into_iter()
583+
.map(|(package, range)| {
584+
(
585+
package.into(),
586+
Dependency {
587+
app: None,
588+
optional: true,
589+
repository: None,
590+
requirement: Range::new(range.into()),
591+
},
592+
)
593+
})
594+
.collect(),
595+
retirement_status: None,
596+
outer_checksum: vec![1, 2, 3],
597+
meta: (),
598+
})
599+
.collect(),
600+
},
601+
);
602+
}
603+
}
604+
603605
#[test]
604606
fn resolution_with_locked() {
605607
let locked_stdlib = ("gleam_stdlib".into(), Version::parse("0.1.0").unwrap());
@@ -961,23 +963,65 @@ mod tests {
961963

962964
#[test]
963965
fn resolve_major_version_upgrades() {
964-
let result = resolve_major_versions(
965-
make_remote(),
966-
vec![
967-
("core_package".into(), Version::try_from("0.1.0").unwrap()),
966+
let manifest = manifest::Manifest {
967+
requirements: vec![
968968
(
969-
"package_depends_on_core".into(),
970-
Version::try_from("0.1.0").unwrap(),
969+
EcoString::from("package_depends_on_indirect_pkg"),
970+
requirement::Requirement::Hex {
971+
version: Range::new("> 0.1.0 and <= 1.0.0".into()),
972+
},
971973
),
974+
(
975+
EcoString::from("direct_pkg_with_major_version"),
976+
requirement::Requirement::Hex {
977+
version: Range::new("> 0.1.0 and <= 1.0.0".into()),
978+
},
979+
)
972980
]
973981
.into_iter()
974982
.collect(),
975-
);
983+
//requirements: HashMap::new(),
984+
packages: vec![
985+
ManifestPackage {
986+
name: "direct_pkg_with_major_version".into(),
987+
version: Version::parse("0.1.0").unwrap(),
988+
build_tools: ["gleam".into()].into(),
989+
otp_app: None,
990+
requirements: vec![],
991+
source: ManifestPackageSource::Hex {
992+
outer_checksum: Base16Checksum(vec![1, 2, 3]),
993+
},
994+
},
995+
ManifestPackage {
996+
name: "package_depends_on_indirect_pkg".into(),
997+
version: Version::parse("0.1.0").unwrap(),
998+
build_tools: ["gleam".into()].into(),
999+
otp_app: None,
1000+
requirements: vec!["core_package".into()],
1001+
source: ManifestPackageSource::Hex {
1002+
outer_checksum: Base16Checksum(vec![1, 2, 3]),
1003+
},
1004+
},
1005+
ManifestPackage {
1006+
name: "indirect_pkg_with_major_version".into(),
1007+
version: Version::parse("0.1.0").unwrap(),
1008+
build_tools: ["gleam".into()].into(),
1009+
otp_app: None,
1010+
requirements: vec![],
1011+
source: ManifestPackageSource::Hex {
1012+
outer_checksum: Base16Checksum(vec![1, 2, 3]),
1013+
},
1014+
},
1015+
],
1016+
};
1017+
let result = check_for_major_version_updates(&manifest, make_remote());
9761018

1019+
// indirect package with major version will not be in the result even though a major
1020+
// version of it is available
9771021
assert_eq!(
9781022
result,
9791023
vec![(
980-
"core_package".into(),
1024+
"direct_pkg_with_major_version".into(),
9811025
(
9821026
Version::try_from("0.1.0").unwrap(),
9831027
Version::try_from("1.1.0").unwrap()

0 commit comments

Comments
 (0)