Skip to content

Commit

Permalink
Support Elixir 1.17
Browse files Browse the repository at this point in the history
The latest Elixir changed how IEx should be started. The current
way we're using is `IEx.start` which is still around in 1.17 but
only arity 0. So if you include any shell_opts, the IEx session would immediately crash. If you don't use shell_opts, then things will work as normal.

This makes the needed adjustments to work with Elixir 1.17 and
support shell_opts, including a change to account for .iex.exs
files in the arguments
  • Loading branch information
jjcarstens committed Jul 12, 2024
1 parent 15938db commit ff7323e
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
4 changes: 3 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2.1

latest: &latest
pattern: "^1.15.2-erlang-26.*$"
pattern: "^1.17.*-erlang-27.*$"

jobs:
build-test:
Expand Down Expand Up @@ -52,6 +52,8 @@ workflows:
matrix:
parameters:
tag: [
1.17.2-erlang-27.0.1-alpine-3.20.1,
1.16.3-erlang-26.2.5.2-alpine-3.20.1,
1.15.2-erlang-26.0.2-alpine-3.18.2,
1.14.5-erlang-25.3.2-alpine-3.18.0,
1.13.4-erlang-25.3.2-alpine-3.18.0,
Expand Down
27 changes: 25 additions & 2 deletions lib/extty.ex
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,31 @@ defmodule ExTTY do
{:shell, :start, opts}
end

defp shell_spawner(%{type: :elixir, shell_opts: opts}) do
{Elixir.IEx, :start, opts}
if Version.match?(System.version(), ">= 1.17.0") do
defp shell_spawner(%{type: :elixir, shell_opts: opts}) do
# :iex.start/0 is now the recommended way to start IEx, but
# we want to support the options so we're using the mostly
# private API :iex.start/2 which takes the options as a
# keyword list and an MFA (which is same one used in :iex.start/0).
#
# Previously, the shell opts needed to be a double list since it
# was passed directly to an MFA, so we need to flatten it here.
# Then we also normalize the dot_iex_path arg to match the Elixir 1.17
# change to normalize the arg across the code
shell_opts =
opts
|> List.flatten()
|> Enum.map(fn
{:dot_iex_path, path} -> {:dot_iex, path}
kv -> kv
end)

{:iex, :start, [shell_opts, {:elixir_utils, :noop, []}]}
end
else
defp shell_spawner(%{type: :elixir, shell_opts: opts}) do
{Elixir.IEx, :start, opts}
end
end

defp shell_spawner(state) do
Expand Down
22 changes: 21 additions & 1 deletion test/extty_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule ExTTYTest do
use ExUnit.Case
doctest ExTTY

test "that Elixir starts" do
test "that Elixir starts by default" do
start_supervised!({ExTTY, [handler: self()]})

assert_receive {:tty_data, message}
Expand All @@ -15,6 +15,26 @@ defmodule ExTTYTest do
refute_receive _
end

@tag :tmp_dir
test "that Elixir starts with .iex.exs option", %{tmp_dir: tmp_dir} do
dot_iex = "alias ExTTY, as: TTY"
dot_iex_path = Path.join(tmp_dir, "iex.exs")
File.write!(dot_iex_path, dot_iex)

start_supervised!(
{ExTTY, [handler: self(), type: :elixir, shell_opts: [[dot_iex_path: dot_iex_path]]]}
)

assert_receive {:tty_data, message}
assert message =~ "Interactive Elixir"

# Expect a prompt
assert_receive {:tty_data, "iex(1)> "}

# # Nothing else
refute_receive _
end

test "that Erlang starts" do
start_supervised!({ExTTY, [type: :erlang, handler: self()]})

Expand Down

0 comments on commit ff7323e

Please sign in to comment.