Skip to content

Commit 55e91ac

Browse files
jjcarstensmhanberg
andauthored
fix: prompt to run mix deps.get if deps are out of sync on start (#338)
Partially addresses #53 #115 #285 Co-authored-by: Mitchell Hanberg <[email protected]>
1 parent 8b0b7bd commit 55e91ac

File tree

8 files changed

+437
-238
lines changed

8 files changed

+437
-238
lines changed

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
src = self.outPath;
116116
inherit version elixir;
117117
pname = "next-ls-deps";
118-
hash = "sha256-BteNxUWcubVZ/SrFeBxKKV7KHmR39H50kUVaUz53dJs=";
118+
hash = "sha256-G0OZlg3CInKPbmBPWCVnFTzudFdOr9yTwWsKXk+7zVg=";
119119
mixEnv = "prod";
120120
};
121121

lib/next_ls.ex

Lines changed: 104 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -743,10 +743,11 @@ defmodule NextLS do
743743

744744
GenLSP.log(lsp, "[NextLS] Booting runtimes...")
745745

746+
parent = self()
747+
746748
for %{uri: uri, name: name} <- lsp.assigns.workspace_folders do
747749
token = Progress.token()
748750
Progress.start(lsp, token, "Initializing NextLS runtime for folder #{name}...")
749-
parent = self()
750751
working_dir = URI.parse(uri).path
751752

752753
{:ok, _} =
@@ -778,6 +779,9 @@ defmodule NextLS do
778779
send(parent, msg)
779780
else
780781
Progress.stop(lsp, token)
782+
783+
send(parent, {:runtime_failed, name, status})
784+
781785
GenLSP.error(lsp, "[NextLS] Runtime for folder #{name} failed to initialize")
782786
end
783787
end,
@@ -865,47 +869,47 @@ defmodule NextLS do
865869
parent = self()
866870
working_dir = URI.parse(uri).path
867871

868-
# TODO: probably extract this to the Runtime module
869872
{:ok, _} =
870-
DynamicSupervisor.start_child(
871-
lsp.assigns.dynamic_supervisor,
872-
{NextLS.Runtime.Supervisor,
873-
path: Path.join(working_dir, ".elixir-tools"),
874-
name: name,
875-
registry: lsp.assigns.registry,
876-
runtime: [
877-
task_supervisor: lsp.assigns.runtime_task_supervisor,
878-
working_dir: working_dir,
879-
uri: uri,
880-
mix_env: lsp.assigns.init_opts.mix_env,
881-
mix_target: lsp.assigns.init_opts.mix_target,
882-
on_initialized: fn status ->
883-
if status == :ready do
884-
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
885-
GenLSP.log(lsp, "[NextLS] Runtime for folder #{name} is ready...")
886-
msg = {:runtime_ready, name, self()}
887-
888-
dispatch(lsp.assigns.registry, :extensions, fn entries ->
889-
for {pid, _} <- entries, do: send(pid, msg)
890-
end)
891-
892-
send(parent, msg)
893-
else
894-
Progress.stop(lsp, token)
895-
GenLSP.error(lsp, "[NextLS] Runtime for folder #{name} failed to initialize")
896-
end
897-
end,
898-
logger: lsp.assigns.logger
899-
]}
873+
NextLS.Runtime.boot(lsp.assigns.dynamic_supervisor,
874+
path: Path.join(working_dir, ".elixir-tools"),
875+
name: name,
876+
registry: lsp.assigns.registry,
877+
runtime: [
878+
task_supervisor: lsp.assigns.runtime_task_supervisor,
879+
working_dir: working_dir,
880+
uri: uri,
881+
mix_env: lsp.assigns.init_opts.mix_env,
882+
mix_target: lsp.assigns.init_opts.mix_target,
883+
on_initialized: fn status ->
884+
if status == :ready do
885+
Progress.stop(lsp, token, "NextLS runtime for folder #{name} has initialized!")
886+
GenLSP.log(lsp, "[NextLS] Runtime for folder #{name} is ready...")
887+
888+
msg = {:runtime_ready, name, self()}
889+
890+
dispatch(lsp.assigns.registry, :extensions, fn entries ->
891+
for {pid, _} <- entries, do: send(pid, msg)
892+
end)
893+
894+
send(parent, msg)
895+
else
896+
Progress.stop(lsp, token)
897+
898+
send(parent, {:runtime_failed, name, status})
899+
900+
GenLSP.error(lsp, "[NextLS] Runtime for folder #{name} failed to initialize")
901+
end
902+
end,
903+
logger: lsp.assigns.logger
904+
]
900905
)
901906
end
902907

903908
names = Enum.map(removed, & &1.name)
904909

905910
for {pid, %{name: name}} <- entries, name in names do
906911
GenLSP.log(lsp, "[NextLS] Removing workspace folder #{name}")
907-
# TODO: probably extract this to the Runtime module
908-
DynamicSupervisor.terminate_child(lsp.assigns.dynamic_supervisor, pid)
912+
NextLS.Runtime.stop(lsp.assigns.dynamic_supervisor, pid)
909913
end
910914
end)
911915

