Skip to content

Commit 90395bb

Browse files
committed
Bring back rel/app/standalone.exs
1 parent bce66a7 commit 90395bb

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

rel/app/standalone.exs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
defmodule Standalone do
2+
require Logger
3+
4+
@doc """
5+
Copies OTP into the release.
6+
"""
7+
@spec copy_otp(Mix.Release.t()) :: Mix.Release.t()
8+
def copy_otp(release) do
9+
erts_source = Path.join(:code.root_dir(), "erts-#{release.erts_version}")
10+
otp_bin_dir = Path.join(:code.root_dir(), "bin")
11+
otp_lib_dir = :code.lib_dir()
12+
vendor_otp_dir = vendor_dir(release, "otp")
13+
File.rm_rf!(vendor_otp_dir)
14+
File.mkdir_p!(vendor_otp_dir)
15+
16+
# 1. copy erts/{bin,include}
17+
release_erts_bin_dir = Path.join([vendor_otp_dir, "erts-#{release.erts_version}", "bin"])
18+
File.mkdir_p!(release_erts_bin_dir)
19+
cp_r!(Path.join(erts_source, "bin"), release_erts_bin_dir)
20+
21+
File.rm(Path.join(release_erts_bin_dir, "erl"))
22+
File.rm(Path.join(release_erts_bin_dir, "erl.ini"))
23+
24+
File.write!(Path.join(release_erts_bin_dir, "erl"), ~S"""
25+
#!/bin/sh
26+
SELF=$(readlink "$0" || true)
27+
if [ -z "$SELF" ]; then SELF="$0"; fi
28+
BINDIR="$(cd "$(dirname "$SELF")" && pwd -P)"
29+
ROOTDIR="${ERL_ROOTDIR:-"$(dirname "$(dirname "$BINDIR")")"}"
30+
EMU=beam
31+
PROGNAME=$(echo "$0" | sed 's/.*\///')
32+
export EMU
33+
export ROOTDIR
34+
export BINDIR
35+
export PROGNAME
36+
exec "$BINDIR/erlexec" ${1+"$@"}
37+
""")
38+
39+
make_executable(Path.join(release_erts_bin_dir, "erl"))
40+
41+
release_erts_include_dir =
42+
Path.join([vendor_otp_dir, "erts-#{release.erts_version}", "include"])
43+
44+
cp_r!(Path.join(erts_source, "include"), release_erts_include_dir)
45+
46+
# 2. copy lib
47+
release_lib_dir = Path.join(vendor_otp_dir, "lib")
48+
cp_r!(otp_lib_dir, release_lib_dir)
49+
50+
for dir <- Path.wildcard("#{release_lib_dir}/*/doc/{xml,html,pdf}") do
51+
File.rm_rf!(dir)
52+
end
53+
54+
for dir <- Path.wildcard("#{release_lib_dir}/*/src") do
55+
File.rm_rf!(dir)
56+
end
57+
58+
# 3. copy boot files
59+
release_bin_dir = Path.join(vendor_otp_dir, "bin")
60+
File.mkdir!(release_bin_dir)
61+
62+
for file <- Path.wildcard(Path.join(otp_bin_dir, "*")) do
63+
File.cp!(file, Path.join(release_bin_dir, Path.basename(file)))
64+
end
65+
66+
# 4. copy usr
67+
cp_r!(Path.join(:code.root_dir(), "usr"), Path.join(vendor_otp_dir, "usr"))
68+
69+
release
70+
end
71+
72+
@doc """
73+
Copies Elixir into the release.
74+
"""
75+
@spec copy_elixir(Mix.Release.t(), elixir_version :: String.t()) :: Mix.Release.t()
76+
def copy_elixir(release, elixir_version) do
77+
standalone_destination = vendor_dir(release, "elixir")
78+
download_elixir_at_destination(standalone_destination, elixir_version)
79+
80+
filenames =
81+
case :os.type() do
82+
{:unix, _} ->
83+
["elixir", "elixirc", "mix", "iex"]
84+
85+
{:win32, _} ->
86+
["elixir.bat", "elixirc.bat", "mix.bat", "iex.bat"]
87+
end
88+
89+
Enum.map(filenames, &make_executable(Path.join(standalone_destination, "bin/#{&1}")))
90+
91+
release
92+
end
93+
94+
defp download_elixir_at_destination(destination, version) do
95+
url = "https://builds.hex.pm/builds/elixir/v#{version}-otp-#{System.otp_release()}.zip"
96+
path = Path.join(System.tmp_dir!(), "elixir_#{version}.zip")
97+
98+
unless File.exists?(path) do
99+
binary = fetch_body!(url)
100+
File.write!(path, binary, [:binary])
101+
end
102+
103+
:zip.unzip(String.to_charlist(path), cwd: String.to_charlist(destination))
104+
end
105+
106+
@doc """
107+
Copies Hex into the release.
108+
"""
109+
@spec copy_hex(Mix.Release.t()) :: Mix.Release.t()
110+
def copy_hex(release) do
111+
release_archives_dir = vendor_dir(release, "archives")
112+
File.mkdir_p!(release_archives_dir)
113+
114+
hex_version = Keyword.fetch!(Application.spec(:hex), :vsn)
115+
source_hex_path = Path.join(Mix.path_for(:archives), "hex-#{hex_version}-otp-#{System.otp_release()}")
116+
release_hex_path = Path.join(release_archives_dir, "hex-#{hex_version}-otp-#{System.otp_release()}")
117+
cp_r!(source_hex_path, release_hex_path)
118+
119+
release
120+
end
121+
122+
@doc """
123+
Copies Rebar3 into the release.
124+
"""
125+
@spec copy_rebar3(Mix.Release.t(), version :: String.t()) :: Mix.Release.t()
126+
def copy_rebar3(release, version) do
127+
url = "https://github.com/erlang/rebar3/releases/download/#{version}/rebar3"
128+
path = Path.join(System.tmp_dir!(), "rebar3_#{version}")
129+
130+
unless File.exists?(path) do
131+
binary = fetch_body!(url)
132+
File.write!(path, binary, [:binary])
133+
end
134+
135+
destination = vendor_dir(release, "rebar3")
136+
File.cp!(path, destination)
137+
make_executable(destination)
138+
139+
release
140+
end
141+
142+
defp fetch_body!(url) do
143+
Logger.debug("Downloading #{url}")
144+
145+
Application.ensure_all_started(:req)
146+
147+
req = Req.new() |> Livebook.Utils.req_attach_defaults()
148+
149+
case Req.get(req, url: url, receive_timeout: :infinity, decode_body: false) do
150+
{:ok, %{status: 200, body: body}} ->
151+
body
152+
153+
{:error, exception} ->
154+
raise "couldn't fetch #{url}: #{Exception.message(exception)}}"
155+
end
156+
end
157+
158+
defp make_executable(path), do: File.chmod!(path, 0o755)
159+
160+
defp cp_r!(source, destination) do
161+
File.cp_r!(source, destination, on_conflict: fn _, _ -> false end)
162+
end
163+
164+
defp vendor_dir(release, path) do
165+
Path.join([release.path, "vendor", "livebook-#{release.version}", path])
166+
end
167+
end

0 commit comments

Comments
 (0)