Skip to content

Commit

Permalink
feat: solver refactoring (alire-project#1739)
Browse files Browse the repository at this point in the history
* Priority-based solver

* Compiler priorities

* Fine tweaks related to pins & conflicts

* Self-review

* Fix feasibility check not considering pins

* Optimization: filter out seen linked deps

* Fix issue with search timeout

* Self-review

* Fix submodules after rebase

* Remove dependency on compare_to_case
  • Loading branch information
mosteo authored Nov 23, 2024
1 parent 0bf0571 commit 20dc457
Show file tree
Hide file tree
Showing 18 changed files with 1,639 additions and 945 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/ci-toolchain.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ jobs:
run: ./bin/alr -d -n version | grep 'compiled with version' | grep -q '${{ matrix.gcc_version }}'

- name: Update dependencies
run: ./bin/alr -d -n update
run: ./bin/alr -d -n -f update
# Force because otherwise solving may time out in non-interactive mode

- name: Show dependencies/pins
run: ./bin/alr -d -n -q with --solve || ./bin/alr -n -v -d with --solve
Expand All @@ -112,7 +113,9 @@ jobs:

- name: Move ./bin to ./bin-old to allow for self-build
shell: bash
run: mv ./bin ./bin-old || { sleep 5s && mv ./bin ./bin-old; }
run: |
mv ./bin ./bin-old || \
{ sleep 5s && mv ./bin ./bin-old && echo Old moved on 2nd attempt; }
# Windows doesn't allow to replace a running exe so the next command
# fails otherwise. Also, this mv fails sometimes so we try twice JIC.

Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@
url = https://github.com/mosteo/cstrings
[submodule "deps/lml"]
path = deps/lml
url = https://github.com/mosteo/lml_ada.git
url = https://github.com/mosteo/lml_ada
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Test of solver timeout behaviors
2 changes: 1 addition & 1 deletion alire.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ windows = { ALIRE_OS = "windows" }

# Some dependencies require precise versions during the development cycle:
[[pins]]

[pins.aaa]
url = "https://github.com/mosteo/aaa"
commit = "ddfeffe2d6c8f9d19161df7b31d16d37bef4ba71"
Expand Down Expand Up @@ -127,3 +126,4 @@ command = ["pwsh", "scripts/version-patcher.ps1"]
[actions.'case(os)'.'...']
type = "pre-build"
command = ["scripts/version-patcher.sh"]

1 change: 1 addition & 0 deletions alr_env.gpr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ aggregate project Alr_Env is
"deps/ajunitgen",
"deps/ansi",
"deps/clic",
"deps/compare_to_case",
"deps/cstrings",
"deps/den",
"deps/dirty_booleans",
Expand Down
1 change: 0 additions & 1 deletion src/alire/alire-conditional_trees.ads
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ package Alire.Conditional_Trees with Preelaborate is
with Post'Class => Flatten'Result.Is_Empty or else
Flatten'Result.Is_Value or else
Flatten'Result.Is_Vector;
-- Above Post kept for reference but gnat bugs out during instantiation.
-- Recursively merge all subtree elements in a single value or vector. It
-- can result in an empty tree if a vector is empty, so it returns a tree.

Expand Down
4 changes: 2 additions & 2 deletions src/alire/alire-meta.ads
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ package Alire.Meta with Preelaborate is

package Working_Tree is

Commit : constant String := "unknown";
Changes : constant String := "unknown";
Commit : constant String := "c3dade93403aaacec59097e450a22ce83e0ceb0f";
Changes : constant String := "dirty";

end Working_Tree;

Expand Down
3 changes: 3 additions & 0 deletions src/alire/alire-releases-containers.ads
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ package Alire.Releases.Containers is
Release_Image);
subtype Optional is Optional_Releases.Optional;

function Unit (Element : Releases.Release) return Optional
renames Optional_Releases.Unit;

