mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-20 10:05:57 +08:00
Remove todos related to Elixir v1.15 (#2354)
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
parent
04eaab448b
commit
82b633d595
|
@ -38,7 +38,6 @@ defmodule Livebook.Runtime.ErlDist do
|
|||
Livebook.Runtime.ErlDist.RuntimeServer,
|
||||
Livebook.Runtime.ErlDist.EvaluatorSupervisor,
|
||||
Livebook.Runtime.ErlDist.IOForwardGL,
|
||||
Livebook.Runtime.ErlDist.LoggerGLBackend,
|
||||
Livebook.Runtime.ErlDist.LoggerGLHandler,
|
||||
Livebook.Runtime.ErlDist.Sink,
|
||||
Livebook.Runtime.ErlDist.SmartCellGL
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
defmodule Livebook.Runtime.ErlDist.LoggerGLBackend do
|
||||
# A logger backend used to forward logs to Livebook,
|
||||
# as with regular output.
|
||||
#
|
||||
# The backend is based on `Logger.Backends.Console`,
|
||||
# but instead of logging to the console, it sends
|
||||
# log output to the group leader of the source process,
|
||||
# provided the group leader is an instance of
|
||||
# `Livebook.Runtime.Evaluator.IOProxy`.
|
||||
#
|
||||
# Basic configuration is taken from the console
|
||||
# logger configuration to match its formatting.
|
||||
|
||||
@behaviour :gen_event
|
||||
|
||||
@type state :: %{
|
||||
colors: keyword(),
|
||||
format: binary(),
|
||||
level: atom(),
|
||||
metadata: list(atom())
|
||||
}
|
||||
|
||||
@impl true
|
||||
def init(__MODULE__) do
|
||||
config = Application.get_env(:logger, :console, [])
|
||||
{:ok, init_state(config)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event({level, gl, {Logger, msg, ts, md}}, state) do
|
||||
%{level: log_level} = state
|
||||
|
||||
if meet_level?(level, log_level) do
|
||||
log_event(level, msg, ts, md, gl, state)
|
||||
end
|
||||
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def handle_event(_, state) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def code_change(_old_vsn, state, _extra) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(_message, state) do
|
||||
{:ok, :ok, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(_message, state) do
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def terminate(_reason, _state) do
|
||||
:ok
|
||||
end
|
||||
|
||||
defp init_state(config) do
|
||||
level = Keyword.get(config, :level)
|
||||
format = Logger.Formatter.compile(Keyword.get(config, :format))
|
||||
colors = configure_colors(config)
|
||||
metadata = Keyword.get(config, :metadata, []) |> configure_metadata()
|
||||
|
||||
%{format: format, metadata: metadata, level: level, colors: colors}
|
||||
end
|
||||
|
||||
defp configure_metadata(:all), do: :all
|
||||
defp configure_metadata(metadata), do: Enum.reverse(metadata)
|
||||
|
||||
defp configure_colors(config) do
|
||||
colors = Keyword.get(config, :colors, [])
|
||||
|
||||
%{
|
||||
debug: Keyword.get(colors, :debug, :cyan),
|
||||
info: Keyword.get(colors, :info, :normal),
|
||||
warn: Keyword.get(colors, :warn, :yellow),
|
||||
error: Keyword.get(colors, :error, :red),
|
||||
enabled: Keyword.get(colors, :enabled, IO.ANSI.enabled?())
|
||||
}
|
||||
end
|
||||
|
||||
defp meet_level?(_lvl, nil), do: true
|
||||
|
||||
defp meet_level?(lvl, min) do
|
||||
Logger.compare_levels(lvl, min) != :lt
|
||||
end
|
||||
|
||||
defp log_event(level, msg, ts, md, gl, state) do
|
||||
output = format_event(level, msg, ts, md, state)
|
||||
|
||||
if Livebook.Runtime.ErlDist.NodeManager.known_io_proxy?(gl) do
|
||||
async_io(gl, output)
|
||||
else
|
||||
send(Livebook.Runtime.ErlDist.NodeManager, {:orphan_log, output})
|
||||
end
|
||||
end
|
||||
|
||||
def async_io(device, output) when is_pid(device) do
|
||||
send(device, {:io_request, self(), make_ref(), {:put_chars, :unicode, output}})
|
||||
end
|
||||
|
||||
defp format_event(level, msg, ts, md, state) do
|
||||
%{format: format, metadata: keys, colors: colors} = state
|
||||
|
||||
format
|
||||
|> Logger.Formatter.format(level, msg, ts, take_metadata(md, keys))
|
||||
|> color_event(level, colors, md)
|
||||
end
|
||||
|
||||
defp take_metadata(metadata, :all) do
|
||||
metadata
|
||||
end
|
||||
|
||||
defp take_metadata(metadata, keys) do
|
||||
Enum.reduce(keys, [], fn key, acc ->
|
||||
case Keyword.fetch(metadata, key) do
|
||||
{:ok, val} -> [{key, val} | acc]
|
||||
:error -> acc
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp color_event(data, _level, %{enabled: false}, _md), do: data
|
||||
|
||||
defp color_event(data, level, %{enabled: true} = colors, md) do
|
||||
color = md[:ansi_color] || Map.fetch!(colors, level)
|
||||
IO.ANSI.format([color, data])
|
||||
end
|
||||
end
|
|
@ -91,20 +91,15 @@ defmodule Livebook.Runtime.ErlDist.NodeManager do
|
|||
Process.unregister(:standard_error)
|
||||
Process.register(io_forward_gl_pid, :standard_error)
|
||||
|
||||
# TODO: remove logger backend once we require Elixir v1.15
|
||||
if Code.ensure_loaded?(Logger) and function_exported?(Logger, :add_handlers, 1) do
|
||||
{:ok, _pid} = Livebook.Runtime.ErlDist.Sink.start_link()
|
||||
{:ok, _pid} = Livebook.Runtime.ErlDist.Sink.start_link()
|
||||
|
||||
:logger.add_handler(:livebook_gl_handler, Livebook.Runtime.ErlDist.LoggerGLHandler, %{
|
||||
formatter: Logger.Formatter.new(),
|
||||
filters: [
|
||||
code_server_logs:
|
||||
{&Livebook.Runtime.ErlDist.LoggerGLHandler.filter_code_server_logs/2, nil}
|
||||
]
|
||||
})
|
||||
else
|
||||
Logger.add_backend(Livebook.Runtime.ErlDist.LoggerGLBackend)
|
||||
end
|
||||
:logger.add_handler(:livebook_gl_handler, Livebook.Runtime.ErlDist.LoggerGLHandler, %{
|
||||
formatter: Logger.Formatter.new(),
|
||||
filters: [
|
||||
code_server_logs:
|
||||
{&Livebook.Runtime.ErlDist.LoggerGLHandler.filter_code_server_logs/2, nil}
|
||||
]
|
||||
})
|
||||
|
||||
# Set `ignore_module_conflict` only for the NodeManager lifetime.
|
||||
initial_ignore_module_conflict = Code.compiler_options()[:ignore_module_conflict]
|
||||
|
@ -154,12 +149,7 @@ defmodule Livebook.Runtime.ErlDist.NodeManager do
|
|||
Process.unregister(:standard_error)
|
||||
Process.register(state.original_standard_error, :standard_error)
|
||||
|
||||
# TODO: remove logger backend once we require Elixir v1.15
|
||||
if Code.ensure_loaded?(Logger) and function_exported?(Logger, :add_handlers, 1) do
|
||||
:logger.remove_handler(:livebook_gl_handler)
|
||||
else
|
||||
Logger.remove_backend(Livebook.Runtime.ErlDist.LoggerGLBackend)
|
||||
end
|
||||
:logger.remove_handler(:livebook_gl_handler)
|
||||
|
||||
if state.unload_modules_on_termination do
|
||||
ErlDist.unload_required_modules()
|
||||
|
|
|
@ -387,7 +387,7 @@ defmodule Livebook.Runtime.ErlDist.RuntimeServer do
|
|||
def handle_info({:orphan_log, output}, state) do
|
||||
with %{} = evaluator <- state.last_evaluator,
|
||||
{:group_leader, io_proxy} <- Process.info(evaluator.pid, :group_leader) do
|
||||
ErlDist.LoggerGLBackend.async_io(io_proxy, output)
|
||||
ErlDist.LoggerGLHandler.async_io(io_proxy, output)
|
||||
end
|
||||
|
||||
{:noreply, state}
|
||||
|
|
|
@ -613,7 +613,7 @@ defmodule Livebook.Runtime.Evaluator do
|
|||
|
||||
defp eval(:elixir, code, binding, env) do
|
||||
{{result, extra_diagnostics}, diagnostics} =
|
||||
with_diagnostics([log: true], fn ->
|
||||
Code.with_diagnostics([log: true], fn ->
|
||||
try do
|
||||
quoted = Code.string_to_quoted!(code, file: env.file)
|
||||
|
||||
|
@ -816,17 +816,6 @@ defmodule Livebook.Runtime.Evaluator do
|
|||
Enum.reject(code_markers, &(&1.line == 0))
|
||||
end
|
||||
|
||||
# TODO: remove once we require Elixir v1.15
|
||||
if Code.ensure_loaded?(Code) and function_exported?(Code, :with_diagnostics, 2) do
|
||||
defp with_diagnostics(opts, fun) do
|
||||
Code.with_diagnostics(opts, fun)
|
||||
end
|
||||
else
|
||||
defp with_diagnostics(_opts, fun) do
|
||||
{fun.(), []}
|
||||
end
|
||||
end
|
||||
|
||||
defp extra_diagnostic?(%SyntaxError{}), do: true
|
||||
defp extra_diagnostic?(%TokenMissingError{}), do: true
|
||||
|
||||
|
@ -847,11 +836,6 @@ defmodule Livebook.Runtime.Evaluator do
|
|||
do: {:variable, var},
|
||||
into: identifiers_used
|
||||
|
||||
identifiers_used =
|
||||
for var <- tracer_info.undefined_vars,
|
||||
do: {:variable, var},
|
||||
into: identifiers_used
|
||||
|
||||
identifiers_defined =
|
||||
for var <- vars_defined(context, prev_context),
|
||||
do: {{:variable, var}, context.id},
|
||||
|
|
|
@ -92,25 +92,11 @@ defmodule Livebook.Runtime.Evaluator.Doctests do
|
|||
defp report_doctest_result(%{state: {:failed, failure}} = test, lines) do
|
||||
doctest_line = test.tags.doctest_line
|
||||
[prompt_line | _] = lines = Enum.drop(lines, doctest_line - 1)
|
||||
|
||||
end_line =
|
||||
if end_line = test.tags[:doctest_data][:end_line] do
|
||||
end_line
|
||||
else
|
||||
# TODO: Remove this branch once we require Elixir v1.15+
|
||||
interval =
|
||||
lines
|
||||
|> Enum.take_while(&(not end_of_doctest?(&1)))
|
||||
|> length()
|
||||
|
||||
interval + doctest_line - 1
|
||||
end
|
||||
end_line = test.tags[:doctest_data][:end_line]
|
||||
|
||||
end_line =
|
||||
with {:error, %ExUnit.AssertionError{}, [{_, _, _, location} | _]} <- failure,
|
||||
assertion_line = location[:line],
|
||||
# TODO: Remove this check once we require Elixir v1.15+
|
||||
true <- is_integer(test.tags[:doctest_data][:end_line]),
|
||||
true <- assertion_line in doctest_line..end_line do
|
||||
end_line -
|
||||
length(
|
||||
|
@ -148,17 +134,6 @@ defmodule Livebook.Runtime.Evaluator.Doctests do
|
|||
end
|
||||
end
|
||||
|
||||
defp end_of_doctest?(line) do
|
||||
case String.trim_leading(line) do
|
||||
"" -> true
|
||||
"```" <> _ -> true
|
||||
"~~~" <> _ -> true
|
||||
"'''" <> _ -> true
|
||||
"\"\"\"" <> _ -> true
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
defp define_test_module(doctests_specs) do
|
||||
id =
|
||||
doctests_specs
|
||||
|
|
|
@ -14,8 +14,7 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
|||
requires_used: MapSet.new(),
|
||||
requires_defined: MapSet.new(),
|
||||
imports_used?: false,
|
||||
imports_defined?: false,
|
||||
undefined_vars: MapSet.new()
|
||||
imports_defined?: false
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
modules_used: MapSet.t(),
|
||||
|
@ -25,8 +24,7 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
|||
requires_used: MapSet.t(),
|
||||
requires_defined: MapSet.t(),
|
||||
imports_used?: boolean(),
|
||||
imports_defined?: boolean(),
|
||||
undefined_vars: MapSet.t()
|
||||
imports_defined?: boolean()
|
||||
}
|
||||
|
||||
@doc false
|
||||
|
@ -62,13 +60,11 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
|||
if(env.module, do: [], else: [:import_defined]) ++
|
||||
[{:module_used, module}, {:alias_used, module}]
|
||||
|
||||
{:imported_function, meta, module, name, _arity} ->
|
||||
var? = Keyword.has_key?(meta, :if_undefined)
|
||||
[{:module_used, module}, {:import_used, name, var?}]
|
||||
{:imported_function, _meta, module, _name, _arity} ->
|
||||
[{:module_used, module}, :import_used]
|
||||
|
||||
{:imported_macro, meta, module, name, _arity} ->
|
||||
var? = Keyword.has_key?(meta, :if_undefined)
|
||||
[{:module_used, module}, {:import_used, name, var?}]
|
||||
{:imported_macro, _meta, module, _name, _arity} ->
|
||||
[{:module_used, module}, :import_used]
|
||||
|
||||
{:alias, _meta, alias, as, _opts} ->
|
||||
if(env.module, do: [], else: [{:alias_defined, as, alias}]) ++
|
||||
|
@ -136,14 +132,8 @@ defmodule Livebook.Runtime.Evaluator.Tracer do
|
|||
update_in(info.requires_defined, &MapSet.put(&1, module))
|
||||
end
|
||||
|
||||
defp apply_update(info, {:import_used, name, var?}) do
|
||||
info = put_in(info.imports_used?, true)
|
||||
|
||||
if var? do
|
||||
update_in(info.undefined_vars, &MapSet.put(&1, {name, nil}))
|
||||
else
|
||||
info
|
||||
end
|
||||
defp apply_update(info, :import_used) do
|
||||
put_in(info.imports_used?, true)
|
||||
end
|
||||
|
||||
defp apply_update(info, :import_defined) do
|
||||
|
|
|
@ -834,22 +834,6 @@ defmodule Livebook.Runtime.EvaluatorTest do
|
|||
assert {:variable, {:z, nil}} not in identifiers.used
|
||||
end
|
||||
|
||||
test "reports parentheses-less arity-0 import as a used variable", %{evaluator: evaluator} do
|
||||
# TODO: remove all logic around undefined unused vars once we require Elixir v1.15
|
||||
Code.put_compiler_option(:on_undefined_variable, :warn)
|
||||
|
||||
identifiers =
|
||||
"""
|
||||
self
|
||||
"""
|
||||
|> eval(evaluator, 0)
|
||||
|
||||
Code.put_compiler_option(:on_undefined_variable, :raise)
|
||||
|
||||
assert {:variable, {:self, nil}} in identifiers.used
|
||||
assert :imports in identifiers.used
|
||||
end
|
||||
|
||||
test "module definition", %{evaluator: evaluator} do
|
||||
identifiers =
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue