Skip to content

Commit

Permalink
Merge pull request #13 from JakeBecker/build-archives
Browse files Browse the repository at this point in the history
Build archives
  • Loading branch information
JakeBecker authored Oct 25, 2017
2 parents f9023bb + 17d3a09 commit 7e955fc
Show file tree
Hide file tree
Showing 19 changed files with 91 additions and 178 deletions.
6 changes: 0 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
While you can develop ElixirLS on its own, it's easiest to test out changes if you clone the [vscode-elixir-ls](https://github.com/JakeBecker/vscode-elixir-ls) repository instead. It includes ElixirLS as a Git submodule, so you can make your changes in the submodule directory and launch the extension from the parent directory via the included "Launch Extension" configuration in `launch.json`. See the README on that repo for more details.

### Building and running

To build for release, run the `release.sh` script. It compiles these two apps to escripts in the `release` folder. If doing a public release, compile it with Erlang OTP 19, since OTP 20 builds are not backwards-compatible with earlier versions of Erlang.

Elixir escripts typically embed Elixir, which is not what we want because users will want to run it against their own system Elixir installation. In order to support this, there are scripts in the `bin` folder that look for the system-wide Elixir installation and set the `ERL_LIBS` environment variable prior to running the escripts. These scripts are copied to the `release` folder by `release.sh`.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ You can control which warnings are shown using the `elixirLS.dialyzerWarnOpts` s

ElixirLS's Dialyzer integration uses internal, undocumented Dialyzer APIs, and so it won't be robust against changes to these APIs in future Erlang versions.


## Building and running

Run `mix release -o <release_dir>` (which is defined in the `elixir_ls_utils` umbrella child) to build the language server and debugger as a set of `.ez` archives. Then you can set `ERL_LIBS=<release_dir> mix elixir_ls.language_server` or `ERL_LIBS=<release_dir> mix elixir_ls.debugger` to launch. (On Windows, the command would be `SET ERL_LIBS=<release_dir>; mix elixir_ls.language_server`)

If you're packaging these archives in an IDE plugin, make sure to build using Erlang/OTP 19, not OTP 20, because OTP 20 beam files are not backwards-compatible with earlier Erlang versions.

## Acknowledgements and related projects

ElixirLS isn't the first frontend-independent server for Elixir language support. The original was [Alchemist Server](https://github.com/tonini/alchemist-server/), which powers the [Alchemist](https://github.com/tonini/alchemist.el) plugin for Emacs. Another project, [Elixir Sense](https://github.com/msaraiva/elixir_sense), builds upon Alchemist and powers the [Elixir plugin for Atom](https://github.com/msaraiva/atom-elixir) as well as another VS Code plugin, [VSCode Elixir](https://github.com/fr1zle/vscode-elixir). ElixirLS uses Elixir Sense for several code insight features. Credit for those projects goes to their respective authors.
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
defmodule ElixirLS.Debugger.CLI do
defmodule Mix.Tasks.ElixirLs.Debugger do
alias ElixirLS.Utils.WireProtocol
alias ElixirLS.Debugger.{Output, Server}

def main(_args) do
def run(_args) do
WireProtocol.intercept_output(&Output.print/1, &Output.print_err/1)

Application.ensure_all_started(:debugger, :permanent)

Mix.Local.append_archives
Mix.Local.append_paths

WireProtocol.stream_packets(&Server.receive_packet/1)
end
end
17 changes: 1 addition & 16 deletions apps/debugger/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ defmodule ElixirLS.Debugger.Mixfile do
start_permanent: true,
build_per_environment: false,
consolidate_protocols: false,
deps: deps(),
escript: escript()]
deps: deps()]
end

# Configuration for the OTP application
Expand Down Expand Up @@ -42,18 +41,4 @@ defmodule ElixirLS.Debugger.Mixfile do
[{:elixir_sense, github: "JakeBecker/elixir_sense"},
{:elixir_ls_utils, in_umbrella: true}]
end

defp escript do
[main_module: ElixirLS.Debugger.CLI,
app: nil,
embed_elixir: false,
path: "../../release/debugger",
strip_beam: false,
comment: escript_comment()]
end

