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

make plugin relx friendly #13

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions priv/bin
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/sh

set -e

SCRIPT=$(readlink $0 || true)
if [ -z $SCRIPT ]; then
SCRIPT=$0
fi;
SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"
RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)"
REL_NAME="{{ release_name }}"
REL_VSN="{{ release_version }}"
ERTS_VSN="{{ release_erts_version }}"
CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
ERL_OPTS="{{ erl_opts }}"
export ESCRIPT_NAME="${ESCRIPT_NAME-$SCRIPT}"

PRE_START_HOOK_DIR="$SCRIPT_DIR/pre-start-hooks"

erllambda_run_hooks() {
HOOKS_DIR=$1
for HOOK in "$HOOKS_DIR"/*
do
if [ -x "$HOOK" ]; then
. "$HOOK"
fi
done
}

find_erts_dir() {
__erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
if [ -d "$__erts_dir" ]; then
ERTS_DIR="$__erts_dir";
ROOTDIR="$RELEASE_ROOT_DIR"
else
__erl="$(which erl)"
code="io:format(\"~s\", [code:root_dir()]), halt()."
__erl_root="$("$__erl" -boot no_dot_erlang -noshell -eval "$code")"
ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
ROOTDIR="$__erl_root"
fi
}

find_sys_config() {
__possible_sys="$REL_DIR/sys.config"
if [ -f "$__possible_sys" ]; then
SYS_CONFIG="$__possible_sys"
else
if [ -L "$__possible_sys".orig ]; then
mv "$__possible_sys".orig "$__possible_sys"
SYS_CONFIG="$__possible_sys"
fi
fi
}

find_vm_args() {
__possible_vm_args="$REL_DIR/vm.args"
if [ -f "$__possible_vm_args" ]; then
VM_ARGS="$__possible_vm_args"
else
if [ -L "$__possible_vm_args".orig ]; then
mv "$__possible_vm_args".orig "$__possible_vm_args"
VM_ARGS="$__possible_vm_args"
fi
fi
}

find_erts_dir
find_sys_config
find_vm_args
export ROOTDIR="$RELEASE_ROOT_DIR"
export HOME="$ROOTDIR"
export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
ERTS_LIB_DIR="$ERTS_DIR/../lib"
[ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
cd "$ROOTDIR"

# Save extra arguments
ARGS="$@"

# Build arguments for erlexec
set -- "$ERL_OPTS"
[ "$SYS_CONFIG" ] && set -- "$@" -config "$SYS_CONFIG"
[ "$VM_ARGS" ] && set -- "$@" -args_file "$VM_ARGS"
set -- "$@" -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" -boot "$REL_DIR/$BOOTFILE" \
-mode "$CODE_LOADING_MODE" -noshell -noinput +Bd \
"$ARGS"

erllambda_run_hooks "$PRE_START_HOOK_DIR"

# Boot the release
exec $BINDIR/erlexec $@
26 changes: 26 additions & 0 deletions priv/bootstrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh

set -e

SCRIPT=$(readlink $0 || true)
if [ -z $SCRIPT ]; then
SCRIPT=$0
fi;
SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"

# temporary migration folders
# specific to some of Alert Logic application
# harmless to other
# to be removed later
echo "creating necessary erllambda run dirs"
export RUN_DIR="/tmp/erllambda_rundir"
export VAR_DIR=${RUN_DIR}
$(mkdir -p "${RUN_DIR}/cachefs")
$(mkdir -p "${RUN_DIR}/checkpointfs")
$(mkdir -p "${RUN_DIR}/tmpfs")
$(mkdir -p "${RUN_DIR}/ramfs")

# we no need coredumps in Lambda
export ERL_CRASH_DUMP="/dev/null"

exec $SCRIPT_DIR/bin/{{ release_name }}
13 changes: 13 additions & 0 deletions priv/make_zip
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

zippath=$1
shift

srcdir=$1
shift

rm -rf ${zippath}

(cd ${srcdir} &&
zip -q -r ${zippath} "$@" \
-x \*.a \*.c \*.h \*.o \*.erl \*.hrl \*.xrl \*.yrl \*.asn1)
80 changes: 24 additions & 56 deletions src/rebar3_erllambda.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
%%
%%
%% @copyright 2017 Alert Logic, Inc
%% Licensed under the MIT License. See LICENSE file in the project
%% root for full license information.
%%%---------------------------------------------------------------------------
-module(rebar3_erllambda).
-author('Paul Fisher <[email protected]>').

-export([init/1]).

-export([format_error/1,
release_name/1, target_dir/1, erllambda_dir/1, zip_path/1,
list/1, os_cmd/1]).
-export([init/1, format_error/1, add_property/4]).

%%============================================================================
%% Callback Functions
Expand All @@ -39,54 +36,25 @@ format_error( Error ) ->
io_lib:format( "~s: ~s", [?MODULE, Error] ).


release_name( State ) ->
case lists:keyfind( release, 1, rebar_state:get(State, relx, []) ) of
false -> throw( {relx_release_undefined, undefined} );
{release, {Name, _Vsn}, _} -> atom_to_list(Name)
end.


target_dir( State ) ->
ReleaseDir = filename:join( rebar_dir:base_dir(State), "rel" ),
ReleaseName = release_name( State ),
TargetDir = filename:join( [ReleaseDir, ReleaseName] ),
case filelib:is_dir( TargetDir ) of
true -> TargetDir;
false -> throw( {target_director_does_not_exist, TargetDir, undefined} )
end.


zip_path( State ) ->
ProfileDir = rebar_dir:base_dir(State),
Version = git_version(),
ReleaseName = [release_name( State ), $-, Version, ".zip"],
filename:join( [ProfileDir, ReleaseName] ).


git_version() ->
string:strip( os:cmd( "git describe" ), right, $\n ).


erllambda_dir( State ) ->
ChkDir = filename:join( ["_checkouts", "erllambda"] ),
ProfDir = filename:join( [rebar_dir:base_dir(State), "lib", "erllambda"] ),
case {filelib:is_dir( ChkDir ), filelib:is_dir( ProfDir )} of
{true, _} -> filename:absname(ChkDir);
{_, true} -> ProfDir;
_Otherwise -> throw( erllambda_dep_missing )
end.


list( V ) when is_atom(V) -> atom_to_list(V);
list( V ) -> V.


os_cmd( Command ) ->
Port = open_port( {spawn, Command}, [exit_status, in, stderr_to_stdout] ),
os_cmd_receive( Port ).
%%%---------------------------------------------------------------------------
-spec add_property(
State :: rebar_state:t(),
ConfigKey :: atom(),
Key :: atom(),
Value :: term()) -> rebar_state:t().
%%%---------------------------------------------------------------------------
%% @doc add at the beginning of existing list of properties or add a new one
%%
add_property(State, ConfigKey, Key, Value) ->
Config = rebar_state:get(State, ConfigKey, []),
Properties = proplists:get_value(Key, Config, []),
Config1 = property_store(Key, Value, Properties, Config),
rebar_state:set(State, ConfigKey, Config1).

os_cmd_receive( Port ) ->
receive
{Port, {data, _Output}} -> os_cmd_receive( Port );
{Port, {exit_status, Status}} -> Status
end.
%%============================================================================
%% Internal functions
%%============================================================================
property_store(Key, Value, Properties, Config) when is_list(Value) ->
lists:keystore(Key, 1, Config, {Key, Value ++ Properties});
property_store(Key, Value, Properties, Config) ->
lists:keystore(Key, 1, Config, {Key, [Value | Properties]}).
81 changes: 30 additions & 51 deletions src/rebar3_erllambda_release.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
%%
%%
%% @copyright 2017 Alert Logic, Inc
%% Licensed under the MIT License. See LICENSE file in the project
%% root for full license information.
%%%---------------------------------------------------------------------------
-module(rebar3_erllambda_release).
-author('Paul Fisher <[email protected]>').

-behaviour(provider).
-export([init/1, do/1, format_error/1]).
Expand Down Expand Up @@ -39,7 +40,7 @@ init( State ) ->
{deps, ?DEPS},
{example, "rebar3 erllambda release"},
{opts, relx:opt_spec_list()},
{short_desc, "Rebar3 erllambda release provider"},
{short_desc, "Build lambda release of project"},
{desc,
"Performs erllamba specific release generation on top of the "
"standard rebar3 release generation."}
Expand All @@ -55,18 +56,10 @@ init( State ) ->
%% @doc Initialize the release provider
%%
do( State ) ->
try
rebar_api:info("running erllambda release generator", []),
ErllambdaDir = rebar3_erllambda:erllambda_dir( State ),
StartScript = start_script( ErllambdaDir ),
{Command, _} = HandlerInfo = handler_info( State ),
TargetDir = rebar3_erllambda:target_dir( State ),
generate_start_script( TargetDir, Command, StartScript ),
{ok, State}
catch
throw:Error ->
{error, format_error(Error)}
end.
rebar_api:info("running erllambda release generator", []),
Overlay = overlay(State),
State1 = rebar3_erllambda:add_property(State, relx, overlay, Overlay),
rebar_relx:do(rlx_prv_release, "release", ?PROVIDER, State1).


%%%---------------------------------------------------------------------------
Expand All @@ -81,42 +74,28 @@ format_error( Error ) ->
%%============================================================================
%% Internal Functions
%%============================================================================
generate_start_script( Dir, Command, Script ) ->
rebar_api:info( "generating start script bin/~s", [Command] ),
Filename = filename:join( [Dir, rebar3_erllambda:list(Command)] ),
BootFilename = filename:join( [Dir, "bootstrap"]),
case file:write_file( Filename, Script ) of
ok ->
ok = make_executable(Filename ),
% it can already exist from previous run. remove it
% technically we can just keep it
% TODO rework for NO symlinks
file:delete(BootFilename),
%% create necessary symlink
ok = file:make_symlink( "/var/task/" ++ rebar3_erllambda:list(Command), BootFilename);
{error, Reason} ->
throw( {generate_start_script_failed, Reason} )
end.

make_executable(Filename ) ->
Mode = 8#00755,
case file:change_mode( Filename, Mode ) of
ok -> ok;
{error, Reason} -> throw( {generate_start_script_failed, Reason} )
end.


handler_info( State ) ->
DefaultName = rebar3_erllambda:release_name( State ),
Config = rebar_state:get(State, erllambda, []),
Module = proplists:get_value( module, Config, DefaultName ),
{["bin/", DefaultName], Module}.
overlay(State) ->
Config = rebar_state:get(State, rebar3_erllambda, []),
boot_overlay() ++ custom_hooks(Config).

custom_hooks(Config) ->
Hooks = proplists:get_value(hooks, Config, []),
PreStartHooks = proplists:get_value(pre_start, Hooks, []),
HookDir = "bin/pre-start-hooks",
HooksOverlay = hooks_overlay(PreStartHooks, HookDir),
case HooksOverlay of
[] ->
[];
_ ->
[{mkdir, HookDir} | HooksOverlay]
end.

hooks_overlay(Hooks, Directory) ->
[{template, Hook, filename:join(Directory, filename:basename(Hook))}
|| Hook <- Hooks].

start_script( ErllambdaDir ) ->
ScriptFile = filename:join( [ErllambdaDir, "priv", "erlang-start"] ),
case file:read_file( ScriptFile ) of
{ok, Script} -> Script;
{error, Reason} ->
throw( {erllambda_script_missing, Reason} )
end.
boot_overlay() ->
PrivDir = code:priv_dir(rebar3_erllambda),
%% relx can't symlink
[{template, filename:join(PrivDir, "bootstrap"), "bootstrap"},
{template, filename:join(PrivDir, "bin"), "bin/{{ release_name }}"}].
Loading