#[test]
fn bundler_like_resolution() {
struct BundlerOfflineDependencyProvider {
dependency_provider: OfflineDependencyProvider<String, RichReq>,
}
impl BundlerOfflineDependencyProvider {
fn add_dependencies(
&mut self,
package: String,
version: RubyVersion,
dependencies: Vec<(String, RichReq)>,
) {
self.dependency_provider
.add_dependencies(package, version, dependencies);
}
}
impl DependencyProvider for BundlerOfflineDependencyProvider {
type P = String;
type V = <RichReq as VersionSet>::V;
type VS = RichReq;
type M = String;
type Err = Infallible;
#[inline]
fn choose_version(
&self,
package: &Self::P,
range: &Self::VS,
) -> Result<Option<Self::V>, Infallible> {
let mut versions = self
.dependency_provider
.versions(package)
.map(|v| v.filter(|v| range.contains(v)).collect::<Vec<_>>())
.unwrap_or_default();
versions.sort_by(|a, b| b.cmp(a));
if let Some(v) = versions.first() {
if package == "grpc-google-iam-v1" {
println!(
"package: {}, choose_version: {}, versions: {:?}",
package, v, versions
);
}
Ok(Some((*v).clone()))
} else {
Ok(None)
}
// Ok(
// .and_then(|versions| {
// versions.keys().rev().find(|v| range.contains(v)).cloned()
// }))
}
type Priority = (u32, Reverse<usize>);
#[inline]
fn prioritize(
&self,
package: &Self::P,
range: &Self::VS,
package_statistics: &PackageResolutionStatistics,
) -> Self::Priority {
self.dependency_provider
.prioritize(package, range, package_statistics)
}
#[inline]
fn get_dependencies(
&self,
package: &Self::P,
version: &Self::V,
) -> Result<Dependencies<Self::P, Self::VS, Self::M>, Infallible> {
self.dependency_provider.get_dependencies(package, version)
}
}
let mut p = BundlerOfflineDependencyProvider {
dependency_provider: OfflineDependencyProvider::new(),
};
/* ------ grpc-google-iam-v1 ------ */
// 1.10.0
p.add_dependencies(
"google-cloud-artifact_registry-v1".into(),
RubyVersion::parse("0.11.0"),
vec![
("grpc-google-iam-v1".into(), parse_req("~> 1.1", ",").0),
("gapic-common".into(), parse_req(">= 0.20.0, < 2.a", ",").0),
],
);
p.add_dependencies(
"gapic-common".into(),
RubyVersion::parse("1.0.0"),
vec![
(
"googleapis-common-protos-types".into(),
parse_req("~> 1.15", ",").0,
),
(
"googleapis-common-protos".into(),
parse_req("~> 1.6", ",").0,
),
],
);
// 1.11.0
p.add_dependencies(
"grpc-google-iam-v1".into(),
RubyVersion::parse("1.10.0"),
vec![
("google-protobuf".into(), parse_req(">= 3.18, < 5.a", ",").0),
(
"googleapis-common-protos".into(),
parse_req("~> 1.4", ",").0,
),
("grpc".into(), parse_req("~> 1.41", ",").0),
],
);
p.add_dependencies(
"grpc-google-iam-v1".into(),
RubyVersion::parse("1.8.0"),
vec![
("google-protobuf".into(), parse_req(">= 3.18, < 5.a", ",").0),
(
"googleapis-common-protos".into(),
parse_req("~> 1.4", ",").0,
),
("grpc".into(), parse_req("~> 1.41", ",").0),
],
);
p.add_dependencies(
"grpc-google-iam-v1".into(),
RubyVersion::parse("1.11.0"),
vec![
("google-protobuf".into(), parse_req(">= 3.18, < 5.a", ",").0),
(
"googleapis-common-protos".into(),
parse_req("~> 1.7.0", ",").0,
),
("grpc".into(), parse_req("~> 1.41", ",").0),
],
);
/* ------ googleapis-common-protos ------ */
p.add_dependencies(
"googleapis-common-protos".into(),
RubyVersion::parse("1.7.0"),
vec![
("google-protobuf".into(), parse_req(">= 3.18, < 5.a", ",").0),
(
"googleapis-common-protos-types".into(),
parse_req("~> 1.7", ",").0,
),
("grpc".into(), parse_req("~> 1.41", ",").0),
],
);
p.add_dependencies(
"googleapis-common-protos".into(),
RubyVersion::parse("1.8.0"),
vec![
("google-protobuf".into(), parse_req(">= 3.18, < 5.a", ",").0),
(
"googleapis-common-protos-types".into(),
parse_req("~> 1.20", ",").0,
),
("grpc".into(), parse_req("~> 1.41", ",").0),
],
);
p.add_dependencies(
"googleapis-common-protos-types".into(),
RubyVersion::parse("1.20.0"),
vec![],
);
p.add_dependencies(
"google-protobuf".into(),
RubyVersion::parse("4.30.2"),
vec![],
);
p.add_dependencies("grpc".into(), RubyVersion::parse("1.71.0"), vec![]);
/* ------ root ------ */
p.add_dependencies(
"root".into(),
RubyVersion::parse("0.0.0"),
vec![(
"google-cloud-artifact_registry-v1".into(),
parse_req("~> 0.11.0", ",").0,
)],
);
let sol = resolve(&p, "root".into(), RubyVersion::parse("0.0.0")).unwrap();
assert_eq!(
sol.get("grpc-google-iam-v1"),
Some(&RubyVersion::parse("1.11.0"))
);
assert_eq!(
sol.get("googleapis-common-protos"),
Some(&RubyVersion::parse("1.7.0"))
);
}
Gemfile:
Differences:
Gemfile.lock
Gemfile.new.lock
Investigation
In the case that the dependencies include
grpc-google-iam-v1 @ 1.8.0,1.10.0is selected. However, Ruby bundler selects1.11.0with that Gemfile.The reason why version
1.10.0is selected when version1.8.0is added is probably that PubGrub doesn't simply choose the latest version, but considers the 'flexibility' of the entire dependency graph. The dependency constraint provided by1.10.0(googleapis-common-protos > 1.4) is broader than the constraint of1.11.0(> 1.7.0), which means it potentially has higher compatibility with other packages.Test code