Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/hex/mix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ defmodule Hex.Mix do
optional: optional,
label: app
}) do
{String.to_atom(app), to_string(constraint),
{String.to_atom(app), Hex.Solver.constraint_to_requirement!(constraint),
hex: String.to_atom(name), repo: repo || "hexpm", optional: optional}
end

Expand Down
2 changes: 1 addition & 1 deletion lib/hex/remote_converger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ defmodule Hex.RemoteConverger do
for %{repo: repo, name: name, constraint: req, optional: optional, label: app} <- deps do
app = String.to_atom(app)
opts = [optional: optional, hex: name, repo: repo]
{app, to_string(req), opts}
{app, Hex.Solver.constraint_to_requirement!(req), opts}
end
end

Expand Down
14 changes: 12 additions & 2 deletions lib/hex/solver.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver do
_ = """
Expand Down Expand Up @@ -26,7 +26,7 @@ defmodule Hex.Solver do
@type result() :: %{package() => {Version.t(), repo()}}
@opaque constraint() :: Hex.Solver.Requirement.t()

alias Hex.Solver.{Failure, Requirement, Solver}
alias Hex.Solver.{Constraint, Failure, Requirement, Solver}

@doc """
Runs the version solver.
Expand Down Expand Up @@ -85,4 +85,14 @@ defmodule Hex.Solver do
def parse_constraint!(string) do
Requirement.to_constraint!(string)
end

@doc """
Serializes an internal solver constraint as an Elixir version requirement.
"""
@spec constraint_to_requirement!(constraint()) :: String.t()
def constraint_to_requirement!(constraint) do
requirement = Constraint.to_requirement(constraint)
Version.parse_requirement!(requirement)
requirement
end
end
2 changes: 1 addition & 1 deletion lib/hex/solver/assignment.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Assignment do
@moduledoc false
Expand Down
3 changes: 2 additions & 1 deletion lib/hex/solver/constraint.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defprotocol Hex.Solver.Constraint do
@moduledoc false
Expand All @@ -12,4 +12,5 @@ defprotocol Hex.Solver.Constraint do
def intersect(left, right)
def union(left, right)
def compare(left, right)
def to_requirement(constraint)
end
6 changes: 5 additions & 1 deletion lib/hex/solver/constraints/empty.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Empty do
@moduledoc false
Expand Down Expand Up @@ -36,6 +36,10 @@ defmodule Hex.Solver.Constraints.Empty do
clauses: []
end

def to_requirement(%Empty{}) do
"< 0.0.0-0"
end

def to_string(%Empty{}) do
"empty"
end
Expand Down
5 changes: 4 additions & 1 deletion lib/hex/solver/constraints/impl.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Impl do
@moduledoc false
Expand Down Expand Up @@ -34,6 +34,9 @@ defmodule Hex.Solver.Constraints.Impl do

def compare(left, right),
do: unquote(__CALLER__.module).compare(left, right)

def to_requirement(constraint),
do: unquote(__CALLER__.module).to_requirement(constraint)
end
end
end
Expand Down
10 changes: 9 additions & 1 deletion lib/hex/solver/constraints/range.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Range do
@moduledoc false
Expand Down Expand Up @@ -383,6 +383,14 @@ defmodule Hex.Solver.Constraints.Range do
def normalize(%Range{} = range), do: range
def normalize(%Elixir.Version{} = version), do: version

def to_requirement(%Range{min: nil, max: nil}) do
">= 0.0.0-0"
end

def to_requirement(%Range{} = range) do
Range.to_string(range)
end

def to_string(%Range{min: nil, max: nil}) do
"any"
end
Expand Down
6 changes: 5 additions & 1 deletion lib/hex/solver/constraints/union.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Union do
@moduledoc false
Expand Down Expand Up @@ -154,6 +154,10 @@ defmodule Hex.Solver.Constraints.Union do
defp maybe_to_range(%Elixir.Version{} = version), do: Version.to_range(version)
defp maybe_to_range(other), do: other

def to_requirement(%Union{ranges: ranges}) do
Enum.map_join(ranges, " or ", &Constraint.to_requirement/1)
end

def to_string(%Union{ranges: ranges}) do
Enum.map_join(ranges, " or ", &Kernel.to_string/1)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/constraints/util.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Util do
@moduledoc false
Expand Down
6 changes: 5 additions & 1 deletion lib/hex/solver/constraints/version.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Constraints.Version do
@moduledoc false
Expand Down Expand Up @@ -101,6 +101,10 @@ defmodule Hex.Solver.Constraints.Version do
end
end

def to_requirement(%Version{} = version) do
Kernel.to_string(version)
end

def max(left, right) do
case compare(left, right) do
:lt -> right
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/failure.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Failure do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/incompatibility.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Incompatibility do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/package_lister.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.PackageLister do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/package_range.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.PackageRange do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/partial_solution.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.PartialSolution do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/registry.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Registry do
_ = """
Expand Down
26 changes: 23 additions & 3 deletions lib/hex/solver/requirement.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Requirement do
@moduledoc false

alias Hex.Solver.Constraints.{Range, Util}
alias Hex.Solver.Constraints.{Empty, Range, Util}
alias Hex.Solver.Requirement.Parser

@allowed_range_ops [:>, :>=, :<, :<=, :~>]
Expand Down Expand Up @@ -45,7 +45,9 @@ defmodule Hex.Solver.Requirement do
end

defp delex([], acc) do
Util.union(acc)
acc
|> Enum.map(&normalize_constraint/1)
|> Util.union()
end

defp delex([op | rest], acc) when op in [:||, :or] do
Expand Down Expand Up @@ -146,6 +148,24 @@ defmodule Hex.Solver.Requirement do
defp to_version({major, minor, patch, pre, _build}),
do: %Elixir.Version{major: major, minor: minor, patch: patch, pre: pre}

defp normalize_constraint(%Range{
max: %Elixir.Version{major: 0, minor: 0, patch: 0, pre: [0]},
include_max: false
}) do
%Empty{}
end

defp normalize_constraint(
%Range{
min: %Elixir.Version{major: 0, minor: 0, patch: 0, pre: [0]},
include_min: true
} = range
) do
%{range | min: nil, include_min: false}
end

defp normalize_constraint(constraint), do: constraint

# Vendored from https://github.com/elixir-lang/elixir/blob/0ff6522/lib/elixir/lib/version.ex#L495
defmodule Parser do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/solver.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Solver do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/term.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Term do
@moduledoc false
Expand Down
2 changes: 1 addition & 1 deletion lib/hex/solver/util.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Vendored from hex_solver v0.2.3 (f702d44), do not edit manually
# Vendored from hex_solver v0.2.3 (291c624), do not edit manually

defmodule Hex.Solver.Util do
@moduledoc false
Expand Down
45 changes: 45 additions & 0 deletions test/hex/mix_test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
defmodule Hex.MixTest do
use HexTest.Case

test "to_lock/1 persists unconstrained dependencies as valid requirements" do
Hex.Registry.Server.open()
put_dependency("unconstrained_parent", "1.0.0", ">= 0.5.50 or < 0.9.0", false)

lock =
Hex.Mix.to_lock([
{"hexpm", "unconstrained_parent", "unconstrained_parent", "1.0.0"}
])

{:hex, :unconstrained_parent, "1.0.0", _inner_checksum, _managers, deps, "hexpm",
_outer_checksum} = lock[:unconstrained_parent]

assert [{:foo, requirement, hex: :foo, repo: "hexpm", optional: false}] = deps
assert requirement == ">= 0.0.0-0"
assert {:ok, _requirement} = Version.parse_requirement(requirement)
assert Hex.Solver.parse_constraint!(requirement) == %Hex.Solver.Constraints.Range{}
end

test "to_lock/1 persists empty optional dependencies as valid requirements" do
Hex.Registry.Server.open()
put_dependency("empty_parent", "1.0.0", "< 0.0.0-0", true)

lock = Hex.Mix.to_lock([{"hexpm", "empty_parent", "empty_parent", "1.0.0"}])

{:hex, :empty_parent, "1.0.0", _inner_checksum, _managers, deps, "hexpm", _outer_checksum} =
lock[:empty_parent]

assert [{:foo, requirement, hex: :foo, repo: "hexpm", optional: true}] = deps
assert requirement == "< 0.0.0-0"
assert {:ok, _requirement} = Version.parse_requirement(requirement)
assert Hex.Solver.parse_constraint!(requirement) == %Hex.Solver.Constraints.Empty{}
end

test "from_lock/1" do
lock = [ex_doc: {:hex, :ex_doc, "0.1.0"}, postgrex: {:hex, :fork, "0.2.1"}]

Expand Down Expand Up @@ -42,4 +75,16 @@ defmodule Hex.MixTest do
Hex.Mix.from_lock(lock)
refute_received ^message
end

defp put_dependency(package, version, requirement, optional) do
:sys.replace_state(Hex.Registry.Server, fn %{ets: tid, fetched: fetched} = state ->
:ets.insert(tid, [
{{:inner_checksum, "hexpm", package, version}, <<0::256>>},
{{:outer_checksum, "hexpm", package, version}, <<1::256>>},
{{:deps, "hexpm", package, version}, [{"hexpm", "foo", "foo", requirement, optional}]}
])

%{state | fetched: MapSet.put(fetched, {"hexpm", package})}
end)
end
end
35 changes: 35 additions & 0 deletions test/hex/remote_converger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,41 @@ defmodule Hex.RemoteConvergerTest do
end)
end

test "deps/2 returns valid requirements for registry dependencies" do
Hex.Registry.Server.open()
package = "unconstrained_parent"
version = "1.0.0"

:sys.replace_state(Hex.Registry.Server, fn %{ets: tid, fetched: fetched} = state ->
:ets.insert(
tid,
{{:deps, "hexpm", package, version},
[
{"hexpm", "foo", "foo", ">= 0.5.50 or < 0.9.0", false},
{"hexpm", "bar", "bar", "< 0.0.0-0", true}
]}
)

%{state | fetched: MapSet.put(fetched, {"hexpm", package})}
end)

lock = %{unconstrained_parent: {:hex, :unconstrained_parent, version}}
deps = Hex.RemoteConverger.deps(%Mix.Dep{app: :unconstrained_parent}, lock)

assert [
{:foo, any_requirement, optional: false, hex: "foo", repo: nil},
{:bar, empty_requirement, optional: true, hex: "bar", repo: nil}
] = deps

assert any_requirement == ">= 0.0.0-0"
assert {:ok, _requirement} = Version.parse_requirement(any_requirement)
assert Hex.Solver.parse_constraint!(any_requirement) == %Hex.Solver.Constraints.Range{}

assert empty_requirement == "< 0.0.0-0"
assert {:ok, _requirement} = Version.parse_requirement(empty_requirement)
assert Hex.Solver.parse_constraint!(empty_requirement) == %Hex.Solver.Constraints.Empty{}
end

defmodule WarnOutdatedWithHexOption.MixProject do
def project do
[
Expand Down
Loading