@@ -995,6 +999,72 @@ defmodule NextLS do
995999
{:noreply, assign(lsp, ready: true, refresh_refs: refresh_refs)}
9961000
end
9971001

1002+
def handle_info({:runtime_failed, name, status}, lsp) do
1003+
{pid, %{init_arg: init_arg}} =
1004+
dispatch(lsp.assigns.registry, :runtime_supervisors, fn entries ->
1005+
Enum.find(entries, fn {_pid, %{name: n}} -> n == name end)
1006+
end)
1007+
1008+
:ok = DynamicSupervisor.terminate_child(lsp.assigns.dynamic_supervisor, pid)
1009+
1010+
if status == {:error, :deps} do
1011+
resp =
1012+
GenLSP.request(
1013+
lsp,
1014+
%GenLSP.Requests.WindowShowMessageRequest{
1015+
id: System.unique_integer([:positive]),
1016+
params: %GenLSP.Structures.ShowMessageRequestParams{
1017+
type: GenLSP.Enumerations.MessageType.error(),
1018+
message: "The NextLS runtime failed with errors on dependencies. Would you like to re-fetch them?",
1019+
actions: [
1020+
%GenLSP.Structures.MessageActionItem{title: "yes"},
1021+
%GenLSP.Structures.MessageActionItem{title: "no"}
1022+
]
1023+
}
1024+
},
1025+
:infinity
1026+
)
1027+
1028+
case resp do
1029+
%GenLSP.Structures.MessageActionItem{title: "yes"} ->
1030+
NextLS.Logger.info(
1031+
lsp.assigns.logger,
1032+
"Running `mix deps.get` in directory #{init_arg[:runtime][:working_dir]}"
1033+
)
1034+
1035+
File.rm_rf!(Path.join(init_arg[:runtime][:working_dir], ".elixir-tools/_build"))
1036+
1037+
case System.cmd("mix", ["deps.get"],
1038+
env: [{"MIX_ENV", "dev"}, {"MIX_BUILD_ROOT", ".elixir-tools/_build"}],
1039+
cd: init_arg[:runtime][:working_dir],
1040+
stderr_to_stdout: true
1041+
) do
1042+
{msg, 0} ->
1043+
NextLS.Logger.info(
1044+
lsp.assigns.logger,
1045+
"Restarting runtime #{name} for directory #{init_arg[:runtime][:working_dir]}"
1046+
)
1047+
1048+
NextLS.Logger.info(lsp.assigns.logger, msg)
1049+
1050+
{:ok, _} =
1051+
DynamicSupervisor.start_child(lsp.assigns.dynamic_supervisor, {NextLS.Runtime.Supervisor, init_arg})
1052+
1053+
{msg, _} ->
1054+
NextLS.Logger.warning(
1055+
lsp.assigns.logger,
1056+
"Failed to run `mix deps.get` in directory #{init_arg[:runtime][:working_dir]} with message: #{msg}"
1057+
)
1058+
end
1059+
1060+
_ ->
1061+
NextLS.Logger.info(lsp.assigns.logger, "Not running `mix deps.get`")
1062+
end
1063+
end
1064+
1065+
{:noreply, lsp}
1066+
end
1067+
9981068
def handle_info({ref, _resp}, %{assigns: %{refresh_refs: refs}} = lsp) when is_map_key(refs, ref) do
9991069
Process.demonitor(ref, [:flush])
10001070
{{token, msg}, refs} = Map.pop(refs, ref)

lib/next_ls/runtime.ex

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ defmodule NextLS.Runtime do
4545
GenServer.call(server, {:compile, opts}, :infinity)
4646
end
4747

48+
def boot(supervisor, opts) do
49+
DynamicSupervisor.start_child(supervisor, {NextLS.Runtime.Supervisor, opts})
50+
end
51+
52+
def stop(supervisor, pid) do
53+
DynamicSupervisor.terminate_child(supervisor, pid)
54+
end
55+
4856
defmacro execute!(runtime, block) do
4957
quote do
5058
{:ok, result} = NextLS.Runtime.execute(unquote_splicing([runtime, block]))
@@ -294,6 +302,9 @@ defmodule NextLS.Runtime do
294302

