improvement: don't install sat solver in initial installation

improvement: ask user to install sat solver when extending with policies
improvement: validate that a solver exists at compile time when using policies
This commit is contained in:
Zach Daniel 2024-07-24 16:08:39 -04:00
parent 62bda80b38
commit 381870ac3e
4 changed files with 68 additions and 13 deletions

View file

@ -410,7 +410,8 @@ defmodule Ash.Policy.Authorizer do
]
@verifiers [
Ash.Policy.Authorizer.Verifiers.VerifyInAuthorizers
Ash.Policy.Authorizer.Verifiers.VerifyInAuthorizers,
Ash.Policy.Authorizer.Verifiers.VerifySatSolverImplementation
]
use Spark.Dsl.Extension,
@ -453,6 +454,38 @@ defmodule Ash.Policy.Authorizer do
)
end
def install(igniter, module, type, _path, _argv) do
igniter =
with nil <- Igniter.Project.Deps.get_dependency_declaration(igniter, :picosat_elixir),
nil <- Igniter.Project.Deps.get_dependency_declaration(igniter, :simple_sat) do
solver =
Owl.IO.select(
[
{:picosat_elixir, "~> 0.2"},
{:simple_sat, "~> 0.1"}
],
label:
"Which sat solver would you like to use? If on windows, use `simple_sat`, otherwise, use `picosat_elixir`.",
render_as: &to_string(elem(&1, 0))
)
igniter
|> Igniter.Project.Deps.add_dep(solver)
|> Igniter.apply_and_fetch_dependencies()
else
_ ->
igniter
end
igniter
|> Spark.Igniter.add_extension(
module,
type,
:authorizers,
Ash.Policy.Authorizer
)
end
@doc false
# We can't actually validate that they are check modules here
# without causing compile time dependencies

View file

@ -0,0 +1,9 @@
defmodule Ash.Policy.Authorizer.Verifiers.VerifySatSolverImplementation do
@moduledoc false
use Spark.Dsl.Verifier
def verify(_dsl) do
Ash.SatSolver.Implementation.check!()
:ok
end
end

View file

@ -36,8 +36,7 @@ defmodule Mix.Tasks.Ash.Install do
@impl Igniter.Mix.Task
def info(_argv, _source) do
%Igniter.Mix.Task.Info{
composes: ["spark.install"],
adds_deps: [picosat_elixir: "~> 0.2"]
composes: ["spark.install"]
}
end

View file

@ -5,6 +5,8 @@ cond do
def solve_expression(cnf) do
Module.concat([System.get_env("SAT_SOLVER") || "Picosat"]).solve(cnf)
end
def check!, do: :ok
end
Code.ensure_loaded?(Picosat) ->
@ -13,6 +15,8 @@ cond do
def solve_expression(cnf) do
Picosat.solve(cnf)
end
def check!, do: :ok
end
Code.ensure_loaded?(SimpleSat) ->
@ -21,22 +25,33 @@ cond do
def solve_expression(cnf) do
SimpleSat.solve(cnf)
end
def check!, do: :ok
end
true ->
defmodule Ash.SatSolver.Implementation do
@moduledoc false
def solve_expression(_cnf) do
check!()
:ok
end
def check! do
if Code.ensure_loaded?(Picosat) || Code.ensure_loaded?(SimpleSat) do
raise """
No SAT solver available, although one was loaded. This typically means you need to run `mix deps.compile ash --force`
No SAT solver available, although one was loaded.
This typically means that you need to run `mix deps.compile ash --force`
If that doesn't work, please ensure that one of the following dependencies is present in your application to use sat solver features:
* `:picosat_elixir` (recommended) - A NIF wrapper around the PicoSAT SAT solver. Fast, production ready, battle tested.
* `:simple_sat` - A pure Elixir SAT solver. Slower than PicoSAT, but no NIF dependency.
"""
else
end
raise """
No SAT solver available.
@ -47,5 +62,4 @@ cond do
"""
end
end
end
end