defp escript_comment do
"Requires Elixir but does not embed it. Run via the included exscript.sh (Unix) or \
exscript.bat (Windows, TODO) scripts to set ERL_LIBS."
end
end
34 changes: 34 additions & 0 deletions apps/elixir_ls_utils/lib/mix.tasks.release.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule Mix.Tasks.Release do
@switches [destination: :string]
@aliases [o: :destination]

def run(args) do
version_warning()
{opts, _} = OptionParser.parse!(args, aliases: @aliases, switches: @switches)
destination = opts[:destination] || "release"

Path.join(destination, "*.ez")
|> Path.wildcard()
|> Enum.each(&File.rm(&1))

Mix.Task.run("archive.build.deps", [
"--skip",
"mix_task_archive_deps",
"--destination",
destination
])
end

defp version_warning do
{otp_version, _} = Integer.parse(to_string(:erlang.system_info(:otp_release)))

if otp_version > 19 do
IO.warn(
"Building with Erlang/OTP #{otp_version}. Make sure to build with OTP 19 if " <>
"publishing the compiled packages because modules built with higher versions are not " <>
"backwards-compatible.",
[]
)
end
end
end
3 changes: 2 additions & 1 deletion apps/elixir_ls_utils/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ defmodule ElixirLS.Utils.Mixfile do
#
# Type "mix help deps" for more examples and options
defp deps do
[{:poison, "~> 3.0"}]
[{:poison, "~> 3.0"},
{:mix_task_archive_deps, "~> 0.4.0"}]
end
end
6 changes: 5 additions & 1 deletion apps/language_server/lib/language_server/build.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule ElixirLS.LanguageServer.Build do
Server.build_finished(parent, {:error, mixfile_diagnostics})
end
end
Logger.info("Compile took #{div(us, 1000)} milliseconds")
JsonRpc.log_message(:info, "Compile took #{div(us, 1000)} milliseconds")
end, [:monitor])
end
end
Expand Down Expand Up @@ -96,7 +96,11 @@ defmodule ElixirLS.LanguageServer.Build do
end

Mix.Task.clear()

# The project may override our logger config, so we reset it after loading their config
logger_config = Application.get_all_env(:logger)
Mix.Task.run("loadconfig")
Mix.Config.persist(logger: logger_config)

# If using Elixir 1.6 or higher, we can get diagnostics if Mixfile fails to load
if Version.match?(System.version(), ">= 1.6.0-dev") do
Expand Down
17 changes: 0 additions & 17 deletions apps/language_server/lib/language_server/cli.ex

This file was deleted.

6 changes: 3 additions & 3 deletions apps/language_server/lib/language_server/dialyzer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
def handle_call({:analyze, warn_opts}, _from, state) do
state =
if Mix.Project.get() do
Logger.info("[ElixirLS Dialyzer] Checking for stale beam files")
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Checking for stale beam files")
new_timestamp = adjusted_timestamp()

{removed_files, file_changes} =
Expand Down Expand Up @@ -281,7 +281,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
end

# Analyze!
Logger.info(
JsonRpc.log_message(:info,
"[ElixirLS Dialyzer] Analyzing #{Enum.count(modules_to_analyze)} modules: " <>
"#{inspect(modules_to_analyze)}"
)
Expand All @@ -299,7 +299,7 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
{active_plt, mod_deps, md5, warnings, timestamp}
end)

Logger.info("[ElixirLS Dialyzer] Analysis finished in #{div(us, 1000)} milliseconds")
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Analysis finished in #{div(us, 1000)} milliseconds")
analysis_finished(parent, :ok, active_plt, mod_deps, md5, warnings, timestamp)
end