295303
diagnostics
296304

305+
{:error, %Mix.Error{message: "Can't continue due to errors on dependencies"}} ->
306+
nil
307+
297308
unknown ->
298309
NextLS.Logger.warning(state.logger, "Unexpected compiler response: #{inspect(unknown)}")
299310
[]
@@ -341,6 +352,16 @@ defmodule NextLS.Runtime do
341352
{:stop, {:shutdown, :nodedown}, state}
342353
end
343354

355+
def handle_info(
356+
{port, {:data, "** (Mix) Can't continue due to errors on dependencies" <> _ = data}},
357+
%{port: port} = state
358+
) do
359+
NextLS.Logger.log(state.logger, data)
360+
361+
state.on_initialized.({:error, :deps})
362+
{:noreply, state}
363+
end
364+
344365
def handle_info({port, {:data, data}}, %{port: port} = state) do
345366
NextLS.Logger.info(state.logger, data)
346367
{:noreply, state}

lib/next_ls/runtime/supervisor.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule NextLS.Runtime.Supervisor do
2121
sidecar_name = :"sidecar-#{name}"
2222
db_activity = :"db-activity-#{name}"
2323

24-
Registry.register(registry, :runtime_supervisors, %{name: name})
24+
Registry.register(registry, :runtime_supervisors, %{name: name, init_arg: init_arg})
2525

2626
children = [
2727
{NextLS.Runtime.Sidecar, name: sidecar_name, db: db_name},

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ defmodule NextLS.MixProject do
5959
defp deps do
6060
[
6161
{:exqlite, "~> 0.13.14"},
62-
{:gen_lsp, "~> 0.7"},
62+
{:gen_lsp, "~> 0.8"},
63+
# {:gen_lsp, path: "../gen_lsp"},
6364
{:req, "~> 0.3"},
6465
{:schematic, "~> 0.2"},
6566
{:spitfire, github: "elixir-tools/spitfire"},

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"exqlite": {:hex, :exqlite, "0.13.15", "a32c0763915e2b0d7ced9dd8638802d38e9569053f3b28b815bd0faef1cbe6d9", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "4afcc870a33b57781a1e57cd4294eef68815059d26b774c7cd075536b21434b7"},
2121
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
2222
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
23-
"gen_lsp": {:hex, :gen_lsp, "0.7.3", "08de9b88a8e8e79777bbab78d07ea0d5bbd05d54fdcba2c1d3328a9d091172eb", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2.1", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "ef7288e55be8889aba263658aa74584af0ea5d04848000cb4e16d3c2e21dde37"},
23+
"gen_lsp": {:hex, :gen_lsp, "0.8.1", "847587dfcb1d6c08c1fc9506a2b47af134e64346b14df551c286623c318705f2", [:mix], [{:jason, "~> 1.3", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:schematic, "~> 0.2.1", [hex: :schematic, repo: "hexpm", optional: false]}, {:typed_struct, "~> 0.3.0", [hex: :typed_struct, repo: "hexpm", optional: false]}], "hexpm", "33a4890b707025491a0c7c907a71516d3b37e08567231d0b0ac3950cda8bc088"},
2424
"gproc": {:hex, :gproc, "0.9.1", "f1df0364423539cf0b80e8201c8b1839e229e5f9b3ccb944c5834626998f5b8c", [:rebar3], [], "hexpm", "905088e32e72127ed9466f0bac0d8e65704ca5e73ee5a62cb073c3117916d507"},
2525
"grpcbox": {:hex, :grpcbox, "0.17.1", "6e040ab3ef16fe699ffb513b0ef8e2e896da7b18931a1ef817143037c454bcce", [:rebar3], [{:acceptor_pool, "~> 1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~> 0.15.1", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~> 0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~> 0.9.1", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "4a3b5d7111daabc569dc9cbd9b202a3237d81c80bf97212fbc676832cb0ceb17"},
2626
"hpack": {:hex, :hpack_erl, "0.3.0", "2461899cc4ab6a0ef8e970c1661c5fc6a52d3c25580bc6dd204f84ce94669926", [:rebar3], [], "hexpm", "d6137d7079169d8c485c6962dfe261af5b9ef60fbc557344511c1e65e3d95fb0"},

0 commit comments

Comments
 (0)