Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for conditional dependencies #101

Open
wants to merge 45 commits into
base: main
Choose a base branch
from

Conversation

prsabahrami
Copy link
Contributor

No description provided.

src/solver/clause.rs Outdated Show resolved Hide resolved
src/solver/clause.rs Outdated Show resolved Hide resolved
@prsabahrami
Copy link
Contributor Author

prsabahrami commented Jan 22, 2025

@baszalmstra In the decide function, I am chaining the conditional clauses with the requires clauses and iterate over both set of the clauses but skip the conditionals if none of the conditions are set to true. Let me know what you think!

@baszalmstra
Copy link
Contributor

Mmm since we iterate over all requirements to find the best requirement to make a decision on I think it might be the case that we decide on a conditional requirement before all requirements have been decided on.

You have to early out if a decision is already available for a non-conditional requirement.

@baszalmstra
Copy link
Contributor

Did you already add tests? I think that will help finding edge cases early!

@prsabahrami prsabahrami marked this pull request as ready for review January 24, 2025 15:52
Copy link
Contributor

@baszalmstra baszalmstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review, will review the rest later.

src/lib.rs Outdated Show resolved Hide resolved
src/snapshot.rs Outdated Show resolved Hide resolved
src/solver/clause.rs Outdated Show resolved Hide resolved
Clause::Conditional(package_id, condition, requirement) => {
iter::once(package_id.negative())
.chain(
requirements_to_sorted_candidates[&condition.into()]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesnt need to be sorted at all. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added another map to DependencyProvider which maps VersionSetId to VariableIds. The cache did not directly provide this and I don't think we need it in the cache as we are only using it in two places and so it would make more sense to have them on the DependencyProvider side.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you mean the Solver instead of the DependencyProvider?

Just a thought but Im wondering if we ever care about the solvables instead of the variables? Perhaps it makes sense to store that in the cache instead?

tests/solver.rs Outdated
Comment on lines 1446 to 1452
let b_spec = Spec::parse_union("b 1").next().unwrap().unwrap();
let c_spec = Spec::parse_union("c 1").next().unwrap().unwrap();

let b_version_set = provider.intern_version_set(&b_spec);
let c_version_set = provider.intern_version_set(&c_spec);

let conditional_req = ConditionalRequirement::new(b_version_set, c_version_set.into());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally you add a little string conversion for parsing this so you can do e.g. c 1; if b 1..2 that would make the tests more readable.

}

#[test]
fn test_circular_conditional_dependencies() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add a few tests that include more versions for a single package.

@wolfv
Copy link
Member

wolfv commented Jan 27, 2025

When I look at the tests, it looks like it's hitting some asserts? :)

tests/solver.rs Outdated Show resolved Hide resolved
tests/solver.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@baszalmstra baszalmstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking, there might be a bug in the code as is.

Given the conditional requirement:
A requires C 1..3; if B 1..2

e.g.

A∧(B1∨B2)⟹C1∨C2∨C3

in CNF form that becomes:

¬A∨¬B1∨C1∨C2∨C3
¬A∨¬B2∨C1∨C2∨C3

But currently we convert it to one clause:

¬A∨¬B1 v ¬B2∨C1∨C2∨C3

Which will always evaluate to true if any version of B is selected.

src/solver/clause.rs Outdated Show resolved Hide resolved
src/solver/clause.rs Outdated Show resolved Hide resolved
src/solver/clause.rs Outdated Show resolved Hide resolved
@prsabahrami
Copy link
Contributor Author

prsabahrami commented Jan 28, 2025

@baszalmstra I have added two tests with more versions. One is the example you provided above A requires C 1..3; if B 1..2. The second one is to confirm the behaviour of the solver when the highest version should be installed.

  • A requires B 1..3, A requires C 1..3 if B 1..2.

In this example, C should not be installed as the resolver picks B 2 as the dependency of A.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants