Skip to content

Commit 6762814

Browse files
committed
Merge remote-tracking branch 'eks/Papipo/add-gleam-compiler+' into add-gleam-compiler
2 parents cff76d0 + d8bd1ff commit 6762814

4 files changed

Lines changed: 97 additions & 59 deletions

File tree

lib/mix/lib/mix/dep/loader.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ defmodule Mix.Dep.Loader do
375375
end
376376

377377
defp gleam_dep(%Mix.Dep{opts: opts} = dep, _children = nil, manager, locked?) do
378-
Mix.Gleam.require!()
378+
Mix.Gleam.requirements!()
379379
dest = opts[:dest]
380380
config = File.cd!(dest, fn -> Mix.Gleam.load_config(".") end)
381381
from = Path.join(dest, "gleam.toml")

lib/mix/lib/mix/gleam.ex

Lines changed: 92 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,77 @@
33

44
defmodule Mix.Gleam do
55
# Version that introduced `gleam export package-information` command
6-
@required_gleam_version ">= 1.10.0"
6+
@gleam_version_requirement ">= 1.10.0"
77

8+
@spec load_config(Path.t()) :: config :: map()
89
def load_config(dir) do
910
File.cd!(dir, fn ->
10-
gleam!(~W(export package-information --out /dev/stdout))
11-
|> JSON.decode!()
12-
|> Map.fetch!("gleam.toml")
13-
|> parse_config()
11+
with {:ok, output} <-
12+
gleam(~W(export package-information --out /dev/stdout)),
13+
json <- JSON.decode!(output),
14+
{:ok, gleam_toml} <- Map.fetch(json, "gleam.toml") do
15+
parse_config(gleam_toml)
16+
else
17+
:error ->
18+
{:error, "\"gleam.toml\" key not found in \"gleam export package-information\" output"}
19+
20+
{:error, message} ->
21+
{:error, message}
22+
end
23+
|> assert_ok_value!()
1424
end)
1525
end
1626

17-
def parse_config(json) do
27+
@spec parse_config(map()) :: {:ok, config :: map()} | {:error, message :: binary()}
28+
def parse_config(json) when is_map(json) do
1829
deps =
1930
Map.get(json, "dependencies", %{})
20-
|> Enum.map(&parse_dep/1)
31+
|> Enum.map(&parse_dep!/1)
2132

2233
dev_deps =
2334
Map.get(json, "dev-dependencies", %{})
24-
|> Enum.map(&parse_dep(&1, only: [:dev, :test]))
25-
26-
%{
27-
name: Map.fetch!(json, "name"),
28-
version: Map.fetch!(json, "version"),
29-
deps: deps ++ dev_deps
30-
}
31-
|> maybe_gleam_version(json)
32-
|> maybe_erlang_opts(json["erlang"])
33-
rescue
34-
KeyError ->
35-
Mix.raise("Command \"gleam export package-information\" unexpected format: \n" <> json)
35+
|> Enum.map(&parse_dep!(&1, only: [:dev, :test]))
36+
37+
with {:ok, name} <- Map.fetch(json, "name"),
38+
{:ok, version} <- Map.fetch(json, "version") do
39+
config =
40+
%{
41+
name: name,
42+
version: version,
43+
deps: deps ++ dev_deps
44+
}
45+
|> maybe_gleam_version(json)
46+
|> maybe_erlang_opts(json["erlang"])
47+
48+
{:ok, config}
49+
else
50+
:error ->
51+
{:error,
52+
"Command \"gleam export package-information\" unexpected format: \n" <>
53+
inspect(json, pretty: true, limit: :infinity)}
54+
end
3655
end
3756

38-
defp parse_dep({dep, requirement}, opts \\ []) do
39-
dep = String.to_atom(dep)
57+
defp parse_dep!({dep, requirement}, opts \\ []) do
58+
String.to_atom(dep)
59+
|> build_dep_spec(requirement, opts)
60+
|> assert_ok_value!()
61+
end
4062

41-
spec =
42-
case requirement do
43-
%{"version" => version} ->
44-
{dep, version, opts}
63+
defp build_dep_spec(dep, %{"version" => version}, []),
64+
do: {:ok, {dep, version}}
4565

46-
%{"path" => path} ->
47-
{dep, Keyword.merge(opts, path: Path.expand(path))}
66+
defp build_dep_spec(dep, %{"version" => version}, opts),
67+
do: {:ok, {dep, version, opts}}
4868

49-
%{"git" => git, "ref" => ref} ->
50-
{dep, git: git, ref: ref}
69+
defp build_dep_spec(dep, %{"path" => path}, opts),
70+
do: {:ok, {dep, Keyword.merge(opts, path: Path.expand(path))}}
5171

52-
_ ->
53-
Mix.raise("Gleam package #{dep} has unsupported requirement: #{inspect(requirement)}")
54-
end
72+
defp build_dep_spec(dep, %{"git" => git, "ref" => ref}, _opts),
73+
do: {:ok, {dep, git: git, ref: ref}}
5574

