Skip to content
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

macOS App includes elixir, erlang for standalone mode. #929

Merged
merged 11 commits into from
Jan 24, 2022
6 changes: 4 additions & 2 deletions app_builder/lib/app_builder/macos.ex
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,12 @@ defmodule AppBuilder.MacOS do
:logo_path,
:info_plist,
:url_schemes,
:document_types
:document_types,
:additional_paths
])

app_name = Keyword.fetch!(options, :name)
additional_paths = Keyword.get(options, :additional_paths, [])

app_bundle_path = Path.join([Mix.Project.build_path(), "rel", "#{app_name}.app"])
File.rm_rf!(app_bundle_path)
Expand All @@ -109,7 +111,7 @@ defmodule AppBuilder.MacOS do

File.mkdir_p!("tmp")
launcher_src_path = "tmp/Launcher.swift"
File.write!(launcher_src_path, launcher(["/rel/vendor/bin"]))
File.write!(launcher_src_path, launcher(additional_paths))
launcher_path = Path.join([app_bundle_path, "Contents", "MacOS", app_name <> "Launcher"])
File.mkdir_p!(Path.dirname(launcher_path))

Expand Down
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ defmodule Livebook.MixProject do
version: @version,
logo_path: "static/images/logo.png",
url_schemes: ["livebook"],
additional_paths: ["/rel/vendor/erts/bin", "/rel/vendor/elixir/bin"],
paridin marked this conversation as resolved.
Show resolved Hide resolved
document_types: [
%{name: "LiveMarkdown", role: "Editor", extensions: ["livemd"]}
]
Expand Down
32 changes: 8 additions & 24 deletions rel/app/standalone.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ defmodule Standalone do
"""
@spec copy_erlang(Mix.Release.t()) :: Mix.Release.t()
def copy_erlang(release) do
{erts_source, erts_bin_dir, erts_lib_dir, erts_version} = erts_data()
{erts_source, erts_bin_dir, erts_lib_dir, _erts_version} = erts_data()

erts_destination_source = Path.join(release.path, "erts-#{erts_version}/bin")
erts_destination_source = Path.join(release.path, "vendor/erts/bin")
File.mkdir_p!(erts_destination_source)

erts_source
Expand Down Expand Up @@ -38,14 +38,14 @@ defmodule Standalone do
executable!(Path.join(erts_destination_source, "erl"))

# Copy lib
erts_destination_lib = Path.join(release.path, "lib")
erts_destination_lib = Path.join(release.path, "/vendor/lib")
File.mkdir_p!(erts_destination_lib)

erts_lib_dir
|> File.cp_r!(erts_destination_lib, fn _, _ -> false end)

# copy start.boot to <resource_path>/rel/bin
erts_destination_bin = Path.join(release.path, "/bin")
erts_destination_bin = Path.join(release.path, "/vendor/bin")
start_boot_file = Path.join(erts_destination_bin, "start.boot")
File.mkdir_p!(erts_destination_bin)

Expand Down Expand Up @@ -73,24 +73,10 @@ defmodule Standalone do
def copy_elixir(release, elixir_version) do
include_executables_for = Keyword.get(release.options, :include_executables_for, [:unix])

elixir_bin_path = Application.app_dir(:elixir, "../../bin")
bin_path = Path.join(release.path, "bin")
File.mkdir_p!(bin_path)

# download and unzip
standalone_destination = Path.join(release.path, "vendor")
standalone_destination = Path.join(release.path, "vendor/elixir")
download_elixir_at_destination(standalone_destination, elixir_version)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we're already downloading Elixir in out bootstrap script https://github.com/livebook-dev/livebook/blob/main/.github/scripts/app/bootstrap_mac.sh#L123:L124 so we don't need to do it again. I think it's better if this function really just copies the currently running Elixir, similarly how copy_erlang does that for OTP. This way it's going to be super easy to test it with Elixir main when developing too.

Copy link
Contributor

@josevalim josevalim Jan 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried though that we will have even less control over how Elixir is installed. For example, some package installers like to change the bin files. :'(

The downside of using the Elixir precompiled though is that it uses the minimum OTP version (at least until Elixir v1.14) and if you are building from scratch then it is guaranteed you compiled it to the latest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair. But we'll always be building Livebook.app with our bootstrap script where we have full control so I don't think that's gonna be an issue in practice. We need to be running the bootstrap script because we need to have full control over OTP for exactly same reason.


# patch elixir file to look for the right erts <resource_path>/rel/releases/#{release.version}/elixir
patch_elixir(include_executables_for, release,
fn filename ->
Path.join(elixir_bin_path, filename)
end,
fn filename ->
Path.join(release.version_path, filename)
end
)

# patch elixir file to look for the right erts <resource_path>/rel/vendor/bin/elixir
patch_elixir(include_executables_for, release,
fn filename ->
Expand Down Expand Up @@ -134,8 +120,7 @@ defmodule Standalone do
{"elixir",
&(&1
|> File.read!()
|> String.replace(~s[ -pa "$SCRIPT_PATH"/../lib/*/ebin], "")
|> replace_erts_bin(release, ~s["$SCRIPT_PATH"/../../erts-#{release.erts_version}/bin/]))},
|> replace_erts_bin(release, ~s["$SCRIPT_PATH"/../../erts/bin/]))},
paridin marked this conversation as resolved.
Show resolved Hide resolved
{"iex", &File.read!/1}
]
end
Expand All @@ -145,8 +130,7 @@ defmodule Standalone do
{"elixir.bat",
&(&1
|> File.read!()
|> String.replace(~s[goto expand_erl_libs], ~s[goto run])
|> replace_erts_bin(release, ~s[%~dp0\\..\\..\\erts-#{release.erts_version}\\bin\\]))},
|> replace_erts_bin(release, ~s[%~dp0\\..\\..\\erts\\bin\\]))},
paridin marked this conversation as resolved.
Show resolved Hide resolved
{"iex.bat", &File.read!/1}
]
end
Expand All @@ -158,7 +142,7 @@ defmodule Standalone do

defp fetch_body!(url) do
Logger.debug("Downloading elixir from #{url}")
case Livebook.Utils.HTTP.request(:get, url, [timeout: 15_000]) do
case Livebook.Utils.HTTP.request(:get, url, [timeout: :infinity]) do
{:ok, 200, _headers, body} ->
body

Expand Down