package Release_Sets
is new Ada.Containers.Indefinite_Ordered_Sets (Releases.Release,
Releases."<",
Expand Down
128 changes: 88 additions & 40 deletions src/alire/alire-solutions.adb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ with Alire.Dependencies.Diffs;
with Alire.Dependencies.Graphs;
with Alire.Errors;
with Alire.Index;
with Alire.Milestones;
with Alire.Root;
with Alire.Solutions.Diffs;
with Alire.Toolchains;
with Alire.Utils.Tables;
with Alire.Utils.Tools;
with Alire.Utils.TTY;
Expand All @@ -21,6 +19,7 @@ package body Alire.Solutions is
package Semver renames Semantic_Versioning;

use type Ada.Containers.Count_Type;
use type Alire.Releases.Release;
use type Semantic_Versioning.Version;
use all type States.Missed_Reasons;

Expand Down Expand Up @@ -51,6 +50,26 @@ package body Alire.Solutions is
else
Mixed);

--------------
-- Contains --
--------------

function Contains (This : Solution;
Release : Alire.Releases.Release) return Boolean
is (for some Rel of This.Releases => Rel = Release);

--------------
-- Contains --
--------------

function Contains (This : Solution;
Release : Milestones.Milestone) return Boolean
is
use type Milestones.Milestone;
begin
return (for some Rel of This.Releases => Rel.Milestone = Release);
end Contains;

----------------------
-- Contains_Release --
----------------------
Expand All @@ -59,6 +78,16 @@ package body Alire.Solutions is
Crate : Crate_Name) return Boolean
is (This.Depends_On (Crate) and then This.State (Crate).Has_Release);

---------------------------
-- Contains_Incompatible --
---------------------------

function Contains_Incompatible (This : Solution;
Release : Alire.Releases.Release)
return Boolean
is (for some Dep of This.Dependencies =>
Dep.Has_Release and then Release.Satisfies (Dep));

----------------
-- Dependency --
----------------
Expand Down Expand Up @@ -92,6 +121,14 @@ package body Alire.Solutions is
return Result;
end Excluding;

-------------------------
-- Depends_Directly_On --
-------------------------

function Depends_Directly_On (This : Solution;
Name : Crate_Name) return Boolean
is (This.Dependencies.Contains (Name));

----------------
-- Depends_On --
----------------
Expand All @@ -111,15 +148,6 @@ package body Alire.Solutions is
Release : Alire.Releases.Release) return Boolean
is (for some Dep of This.Dependencies => Release.Provides (Dep.Crate));

------------------------------
-- Depends_On_Specific_GNAT --
------------------------------

function Depends_On_Specific_GNAT (This : Solution) return Boolean
is (This.Releases.Contains_Or_Provides (GNAT_Crate) and then
(for some Rel of This.Releases.Elements_Providing (GNAT_Crate) =>
Rel.Name /= GNAT_Crate));

----------------------------
-- Empty_Invalid_Solution --
----------------------------
Expand Down Expand Up @@ -241,6 +269,17 @@ package body Alire.Solutions is
return Boolean
is (for some Solved of This.Releases => Solved.Provides (Release));

---------------
-- Satisfies --
---------------

function Satisfies (This : Solution;
Dep : Dependencies.Dependency'Class)
return Boolean
is (This.Links.Contains (Dep.Crate)
or else
(for some Solved of This.Releases => Solved.Satisfies (Dep)));

---------------
-- Resetting --
---------------
Expand Down Expand Up @@ -409,18 +448,48 @@ package body Alire.Solutions is
Env : Properties.Vector)
return Boolean
is
use type Milestones.Milestone;
begin
return
-- Some of the releases in the solution forbid this one release
((for some Solved of This.Releases =>
(for some Dep of Solved.Forbidden (Env) =>
Release.Satisfies (Dep.Value)))
or else
-- The candidate release forbids something in the solution
(for some Dep of Release.Forbidden (Env) =>
(for some Rel of This.Releases => Rel.Satisfies (Dep.Value))));
-- Some of the releases in the solution forbid this one release
(for all Solved of This.Releases =>
Solved.Milestone /= Release.Milestone)
and then
((for some Solved of This.Releases =>
(for some Dep of Solved.Forbidden (Env) =>
Release.Satisfies (Dep.Value)))
or else
-- The candidate release forbids something in the solution
(for some Dep of Release.Forbidden (Env) =>
(for some Rel of This.Releases => Rel.Satisfies (Dep.Value))));
end Forbids;

--------------------
-- Image_One_Line --
--------------------