Expand Down
4 changes: 2 additions & 2 deletions apps/language_server/lib/language_server/dialyzer/manifest.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ defmodule ElixirLS.LanguageServer.Dialyzer.Manifest do
fn ->
# Because the manifest file can be several megabytes, we do a write-then-rename
# to reduce the likelihood of corrupting the manifest
Logger.info("[ElixirLS Dialyzer] Writing manifest...")
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Writing manifest...")
File.mkdir_p!(Path.dirname(manifest_path))
tmp_manifest_path = manifest_path <> ".new"
File.write!(tmp_manifest_path, :erlang.term_to_binary(manifest_data, compressed: 9))
File.rename(tmp_manifest_path, manifest_path)
File.touch!(manifest_path, timestamp)
Logger.info("[ElixirLS Dialyzer] Done writing manifest.")
JsonRpc.log_message(:info, "[ElixirLS Dialyzer] Done writing manifest.")
end,
[]
)
Expand Down
27 changes: 27 additions & 0 deletions apps/language_server/lib/mix.tasks.elixir_ls.language_server.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Mix.Tasks.ElixirLs.LanguageServer do
alias ElixirLS.Utils.WireProtocol
alias ElixirLS.LanguageServer.JsonRpc

def run(_args) do
WireProtocol.intercept_output(&JsonRpc.print/1, &JsonRpc.print_err/1)
configure_logger()
Application.ensure_all_started(:language_server, :permanent)
Mix.shell(ElixirLS.LanguageServer.MixShell)
WireProtocol.stream_packets(&JsonRpc.receive_packet/1)
end

defp configure_logger do
use Mix.Config

Mix.Config.persist(logger: [
handle_otp_reports: true,
handle_sasl_reports: true,
level: :warn,
backends: [{ElixirLS.LanguageServer.LoggerBackend, :lsp_logger_backend}]
])

logger = Process.whereis(Logger)
if logger, do: Logger.App.stop()
Logger.App.start()
end
end
17 changes: 1 addition & 16 deletions apps/language_server/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ defmodule ElixirLS.LanguageServer.Mixfile do
start_permanent: true,
build_per_environment: false,
consolidate_protocols: false,
deps: deps(),
escript: escript()]
deps: deps()]
end

# Configuration for the OTP application
Expand All @@ -39,18 +38,4 @@ defmodule ElixirLS.LanguageServer.Mixfile do
{:elixir_sense, github: "JakeBecker/elixir_sense"},
{:forms, "~> 0.0.1"}]
end

defp escript do
[main_module: ElixirLS.LanguageServer.CLI,
app: nil,
embed_elixir: false,
path: "../../release/language_server",
strip_beam: false,
comment: escript_comment()]
end

defp escript_comment do
"Requires Elixir but does not embed it. Run via the included exscript.sh (Unix) or \
exscript.bat (Windows) scripts to set ERL_LIBS."
end
end
10 changes: 6 additions & 4 deletions apps/language_server/test/dialyzer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ defmodule ElixirLS.LanguageServer.DialyzerTest do
end
))

assert capture_log(fn ->
Server.receive_packet(server, did_save(SourceFile.path_to_uri("lib/b.ex")))
assert_receive publish_diagnostics_notif(^file_a, []), 20000
end) =~ "[ElixirLS Dialyzer] Analyzing 2 modules: [A, B]"
Server.receive_packet(server, did_save(SourceFile.path_to_uri("lib/b.ex")))
assert_receive publish_diagnostics_notif(^file_a, []), 20000

assert_receive notification("window/logMessage", %{
"message" => "[ElixirLS Dialyzer] Analyzing 2 modules: [A, B]"
})
end)

# Stop while we're still capturing logs to avoid log leakage
Expand Down
9 changes: 0 additions & 9 deletions bin/debugger.bat

This file was deleted.

15 changes: 0 additions & 15 deletions bin/debugger.sh

This file was deleted.

38 changes: 0 additions & 38 deletions bin/exscript.bat

This file was deleted.

27 changes: 0 additions & 27 deletions bin/exscript.sh

This file was deleted.

1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"logger_file_backend": {:hex, :logger_file_backend, "0.0.9", "5c2f7d4a28431e695cdf94d191523dbafe609321a67bb654254897f546c393db", [:mix], []},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
"mix_task_archive_deps": {:hex, :mix_task_archive_deps, "0.4.0", "95cf15d1b04e10c6319e16a82b88109db2e8164f63e733c1742dfaf8ed9cace5", [], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
}
16 changes: 0 additions & 16 deletions release.sh

This file was deleted.

0 comments on commit 7e955fc

Please sign in to comment.