|
1 | 1 | use std::{borrow::Borrow, cell::RefCell, collections::HashMap, error::Error as StdError}; |
2 | 2 |
|
3 | | -use crate::{Error, Result}; |
| 3 | +use crate::{manifest, Error, Result}; |
4 | 4 |
|
5 | 5 | use ecow::EcoString; |
6 | 6 | use hexpm::{ |
|
69 | 69 | */ |
70 | 70 | pub type PackageVersionDiffs = HashMap<String, (Version, Version)>; |
71 | 71 |
|
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( |
80 | 73 | package_fetcher: Box<dyn PackageFetcher>, |
81 | 74 | versions: PackageVersions, |
82 | 75 | ) -> PackageVersionDiffs { |
@@ -107,6 +100,29 @@ pub fn resolve_major_versions( |
107 | 100 | .collect() |
108 | 101 | } |
109 | 102 |
|
| 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 | + |
110 | 126 | // If the string would parse to an exact version then return the version |
111 | 127 | fn parse_exact_version(ver: &str) -> Option<Version> { |
112 | 128 | let version = ver.trim(); |
@@ -337,6 +353,11 @@ impl pubgrub::solver::DependencyProvider<PackageName, Version> for DependencyPro |
337 | 353 |
|
338 | 354 | #[cfg(test)] |
339 | 355 | mod tests { |
| 356 | + use crate::{ |
| 357 | + manifest::{Base16Checksum, ManifestPackage, ManifestPackageSource}, |
| 358 | + requirement, |
| 359 | + }; |
| 360 | + |
340 | 361 | use super::*; |
341 | 362 |
|
342 | 363 | struct Remote { |
@@ -515,91 +536,72 @@ mod tests { |
515 | 536 | }, |
516 | 537 | ); |
517 | 538 |
|
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")]), |
572 | 546 | ], |
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 | + ]; |
575 | 561 |
|
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); |
599 | 563 |
|
600 | 564 | Box::new(Remote { deps }) |
601 | 565 | } |
602 | 566 |
|
| 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 | + |
603 | 605 | #[test] |
604 | 606 | fn resolution_with_locked() { |
605 | 607 | let locked_stdlib = ("gleam_stdlib".into(), Version::parse("0.1.0").unwrap()); |
@@ -961,23 +963,65 @@ mod tests { |
961 | 963 |
|
962 | 964 | #[test] |
963 | 965 | 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![ |
968 | 968 | ( |
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 | + }, |
971 | 973 | ), |
| 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 | + ) |
972 | 980 | ] |
973 | 981 | .into_iter() |
974 | 982 | .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()); |
976 | 1018 |
|
| 1019 | + // indirect package with major version will not be in the result even though a major |
| 1020 | + // version of it is available |
977 | 1021 | assert_eq!( |
978 | 1022 | result, |
979 | 1023 | vec![( |
980 | | - "core_package".into(), |
| 1024 | + "direct_pkg_with_major_version".into(), |
981 | 1025 | ( |
982 | 1026 | Version::try_from("0.1.0").unwrap(), |
983 | 1027 | Version::try_from("1.1.0").unwrap() |
|
0 commit comments