56-
case spec do
57-
{dep, version, []} -> {dep, version}
58-
spec -> spec
59-
end
60-
end
75+
defp build_dep_spec(dep, requirement, _opts),
76+
do: {:error, "Gleam package #{dep} has unsupported requirement: #{inspect(requirement)}"}
6177

6278
defp maybe_gleam_version(config, json) do
6379
case json["gleam"] do
@@ -86,37 +102,58 @@ defmodule Mix.Gleam do
86102
Map.put(config, :application, application)
87103
end
88104

89-
def require!() do
90-
available_version()
91-
|> Version.match?(@required_gleam_version)
105+
@spec requirements!() :: :ok
106+
def requirements!() do
107+
case fetch_gleam_version() do
108+
{:ok, gleam_version} ->
109+
if Version.match?(gleam_version, @gleam_version_requirement) do
110+
{:ok, :ok}
111+
else
112+
{:error,
113+
"Current Gleam version does not meet minimum requirements " <>
114+
"#{@gleam_version_requirement}), got: #{gleam_version}"}
115+
end
116+
117+
{:error, message} ->
118+
{:error, message}
119+
end
120+
|> assert_ok_value!()
92121
end
93122

94-
defp available_version do
95-
case gleam!(["--version"]) do
96-
"gleam " <> version -> Version.parse!(version) |> Version.to_string()
97-
output -> Mix.raise("Command \"gleam --version\" unexpected format: #{output}")
123+
defp fetch_gleam_version() do
124+
case gleam(["--version"]) do
125+
{:ok, version} ->
126+
case Version.parse(version) do
127+
{:ok, parsed_version} ->
128+
{:ok, Version.to_string(parsed_version)}
129+
130+
:error ->
131+
{:error, "Command \"gleam --version\" invalid version format: #{version}"}
132+
end
133+
134+
{:error, output} ->
135+
{:error, "Command \"gleam --version\" unexpected format: #{output}"}
98136
end
99-
rescue
100-
e in Version.InvalidVersionError ->
101-
Mix.raise("Command \"gleam --version\" invalid version format: #{e.version}")
102137
end
103138

104-
defp gleam!(args) do
139+
defp gleam(args) do
105140
System.cmd("gleam", args)
106141
catch
107142
:error, :enoent ->
108-
Mix.raise(
109-
"The \"gleam\" executable is not available in your PATH. " <>
110-
"Please install it, as one of your dependencies requires it"
111-
)
143+
{:error,
144+
"The \"gleam\" executable is not available in your PATH. " <>
145+
"Please install it, as one of your dependencies requires it"}
112146
else
113147
{response, 0} ->
114-
String.trim(response)
148+
{:ok, String.trim(response)}
115149

116150
{response, _} when is_binary(response) ->
117-
Mix.raise("Command \"gleam #{Enum.join(args, " ")}\" failed with reason: #{response}")
151+
{:error, "Command \"gleam #{Enum.join(args, " ")}\" failed with reason: #{response}"}
118152

119153
{_, _} ->
120-
Mix.raise("Command \"gleam #{Enum.join(args, " ")}\" failed")
154+
{:error, "Command \"gleam #{Enum.join(args, " ")}\" failed"}
121155
end
156+
157+
defp assert_ok_value!({:ok, term}), do: term
158+
defp assert_ok_value!({:error, message}) when is_binary(message), do: Mix.raise(message)
122159
end

lib/mix/lib/mix/tasks/deps.compile.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ defmodule Mix.Tasks.Deps.Compile do
314314
end
315315

316316
defp do_gleam(%Mix.Dep{opts: opts} = dep, config) do
317-
Mix.Gleam.require!()
317+
Mix.Gleam.requirements!()
318318
Mix.Project.ensure_structure()
319319

320320
lib = Path.join(Mix.Project.build_path(), "lib")

lib/mix/test/test_helper.exs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ re_import_exclude =
5353

5454
gleam_exclude =
5555
try do
56-
Mix.Gleam.require!()
56+
Mix.Gleam.requirements!()
5757
[]
5858
rescue
5959
Mix.Error -> [gleam: true]
@@ -69,7 +69,8 @@ ex_unit_opts =
6969
trace: !!System.get_env("TRACE"),
7070
exclude:
7171
epmd_exclude ++
72-
os_exclude ++ git_exclude ++ line_exclude ++ cover_exclude ++ re_import_exclude ++ gleam_exclude,
72+
os_exclude ++
73+
git_exclude ++ line_exclude ++ cover_exclude ++ re_import_exclude ++ gleam_exclude,
7374
include: line_include,
7475
assert_receive_timeout: String.to_integer(System.get_env("ELIXIR_ASSERT_TIMEOUT", "300"))
7576
] ++ maybe_seed_opt

0 commit comments

Comments
 (0)