function Image_One_Line (This : Solution) return String is
use UStrings;
Result : UString;
First : Boolean := True;
begin
for State of This.Dependencies loop
if First then
First := False;
else
Result := Result & "; ";
end if;

if State.Has_Release then
Append (Result, State.Release.Milestone.TTY_Image);
else
Append (Result, State.TTY_Image);
end if;
end loop;

return +Result;
end Image_One_Line;

---------------
-- Including --
---------------
Expand Down Expand Up @@ -508,27 +577,6 @@ package body Alire.Solutions is
-- TODO: instead of using the first discrepancy, we should count all
-- differences and see which one is globally "newer".

-- Prefer one with an installed compiler

for Rel_L of This.Releases loop
if Rel_L.Provides (GNAT_Crate) then
for Rel_R of Than.Releases loop
if Rel_R.Provides (GNAT_Crate) then
if Toolchains.Available.Contains (Rel_L)
xor Toolchains.Available.Contains (Rel_R)
then
return (if Toolchains.Available.Contains (Rel_L)
then Better
else Worse);
else
exit; -- No need to keep checking, 1 compiler in sol
end if;
end if;
end loop;
exit; -- No need to keep checking, only 1 compiler in sol
end if;
end loop;

-- Check releases in both only

for Rel of This.Releases loop
Expand Down
32 changes: 29 additions & 3 deletions src/alire/alire-solutions.ads
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ with Alire.Containers;
with Alire.Dependencies.Containers;
with Alire.Dependencies.States.Maps;
with Alire.Interfaces;
with Alire.Milestones;
with Alire.Optional;
with Alire.Properties;
with Alire.Releases.Containers;
Expand Down Expand Up @@ -186,11 +187,25 @@ package Alire.Solutions is

function Composition (This : Solution) return Compositions;

function Contains (This : Solution;
Release : Alire.Releases.Release) return Boolean;
-- Say if the solution contains exactly this release

function Contains (This : Solution;
Release : Milestones.Milestone) return Boolean;

function Contains_Release (This : Solution;
Crate : Crate_Name) return Boolean;
-- Say if Crate is among the releases (solved or linked) for this solution.
-- It will return False if the solution does not even depend on Crate.

function Contains_Incompatible (This : Solution;
Release : Alire.Releases.Release)
return Boolean;
-- Say if this solution already contains a release for a dependency
-- provided by the given release; in which case Release cannot be added
-- to this solution for a different dependency.

function Crates (This : Solution) return Name_Set;
-- Dependency name closure, independent of the status in the solution, as
-- found by the solver starting from the direct dependencies.
Expand Down Expand Up @@ -221,6 +236,10 @@ package Alire.Solutions is
-- This function allows identifying the concrete dependency that a solved
-- release introduced in the solution.

function Depends_Directly_On (This : Solution;
Name : Crate_Name) return Boolean;
-- Says if Name is one of the dependency state keys in solution

function Depends_On (This : Solution;
Name : Crate_Name) return Boolean;
-- Says if the solution depends on the crate in some way. Will also
Expand All @@ -230,9 +249,6 @@ package Alire.Solutions is
Release : Alire.Releases.Release) return Boolean;
-- Likewise, but take also into account the Release.Provides

function Depends_On_Specific_GNAT (This : Solution) return Boolean;
-- Say if the solution contains a release which is a gnat_something

function Forbidden (This : Solution;
Env : Properties.Vector)
return Dependency_Map;
Expand All @@ -250,6 +266,12 @@ package Alire.Solutions is
-- Check whether the solution already contains or provides a release
-- equivalent to Release.

function Satisfies (This : Solution;
Dep : Dependencies.Dependency'Class)
return Boolean;
-- Say if some release already in solution will satisfy Dep, either
-- directly, via provides, or via link.

function Dependencies_Providing (This : Solution;
Crate : Crate_Name)
return State_Map;
Expand Down Expand Up @@ -346,6 +368,10 @@ package Alire.Solutions is
-- I/O --
---------

function Image_One_Line (This : Solution) return String;
-- Simplified representation containing only solved milestones or unsolved
-- dependencies

procedure Print (This : Solution;
Root : Alire.Releases.Release;
Env : Properties.Vector;
Expand Down
Loading

0 comments on commit 20dc457

Please sign in to comment.