-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
release.init.ex
473 lines (406 loc) · 15.5 KB
/
release.init.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
defmodule Mix.Tasks.Release.Init do
use Mix.Task
@shortdoc "Generates sample files for releases"
@moduledoc """
Generates sample files for releases.
$ mix release.init
* creating rel/vm.args.eex
* creating rel/remote.vm.args.eex
* creating rel/env.sh.eex
* creating rel/env.bat.eex
"""
import Mix.Generator
@switches [
force: :boolean,
quiet: :boolean
]
@aliases [
force: :f
]
@impl true
def run(args) do
{opts, args} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
if args != [] do
Mix.raise("Expected \"mix release.init\" without arguments, got: #{inspect(args)}")
end
create_file("rel/vm.args.eex", vm_args_text(), opts)
create_file("rel/remote.vm.args.eex", vm_args_text(), opts)
create_file("rel/env.sh.eex", env_text(), opts)
create_file("rel/env.bat.eex", env_bat_text(), opts)
:ok
end
@doc false
def vm_args_text,
do: ~S"""
## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html
## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Increase number of concurrent ports/sockets
##+Q 65536
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10
"""
@doc false
def env_text,
do: ~S"""
#!/bin/sh
# # Sets and enables heart (recommended only in daemon mode)
# case $RELEASE_COMMAND in
# daemon*)
# HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND"
# export HEART_COMMAND
# export ELIXIR_ERL_OPTIONS="-heart"
# ;;
# *)
# ;;
# esac
# # Set the release to load code on demand (interactive) instead of preloading (embedded).
# export RELEASE_MODE=interactive
# # Set the release to work across nodes.
# # RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
# export RELEASE_DISTRIBUTION=name
# export RELEASE_NODE=<%= @release.name %>
"""
@doc false
def cli_text,
do: ~S"""
#!/bin/sh
set -e
SELF=$(readlink "$0" || true)
if [ -z "$SELF" ]; then SELF="$0"; fi
RELEASE_ROOT="$(CDPATH='' cd "$(dirname "$SELF")/.." && pwd -P)"
export RELEASE_ROOT
RELEASE_NAME="${RELEASE_NAME:-"<%= @release.name %>"}"
export RELEASE_NAME
RELEASE_VSN="${RELEASE_VSN:-"$(cut -d' ' -f2 "$RELEASE_ROOT/releases/start_erl.data")"}"
export RELEASE_VSN
RELEASE_COMMAND="$1"
export RELEASE_COMMAND
RELEASE_PROG="${RELEASE_PROG:-"$(echo "$0" | sed 's/.*\///')"}"
export RELEASE_PROG
REL_VSN_DIR="$RELEASE_ROOT/releases/$RELEASE_VSN"
. "$REL_VSN_DIR/env.sh"
RELEASE_COOKIE="${RELEASE_COOKIE:-"$(cat "$RELEASE_ROOT/releases/COOKIE")"}"
export RELEASE_COOKIE
RELEASE_MODE="${RELEASE_MODE:-"embedded"}"
export RELEASE_MODE
RELEASE_NODE="${RELEASE_NODE:-"$RELEASE_NAME"}"
export RELEASE_NODE
RELEASE_TMP="${RELEASE_TMP:-"$RELEASE_ROOT/tmp"}"
export RELEASE_TMP
RELEASE_VM_ARGS="${RELEASE_VM_ARGS:-"$REL_VSN_DIR/vm.args"}"
export RELEASE_VM_ARGS
RELEASE_REMOTE_VM_ARGS="${RELEASE_REMOTE_VM_ARGS:-"$REL_VSN_DIR/remote.vm.args"}"
export RELEASE_REMOTE_VM_ARGS
RELEASE_DISTRIBUTION="${RELEASE_DISTRIBUTION:-"sname"}"
export RELEASE_DISTRIBUTION
RELEASE_BOOT_SCRIPT="${RELEASE_BOOT_SCRIPT:-"start"}"
export RELEASE_BOOT_SCRIPT
RELEASE_BOOT_SCRIPT_CLEAN="${RELEASE_BOOT_SCRIPT_CLEAN:-"start_clean"}"
export RELEASE_BOOT_SCRIPT_CLEAN
rand () {
dd count=1 bs=2 if=/dev/urandom 2> /dev/null | od -x | awk 'NR==1{print $2}'
}
release_distribution () {
case $RELEASE_DISTRIBUTION in
none)
;;
name | sname)
echo "--$RELEASE_DISTRIBUTION $1"
;;
*)
echo "ERROR: Expected sname, name, or none in RELEASE_DISTRIBUTION, got: $RELEASE_DISTRIBUTION" >&2
exit 1
;;
esac
}
rpc () {
exec "$REL_VSN_DIR/elixir" \
--hidden --cookie "$RELEASE_COOKIE" \
$(release_distribution "rpc-$(rand)-$RELEASE_NODE") \
--boot "$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN" \
--boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \
--vm-args "$RELEASE_REMOTE_VM_ARGS" \
--rpc-eval "$RELEASE_NODE" "$1"
}
start () {
export_release_sys_config
REL_EXEC="$1"
shift
exec "$REL_VSN_DIR/$REL_EXEC" \
--cookie "$RELEASE_COOKIE" \
$(release_distribution "$RELEASE_NODE") \
--erl "<%= release_mode(@release, "$RELEASE_MODE") %>" \
--erl-config "$RELEASE_SYS_CONFIG" \
--boot "$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT" \
--boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \
--vm-args "$RELEASE_VM_ARGS" "$@"
}
export_release_sys_config () {
DEFAULT_SYS_CONFIG="${RELEASE_SYS_CONFIG:-"$REL_VSN_DIR/sys"}"
if grep -q "RUNTIME_CONFIG=true" "$DEFAULT_SYS_CONFIG.config"; then
RELEASE_SYS_CONFIG="$RELEASE_TMP/$RELEASE_NAME-$RELEASE_VSN-$(date +%Y%m%d%H%M%S)-$(rand).runtime"
(mkdir -p "$RELEASE_TMP" && cat "$DEFAULT_SYS_CONFIG.config" >"$RELEASE_SYS_CONFIG.config") || (
echo "ERROR: Cannot start release because it could not write $RELEASE_SYS_CONFIG.config" >&2
exit 1
)
else
RELEASE_SYS_CONFIG="$DEFAULT_SYS_CONFIG"
fi
export RELEASE_SYS_CONFIG
}
case $1 in
start)
start "elixir" --no-halt
;;
start_iex)
start "iex" --werl
;;
daemon)
start "elixir" --no-halt --pipe-to "${RELEASE_TMP}/pipe" "${RELEASE_TMP}/log"
;;
daemon_iex)
start "iex" --pipe-to "${RELEASE_TMP}/pipe" "${RELEASE_TMP}/log"
;;
eval)
if [ -z "$2" ]; then
echo "ERROR: EVAL expects an expression as argument" >&2
exit 1
fi
script="$2"
shift 2
export_release_sys_config
exec "$REL_VSN_DIR/elixir" \
--cookie "$RELEASE_COOKIE" \
--erl-config "$RELEASE_SYS_CONFIG" \
--boot "$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN" \
--boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \
--vm-args "$RELEASE_VM_ARGS" --eval "$script" -- "$@"
;;
remote)
exec "$REL_VSN_DIR/iex" \
--werl --hidden --cookie "$RELEASE_COOKIE" \
$(release_distribution "rem-$(rand)-$RELEASE_NODE") \
--boot "$REL_VSN_DIR/$RELEASE_BOOT_SCRIPT_CLEAN" \
--boot-var RELEASE_LIB "$RELEASE_ROOT/lib" \
--vm-args "$RELEASE_REMOTE_VM_ARGS" \
--remsh "$RELEASE_NODE"
;;
rpc)
if [ -z "$2" ]; then
echo "ERROR: RPC expects an expression as argument" >&2
exit 1
fi
rpc "$2"
;;
restart|stop)
rpc "System.$1()"
;;
pid)
rpc "IO.puts System.pid()"
;;
version)
echo "$RELEASE_NAME $RELEASE_VSN"
;;
*)
echo "Usage: $(basename "$0") COMMAND [ARGS]
The known commands are:
start Starts the system
start_iex Starts the system with IEx attached
daemon Starts the system as a daemon
daemon_iex Starts the system as a daemon with IEx attached
eval \"EXPR\" Executes the given expression on a new, non-booted system
rpc \"EXPR\" Executes the given expression remotely on the running system
remote Connects to the running system via a remote shell
restart Restarts the running system via a remote command
stop Stops the running system via a remote command
pid Prints the operating system PID of the running system via a remote command
version Prints the release name and version to be booted
" >&2
if [ -n "$1" ]; then
echo "ERROR: Unknown command $1" >&2
exit 1
fi
;;
esac
"""
@doc false
def env_bat_text,
do: ~S"""
@echo off
rem Set the release to load code on demand (interactive) instead of preloading (embedded).
rem set RELEASE_MODE=interactive
rem Set the release to work across nodes.
rem RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
rem set RELEASE_DISTRIBUTION=name
rem set RELEASE_NODE=<%= @release.name %>
"""
@doc false
def cli_bat_text,
do: ~S"""
@echo off
setlocal enabledelayedexpansion
pushd .
cd "%~dp0\.."
set RELEASE_ROOT=%cd%
popd
if not defined RELEASE_NAME (set RELEASE_NAME=<%= @release.name %>)
if not defined RELEASE_VSN (for /f "tokens=1,2" %%K in ('type "!RELEASE_ROOT!\releases\start_erl.data"') do (set ERTS_VSN=%%K) && (set RELEASE_VSN=%%L))
if not defined RELEASE_PROG (set RELEASE_PROG=%~nx0)
set RELEASE_COMMAND=%~1
set REL_VSN_DIR=!RELEASE_ROOT!\releases\!RELEASE_VSN!
call "!REL_VSN_DIR!\env.bat"
if not defined RELEASE_COOKIE (set /p RELEASE_COOKIE=<!RELEASE_ROOT!\releases\COOKIE)
if not defined RELEASE_MODE (set RELEASE_MODE=embedded)
if not defined RELEASE_NODE (set RELEASE_NODE=!RELEASE_NAME!)
if not defined RELEASE_TMP (set RELEASE_TMP=!RELEASE_ROOT!\tmp)
if not defined RELEASE_VM_ARGS (set RELEASE_VM_ARGS=!REL_VSN_DIR!\vm.args)
if not defined RELEASE_REMOTE_VM_ARGS (set RELEASE_REMOTE_VM_ARGS=!REL_VSN_DIR!\remote.vm.args)
if not defined RELEASE_DISTRIBUTION (set RELEASE_DISTRIBUTION=sname)
if not defined RELEASE_BOOT_SCRIPT (set RELEASE_BOOT_SCRIPT=start)
if not defined RELEASE_BOOT_SCRIPT_CLEAN (set RELEASE_BOOT_SCRIPT_CLEAN=start_clean)
if not defined RELEASE_SYS_CONFIG (set RELEASE_SYS_CONFIG=!REL_VSN_DIR!\sys)
if "%~1" == "start" (set "REL_EXEC=elixir" && set "REL_EXTRA=--no-halt" && set "REL_GOTO=start")
if "%~1" == "start_iex" (set "REL_EXEC=iex" && set "REL_EXTRA=--werl" && set "REL_GOTO=start")
if "%~1" == "install" (set "REL_GOTO=install")
if "%~1" == "eval" (
if "%~2" == "" (
echo ERROR: EVAL expects an expression as argument
goto end
)
set "REL_GOTO=eval"
)
if not "!REL_GOTO!" == "" (
findstr "RUNTIME_CONFIG=true" "!RELEASE_SYS_CONFIG!.config" >nul 2>&1 && (
set DEFAULT_SYS_CONFIG=!RELEASE_SYS_CONFIG!
for /f "skip=1" %%X in ('wmic os get localdatetime') do if not defined TIMESTAMP set TIMESTAMP=%%X
set RELEASE_SYS_CONFIG=!RELEASE_TMP!\!RELEASE_NAME!-!RELEASE_VSN!-!TIMESTAMP:~0,11!-!RANDOM!.runtime
mkdir "!RELEASE_TMP!" >nul 2>&1
copy /y "!DEFAULT_SYS_CONFIG!.config" "!RELEASE_SYS_CONFIG!.config" >nul || (
echo Cannot start release because it could not write to "!RELEASE_SYS_CONFIG!.config"
goto end
)
)
goto !REL_GOTO!
)
if "%~1" == "remote" (goto remote)
if "%~1" == "version" (goto version)
if "%~1" == "stop" (set "REL_RPC=System.stop()" && goto rpc)
if "%~1" == "restart" (set "REL_RPC=System.restart()" && goto rpc)
if "%~1" == "pid" (set "REL_RPC=IO.puts(System.pid())" && goto rpc)
if "%~1" == "rpc" (
if "%~2" == "" (
echo ERROR: RPC expects an expression as argument
goto end
)
set "REL_RPC=%~2"
goto rpc
)
echo Usage: %~nx0 COMMAND [ARGS]
echo.
echo The known commands are:
echo.
echo start Starts the system
echo start_iex Starts the system with IEx attached
echo install Installs this system as a Windows service
echo eval "EXPR" Executes the given expression on a new, non-booted system
echo rpc "EXPR" Executes the given expression remotely on the running system
echo remote Connects to the running system via a remote shell
echo restart Restarts the running system via a remote command
echo stop Stops the running system via a remote command
echo pid Prints the operating system PID of the running system via a remote command
echo version Prints the release name and version to be booted
echo.
if not "%~1" == "" (echo ERROR: Unknown command %~1)
goto end
:start
if "!RELEASE_DISTRIBUTION!" == "none" (
set RELEASE_DISTRIBUTION_FLAG=
) else (
set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! "!RELEASE_NODE!"
)
"!REL_VSN_DIR!\!REL_EXEC!.bat" !REL_EXTRA! ^
--cookie "!RELEASE_COOKIE!" ^
!RELEASE_DISTRIBUTION_FLAG! ^
--erl "<%= release_mode(@release, "!RELEASE_MODE!") %>" ^
--erl-config "!RELEASE_SYS_CONFIG!" ^
--boot "!REL_VSN_DIR!\!RELEASE_BOOT_SCRIPT!" ^
--boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^
--vm-args "!RELEASE_VM_ARGS!"
goto end
:eval
set EVAL=%~2
shift
:loop
shift
if not "%1"=="" (
set args=%args% %1
goto :loop
)
"!REL_VSN_DIR!\elixir.bat" ^
--eval "!EVAL!" ^
--cookie "!RELEASE_COOKIE!" ^
--erl-config "!RELEASE_SYS_CONFIG!" ^
--boot "!REL_VSN_DIR!\!RELEASE_BOOT_SCRIPT_CLEAN!" ^
--boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^
--vm-args "!RELEASE_VM_ARGS!" -- %args%
goto end
:remote
if "!RELEASE_DISTRIBUTION!" == "none" (
set RELEASE_DISTRIBUTION_FLAG=
) else (
set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! "rem-!RANDOM!-!RELEASE_NODE!"
)
"!REL_VSN_DIR!\iex.bat" ^
--werl --hidden --cookie "!RELEASE_COOKIE!" ^
!RELEASE_DISTRIBUTION_FLAG! ^
--boot "!REL_VSN_DIR!\!RELEASE_BOOT_SCRIPT_CLEAN!" ^
--boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^
--vm-args "!RELEASE_REMOTE_VM_ARGS!" ^
--remsh "!RELEASE_NODE!"
goto end
:rpc
if "!RELEASE_DISTRIBUTION!" == "none" (
set RELEASE_DISTRIBUTION_FLAG=
) else (
set RELEASE_DISTRIBUTION_FLAG=--!RELEASE_DISTRIBUTION! "rem-!RANDOM!-!RELEASE_NODE!"
)
"!REL_VSN_DIR!\elixir.bat" ^
--hidden --cookie "!RELEASE_COOKIE!" ^
!RELEASE_DISTRIBUTION_FLAG! ^
--boot "!REL_VSN_DIR!\!RELEASE_BOOT_SCRIPT_CLEAN!" ^
--boot-var RELEASE_LIB "!RELEASE_ROOT!\lib" ^
--vm-args "!RELEASE_REMOTE_VM_ARGS!" ^
--rpc-eval "!RELEASE_NODE!" "!REL_RPC!"
goto end
:version
echo !RELEASE_NAME! !RELEASE_VSN!
goto end
:install
if exist !RELEASE_ROOT!\erts-!ERTS_VSN! (
set ERLSRV=!RELEASE_ROOT!\erts-!ERTS_VSN!\bin\erlsrv.exe
) else (
set ERLSRV=erlsrv.exe
)
if "!RELEASE_DISTRIBUTION!" == "none" (
echo ERROR: RELEASE_DISTRIBUTION is required in install command
goto end
)
"!ERLSRV!" add "!RELEASE_NAME!_!RELEASE_NAME!" ^
-!RELEASE_DISTRIBUTION! "!RELEASE_NODE!" ^
-env RELEASE_ROOT="!RELEASE_ROOT!" -env RELEASE_NAME="!RELEASE_NAME!" -env RELEASE_VSN="!RELEASE_VSN!" -env RELEASE_MODE="!RELEASE_MODE!" -env RELEASE_COOKIE="!RELEASE_COOKIE!" -env RELEASE_NODE="!RELEASE_NODE!" -env RELEASE_VM_ARGS="!RELEASE_VM_ARGS!" -env RELEASE_TMP="!RELEASE_TMP!" -env RELEASE_SYS_CONFIG="!RELEASE_SYS_CONFIG!" ^
-args "-setcookie !RELEASE_COOKIE! -config ""!RELEASE_SYS_CONFIG!"" <%= release_mode(@release, "!RELEASE_MODE!") %> -boot ""!REL_VSN_DIR!\start"" -boot_var RELEASE_LIB ""!RELEASE_ROOT!\lib"" -args_file ""!REL_VSN_DIR!\vm.args\"""
if %ERRORLEVEL% EQU 0 (
echo Service installed but not started. From now on, it must be started and stopped by erlsrv:
echo.
echo !ERLSRV! start !RELEASE_NAME!_!RELEASE_NAME!
echo !ERLSRV! stop !RELEASE_NAME!_!RELEASE_NAME!
echo !ERLSRV! remove !RELEASE_NAME!_!RELEASE_NAME!
echo !ERLSRV! list
echo !ERLSRV! help
echo.
)
goto end
:end
endlocal
"""
end