Skip to content

Commit

Permalink
expand local_cycle_hint() logic to catch more cases
Browse files Browse the repository at this point in the history
  • Loading branch information
lucab committed Sep 19, 2024
1 parent 95ccb9f commit 0defe6e
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 18 deletions.
69 changes: 51 additions & 18 deletions crates/uv-resolver/src/pubgrub/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,26 +737,59 @@ impl PubGrubReportFormatter<'_> {
for local_package in workspace_members {
let pkg = PubGrubPackage::from_package(local_package.clone(), None, None.into());
if derived.terms.contains_key(&pkg) {
let DerivationTree::External(External::FromDependencyOf(src1, _, dst1, _)) =
// Check for a direct loop between two dependencies, involving a local package...
if let DerivationTree::External(External::FromDependencyOf(src1, _, dst1, _)) =
derived.cause1.borrow()
else {
continue;
};

let DerivationTree::External(External::FromDependencyOf(src2, _, dst2, _)) =
{
let DerivationTree::External(External::FromDependencyOf(src2, _, dst2, _)) =
derived.cause2.borrow()
else {
continue;
};

// Detect a direct loop condition, with two opposing edges between the same
// packages.
let cycle_edge_first =
src1.name_no_root().is_some() && src1.name_no_root() == dst2.name_no_root();
let cycle_edge_second =
dst1.name_no_root().is_some() && dst1.name_no_root() == src2.name_no_root();
if cycle_edge_first && cycle_edge_second {
output_hints.insert(PubGrubHint::WorkspacePackageNoVersions {
package: pkg.clone(),
});
}
}
// ... otherwise, check left child for an error caused by a failed dependency
// on a local package...
else if let DerivationTree::External(External::NoVersions(_, _)) =
derived.cause1.borrow()
{
let DerivationTree::External(External::FromDependencyOf(_, _, dst, _)) =
derived.cause2.borrow()
else {
continue;
};
if *dst == pkg {
output_hints.insert(PubGrubHint::WorkspacePackageNoVersions {
package: pkg.clone(),
});
}
}
// ... otherwise, check right child for an error caused by a failed dependency
// on a local package...
else if let DerivationTree::External(External::NoVersions(_, _)) =
derived.cause2.borrow()
else {
continue;
};

let cycle_edge_first =
src1.name_no_root().is_some() && src1.name_no_root() == dst2.name_no_root();
let cycle_edge_second =
dst1.name_no_root().is_some() && dst1.name_no_root() == src2.name_no_root();
if cycle_edge_first && cycle_edge_second {
output_hints.insert(PubGrubHint::WorkspacePackageNoVersions {
package: pkg.clone(),
});
{
let DerivationTree::External(External::FromDependencyOf(_, _, dst, _)) =
derived.cause1.borrow()
else {
continue;
};
if *dst == pkg {
output_hints.insert(PubGrubHint::WorkspacePackageNoVersions {
package: pkg.clone(),
});
}
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions crates/uv/tests/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4824,6 +4824,7 @@ fn add_error_local_cycle() -> Result<()> {
dependencies = []
"#})?;

// Pinned constrained, check for a direct dependency loop.
uv_snapshot!(context.filters(), context.add().arg("dagster-webserver==1.6.13"), @r###"
success: false
exit_code: 1
Expand All @@ -4837,5 +4838,30 @@ fn add_error_local_cycle() -> Result<()> {
help: If this is intentional, run `uv add --frozen` to skip the lock and sync steps.
"###);

// Constraint with several available versions, check for an indirect dependency loop.
uv_snapshot!(context.filters(), context.add().arg("dagster-webserver>=1.6.11,<1.7.0"), @r###"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because only the following versions of dagster-webserver are available:
dagster-webserver<=1.6.13
dagster-webserver>1.7.0
and dagster-webserver==1.6.11 depends on your project, we can conclude that all of:
dagster-webserver>=1.6.11,<1.6.12
dagster-webserver>1.6.13,<1.7.0
depend on your project.
And because dagster-webserver==1.6.12 depends on your project, we can conclude that all of:
dagster-webserver>=1.6.11,<1.6.13
dagster-webserver>1.6.13,<1.7.0
depend on your project.
And because dagster-webserver==1.6.13 depends on your project and your project depends on dagster-webserver>=1.6.11,<1.7.0, we can conclude that your project's requirements are unsatisfiable.
hint: Resolution failed on a dependency ('dagster') which has the same name as your local package ('dagster'). Consider checking your project for possible name conflicts with packages in the index.
help: If this is intentional, run `uv add --frozen` to skip the lock and sync steps.
"###);

Ok(())
}

0 comments on commit 0defe6e

Please sign in to comment.