-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Add gleam support to Mix #14262
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
Open
Papipo
wants to merge
20
commits into
elixir-lang:main
Choose a base branch
from
Papipo:add-gleam-compiler
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add gleam support to Mix #14262
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
6de56db
Add fixture for gleam support
Papipo cb236e7
Add Gleam integration with Mix
Papipo a08ef98
Add support for git dependencies in gleam packages
Papipo 86266fb
Exclude gleam tests if gleam is missing
Papipo 1ab8e9b
Fix deps.compile for gleam
Papipo b09c9dc
Add support for application_start_module
Papipo 360db23
Handle gleam extra_applications
Papipo f0c0a29
Remove redundant quotes
Papipo 7086167
Do not force `app: false` in gleam deps
Papipo b64f23a
Generate app file for gleam deps on compilation
Papipo fe685f2
Add license and copyright
Papipo b62bc64
Remove unneded try()
Papipo 4c57c3a
Remove unneded try()
Papipo fd7f25b
Remove unneded try()
Papipo 220a0d7
Update lib/mix/test/fixtures/gleam_dep/.gitignore
Papipo b70ff5d
Merge branch 'main' into add-gleam-compiler
Papipo ec0320c
Fix documentation
Papipo 583b504
Proper beam compilation and .app file generation
Papipo bb52564
Use ~w sigil for command
Papipo 3051b90
Extract var
Papipo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8,7 +8,7 @@ | |||||||||||||
defmodule Mix.Dep.Loader do | ||||||||||||||
@moduledoc false | ||||||||||||||
|
||||||||||||||
import Mix.Dep, only: [ok?: 1, mix?: 1, rebar?: 1, make?: 1] | ||||||||||||||
import Mix.Dep, only: [ok?: 1, mix?: 1, rebar?: 1, make?: 1, gleam?: 1] | ||||||||||||||
|
||||||||||||||
@doc """ | ||||||||||||||
Gets all direct children of the current `Mix.Project` | ||||||||||||||
|
@@ -84,9 +84,9 @@ defmodule Mix.Dep.Loader do | |||||||||||||
def load(%Mix.Dep{manager: manager, scm: scm, opts: opts} = dep, children, locked?) do | ||||||||||||||
# The manager for a child dependency is set based on the following rules: | ||||||||||||||
# 1. Set in dependency definition | ||||||||||||||
# 2. From SCM, so that Hex dependencies of a rebar project can be compiled with mix | ||||||||||||||
# 2. From SCM, so that Hex dependencies of a rebar/gleam project can be compiled with mix | ||||||||||||||
# 3. From the parent dependency, used for rebar dependencies from git | ||||||||||||||
# 4. Inferred from files in dependency (mix.exs, rebar.config, Makefile) | ||||||||||||||
# 4. Inferred from files in dependency (mix.exs, rebar.config, Makefile, gleam.toml) | ||||||||||||||
manager = opts[:manager] || scm_manager(scm, opts) || manager || infer_manager(opts[:dest]) | ||||||||||||||
dep = %{dep | manager: manager, status: scm_status(scm, opts)} | ||||||||||||||
|
||||||||||||||
|
@@ -106,6 +106,9 @@ defmodule Mix.Dep.Loader do | |||||||||||||
make?(dep) -> | ||||||||||||||
make_dep(dep) | ||||||||||||||
|
||||||||||||||
gleam?(dep) -> | ||||||||||||||
gleam_dep(dep, children, manager, locked?) | ||||||||||||||
|
||||||||||||||
true -> | ||||||||||||||
{dep, []} | ||||||||||||||
end | ||||||||||||||
|
@@ -220,7 +223,7 @@ defmodule Mix.Dep.Loader do | |||||||||||||
|
||||||||||||||
# Note that we ignore Make dependencies because the | ||||||||||||||
# file based heuristic will always figure it out. | ||||||||||||||
@scm_managers ~w(mix rebar3)a | ||||||||||||||
@scm_managers ~w(mix rebar3 gleam)a | ||||||||||||||
|
||||||||||||||
defp scm_manager(scm, opts) do | ||||||||||||||
managers = scm.managers(opts) | ||||||||||||||
|
@@ -246,6 +249,9 @@ defmodule Mix.Dep.Loader do | |||||||||||||
any_of?(dest, ["Makefile", "Makefile.win"]) -> | ||||||||||||||
:make | ||||||||||||||
|
||||||||||||||
any_of?(dest, ["gleam.toml"]) -> | ||||||||||||||
:gleam | ||||||||||||||
|
||||||||||||||
true -> | ||||||||||||||
nil | ||||||||||||||
end | ||||||||||||||
|
@@ -361,6 +367,20 @@ defmodule Mix.Dep.Loader do | |||||||||||||
{dep, []} | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
defp gleam_dep(%Mix.Dep{opts: opts} = dep, _children = nil, manager, locked?) do | ||||||||||||||
Mix.Gleam.require!() | ||||||||||||||
|
||||||||||||||
config = File.cd!(opts[:dest], fn -> Mix.Gleam.load_config(".") end) | ||||||||||||||
from = Path.join(opts[:dest], "gleam.toml") | ||||||||||||||
Comment on lines
+372
to
+374
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
deps = Enum.map(config[:deps], &to_dep(&1, from, manager, locked?)) | ||||||||||||||
|
||||||||||||||
{dep, deps} | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
defp gleam_dep(%Mix.Dep{opts: opts} = dep, children, manager, locked?) do | ||||||||||||||
{dep, Enum.map(children, &to_dep(&1, opts[:dest], manager, locked?))} | ||||||||||||||
end | ||||||||||||||
|
||||||||||||||
defp mix_children(config, locked?, opts) do | ||||||||||||||
from = Mix.Project.project_file() | ||||||||||||||
|
||||||||||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,116 @@ | ||||||
# SPDX-License-Identifier: Apache-2.0 | ||||||
# SPDX-FileCopyrightText: 2021 The Elixir Team | ||||||
# SPDX-FileCopyrightText: 2012 Plataformatec | ||||||
|
||||||
defmodule Mix.Gleam do | ||||||
Papipo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
# Version that introduced `gleam export package-information` command | ||||||
@required_gleam_version ">= 1.10.0" | ||||||
|
||||||
def load_config(dir) do | ||||||
File.cd!(dir, fn -> | ||||||
gleam!(["export", "package-information", "--out", "/dev/stdout"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|> JSON.decode!() | ||||||
|> Map.fetch!("gleam.toml") | ||||||
|> parse_config() | ||||||
end) | ||||||
end | ||||||
|
||||||
def parse_config(json) do | ||||||
deps = | ||||||
Map.get(json, "dependencies", %{}) | ||||||
|> Enum.map(&parse_dep/1) | ||||||
|
||||||
dev_deps = | ||||||
Map.get(json, "dev-dependencies", %{}) | ||||||
|> Enum.map(&parse_dep(&1, only: :dev)) | ||||||
|
||||||
%{ | ||||||
name: Map.fetch!(json, "name"), | ||||||
version: Map.fetch!(json, "version"), | ||||||
deps: deps ++ dev_deps | ||||||
} | ||||||
|> maybe_gleam_version(json) | ||||||
|> maybe_erlang_opts(json) | ||||||
rescue | ||||||
KeyError -> | ||||||
Mix.raise("Command \"gleam export package-information\" unexpected format: \n" <> json) | ||||||
end | ||||||
|
||||||
defp parse_dep({dep, requirement}, opts \\ []) do | ||||||
dep = String.to_atom(dep) | ||||||
|
||||||
spec = | ||||||
case requirement do | ||||||
%{"version" => version} -> | ||||||
{dep, version, opts} | ||||||
|
||||||
%{"path" => path} -> | ||||||
{dep, Keyword.merge(opts, path: Path.expand(path))} | ||||||
|
||||||
%{"git" => git, "ref" => ref} -> | ||||||
{dep, git: git, ref: ref} | ||||||
|
||||||
_ -> | ||||||
Mix.raise("Gleam package #{dep} has unsupported requirement: #{inspect(requirement)}") | ||||||
end | ||||||
|
||||||
case spec do | ||||||
{dep, version, []} -> {dep, version} | ||||||
spec -> spec | ||||||
end | ||||||
end | ||||||
|
||||||
defp maybe_gleam_version(config, json) do | ||||||
case json["gleam"] do | ||||||
nil -> config | ||||||
version -> Map.put(config, :gleam, version) | ||||||
end | ||||||
end | ||||||
|
||||||
defp maybe_erlang_opts(config, json) do | ||||||
config = | ||||||
case get_in(json, ["erlang", "application_start_module"]) do | ||||||
nil -> config | ||||||
mod -> Map.put(config, :mod, mod) | ||||||
end | ||||||
|
||||||
case get_in(json, ["erlang", "extra_applications"]) do | ||||||
nil -> config | ||||||
extra_applications -> Map.put(config, :extra_applications, extra_applications) | ||||||
end | ||||||
end | ||||||
|
||||||
def require!() do | ||||||
available_version() | ||||||
|> Version.match?(@required_gleam_version) | ||||||
end | ||||||
|
||||||
defp available_version do | ||||||
case gleam!(["--version"]) do | ||||||
"gleam " <> version -> Version.parse!(version) |> Version.to_string() | ||||||
output -> Mix.raise("Command \"gleam --version\" unexpected format: #{output}") | ||||||
end | ||||||
rescue | ||||||
e in Version.InvalidVersionError -> | ||||||
Mix.raise("Command \"gleam --version\" invalid version format: #{e.version}") | ||||||
end | ||||||
|
||||||
defp gleam!(args) do | ||||||
System.cmd("gleam", args) | ||||||
catch | ||||||
:error, :enoent -> | ||||||
Mix.raise( | ||||||
"The \"gleam\" executable is not available in your PATH. " <> | ||||||
"Please install it, as one of your dependencies requires it. " | ||||||
) | ||||||
else | ||||||
{response, 0} -> | ||||||
String.trim(response) | ||||||
|
||||||
{response, _} when is_binary(response) -> | ||||||
Mix.raise("Command \"gleam #{Enum.join(args, " ")}\" failed with reason: #{response}") | ||||||
|
||||||
{_, _} -> | ||||||
Mix.raise("Command \"gleam #{Enum.join(args, " ")}\" failed") | ||||||
end | ||||||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# The directory Mix will write compiled artifacts to. | ||
/_build/ | ||
|
||
# If the VM crashes, it generates a dump, let's ignore it too. | ||
erl_crash.dump | ||
|
||
# BEAM bytecode files. | ||
*.beam | ||
|
||
# Also ignore archive artifacts (built via "mix archive.build"). | ||
*.ez |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name = "gleam_dep" | ||
version = "1.0.0" | ||
|
||
# Fill out these fields if you intend to generate HTML documentation or publish | ||
# your project to the Hex package manager. | ||
# | ||
# description = "" | ||
# licences = ["Apache-2.0"] | ||
# repository = { type = "github", user = "", repo = "" } | ||
# links = [{ title = "Website", href = "" }] | ||
# | ||
# For a full reference of all the available options, you can have a look at | ||
# https://gleam.run/writing-gleam/gleam-toml/. | ||
|
||
[dependencies] | ||
gleam_stdlib = ">= 0.44.0 and < 2.0.0" | ||
gleam_otp = ">= 0.16.1 and < 1.0.0" | ||
|
||
[dev-dependencies] | ||
gleeunit = ">= 1.0.0 and < 2.0.0" | ||
|
||
[erlang] | ||
extra_applications = ["ssl"] | ||
application_start_module = "gleam_dep@somemodule" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# This file was generated by Gleam | ||
# You typically do not need to edit this file | ||
|
||
packages = [ | ||
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" }, | ||
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" }, | ||
{ name = "gleam_stdlib", version = "0.54.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "723BA61A2BAE8D67406E59DD88CEA1B3C3F266FC8D70F64BE9FEC81B4505B927" }, | ||
{ name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" }, | ||
] | ||
|
||
[requirements] | ||
gleam_otp = { version = ">= 0.16.1 and < 1.0.0" } | ||
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } | ||
gleeunit = { version = ">= 1.0.0 and < 2.0.0" } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
-module(collocated_erlang). | ||
-export([hello/0]). | ||
|
||
hello() -> | ||
"Hello from Collocated Erlang!". |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pub fn main() { | ||
True | ||
} | ||
|
||
@external(erlang, "collocated_erlang", "hello") | ||
pub fn erl() -> String |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.