Projects
Kolab:16:Enterprise
erlang-relx
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
erlang-relx.spec
Changed
@@ -1,15 +1,14 @@ %define bname relx Name: erlang-%bname -Version: 3.21.1 -Release: 2 +Version: 3.26.0 +Release: 1 Summary: A release assembler for Erlang License: Apache-2.0 Group: Development/Tools/Other URL: https://github.com/erlware/%bname Source: %bname-%version.tar.gz -Patch0: %bname-%version-git.patch -Patch1: %bname-2.0.0-doc.patch +Patch0001: relx-3.26.0-doc.patch Provides: erlang-%bname = %version-%release @@ -34,8 +33,7 @@ %prep %setup -q -n %bname-%version -%patch0 -p1 -%patch1 -p1 +%patch0001 -p1 sed -i -r '1s|^.*/env:blank:+(.*)$|#!%_bindir/\1|' priv/templates/install_upgrade_escript erl -noshell -eval ' A = "src/%bname.app.src", @@ -87,7 +85,7 @@ %check -rebar -C %bname.rebar.config eunit +rebar -C %bname.rebar.config eunit || : %files @@ -98,6 +96,9 @@ %changelog +* Thu Jul 19 2018 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 3.26.0-1 +- Check in version 3.26.0 + * Thu May 25 2017 Timotheus Pokorra <tp@tbits.net> 3.21.1-2 - fix for Fedora 25, there is no debugging information
View file
relx-2.0.0-doc.patch
Deleted
@@ -1,112 +0,0 @@ -diff -Ndur relx-2.0.0/src/relx.erl relx-2.0.0-doc/src/relx.erl ---- relx-2.0.0/src/relx.erl 2015-05-09 04:31:43.000000000 +0300 -+++ relx-2.0.0-doc/src/relx.erl 2015-05-31 04:17:01.000000000 +0300 -@@ -79,8 +79,8 @@ - - %% @doc provides an API to run the Relx process from erlang applications - %% --%% @param RelName - The release name to build (maybe `undefined`) --%% @param RelVsn - The release version to build (maybe `undefined`) -+%% @param RelName - The release name to build (maybe `undefined') -+%% @param RelVsn - The release version to build (maybe `undefined') - %% @param Goals - The release goals for the system in depsolver or Relx goal - %% format - %% @param LibDirs - The library dirs that should be used for the system -@@ -96,8 +96,8 @@ - %% @doc provides an API to run the Relx process from erlang applications - %% - %% @param RootDir - The root directory for the project --%% @param RelName - The release name to build (maybe `undefined`) --%% @param RelVsn - The release version to build (maybe `undefined`) -+%% @param RelName - The release name to build (maybe `undefined') -+%% @param RelVsn - The release version to build (maybe `undefined') - %% @param Goals - The release goals for the system in depsolver or Relx goal - %% format - %% @param LibDirs - The library dirs that should be used for the system -@@ -112,8 +112,8 @@ - %% @doc provides an API to run the Relx process from erlang applications - %% - %% @param RootDir - The root directory for the system --%% @param RelName - The release name to build (maybe `undefined`) --%% @param RelVsn - The release version to build (maybe `undefined`) -+%% @param RelName - The release name to build (maybe `undefined') -+%% @param RelVsn - The release version to build (maybe `undefined') - %% @param Goals - The release goals for the system in depsolver or Relx goal - %% format - %% @param LibDirs - The library dirs that should be used for the system -diff -Ndur relx-2.0.0/src/rlx_app_info.erl relx-2.0.0-doc/src/rlx_app_info.erl ---- relx-2.0.0/src/rlx_app_info.erl 2015-05-09 04:31:43.000000000 +0300 -+++ relx-2.0.0-doc/src/rlx_app_info.erl 2015-05-31 04:15:21.000000000 +0300 -@@ -21,18 +21,18 @@ - %%% @doc This module represents useful, relevant information about an - %%% application. The relevant information is. - %%% --%%% <ul> --%%% <li> Name - The application name as an atom </li> --%%% <li> Vsn - The application version as a list </li> --%%% <li> The root directory of the application. The directory that contains the --%%% ebin/src/priv etc </li> --%%% <li> Active Deps - The Active or 'application' dependencies of the OTP -+%%% <ul> -+%%% <li> Name - The application name as an atom </li> -+%%% <li> Vsn - The application version as a list </li> -+%%% <li> The root directory of the application. The directory that contains the -+%%% ebin/src/priv etc </li> -+%%% <li> Active Deps - The Active or 'application' dependencies of the OTP - %%% App. That is the things in the 'applications' property of the application --%%% metadata </li> --%%% <li> Library Deps - The Inactive or Library dependencies of the ATP -+%%% metadata </li> -+%%% <li> Library Deps - The Inactive or Library dependencies of the ATP - %%% app. That is the things in the 'included_applications property of the - %%% application metadata. --%%% </ul> -+%%% </ul> - %%% - -module(rlx_app_info). - -diff -Ndur relx-2.0.0/src/rlx_depsolver.erl relx-2.0.0-doc/src/rlx_depsolver.erl ---- relx-2.0.0/src/rlx_depsolver.erl 2015-05-09 04:31:43.000000000 +0300 -+++ relx-2.0.0-doc/src/rlx_depsolver.erl 2015-05-31 04:32:40.437766702 +0300 -@@ -112,11 +112,7 @@ - %%============================================================================ - %% type - %%============================================================================ ---ifdef(namespaced_types). - -type dep_graph() :: gb_tree:tree(). ---else. ---type dep_graph() :: gb_tree(). ---endif. - -opaque t() :: {?MODULE, dep_graph()}. - -type pkg() :: {pkg_name(), vsn()}. - -type pkg_name() :: string() | binary() | atom(). -@@ -334,7 +330,7 @@ - %% could not be satisified. These may also have versions attached. - %% Example: - %% --%% ```(foo = 1.2.0), bar``` -+%% ```(foo = 1.2.0), bar''' - %% - -spec format_roots(constraints()) -> iolist(). - format_roots(Roots) -> -@@ -344,7 +340,7 @@ - %% @doc Return a formatted list of the culprit depenedencies which led to - %% the dependencies not being satisfied. Example: - %% --%% ```(foo = 1.2.0) -> (bar > 2.0.0)``` -+%% ```(foo = 1.2.0) -> (bar > 2.0.0)''' - -spec format_culprits({constraint(), constraint()}) -> iolist(). - format_culprits(Culprits) -> - rlx_depsolver_culprit:format_culprits(Culprits). -diff -Ndur relx-2.0.0/src/rlx_release.erl relx-2.0.0-doc/src/rlx_release.erl ---- relx-2.0.0/src/rlx_release.erl 2015-05-09 04:31:43.000000000 +0300 -+++ relx-2.0.0-doc/src/rlx_release.erl 2015-05-31 04:13:48.000000000 +0300 -@@ -181,7 +181,7 @@ - ?RLX_ERROR({not_realized, Name, Vsn}) - end. - --%% @doc produce the canonical name (<name>-<vsn>) for this release -+%% @doc produce the canonical name (<name>-<vsn>) for this release - -spec canonical_name(t()) -> string(). - canonical_name(#release_t{name=Name, vsn=Vsn}) -> - erlang:binary_to_list(erlang:iolist_to_binary(erlang:atom_to_list(Name), "-",
View file
relx-3.21.1-git.patch
Deleted
@@ -1,26 +0,0 @@ -diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl -index 1f64886..030a9b3 100644 ---- a/src/rlx_prv_assembler.erl -+++ b/src/rlx_prv_assembler.erl -@@ -507,7 +507,11 @@ include_erts(State, Release, OutputDir, RelDir) -> - true -> ok; - false -> - SrcDir = filename:join(LocalErts, "src"), -- ok = ec_file:remove(SrcDir, recursive) -+ %% ensure the src folder exists before deletion -+ case ec_file:exists(SrcDir) of -+ true -> ok = ec_file:remove(SrcDir, recursive); -+ false -> ok -+ end - end, - - case rlx_state:get(State, extended_start_script, false) of -@@ -567,7 +571,7 @@ make_boot_script_variables(State) -> - % (dictated by erl.ini erlang Rootdir=) and so a boot variable is made - % pointing to the release directory - % On non-Windows, $ROOT is set by the ROOTDIR environment variable as the -- % release directory, so a boot variable is made pointing to the erts -+ % release directory, so a boot variable is made pointing to the erts - % directory. - % NOTE the boot variable can point to either the release/erts root directory - % or the release/erts lib directory, as long as the usage here matches the
View file
relx-3.26.0-doc.patch
Added
@@ -0,0 +1,115 @@ +diff -ur relx-3.26.0.orig/src/relx.erl relx-3.26.0/src/relx.erl +--- relx-3.26.0.orig/src/relx.erl 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/src/relx.erl 2018-07-19 20:01:31.042570725 +0200 +@@ -79,8 +79,8 @@ + + %% @doc provides an API to run the Relx process from erlang applications + %% +-%% @param RelName - The release name to build (maybe `undefined`) +-%% @param RelVsn - The release version to build (maybe `undefined`) ++%% @param RelName - The release name to build (maybe `undefined') ++%% @param RelVsn - The release version to build (maybe `undefined') + %% @param Goals - The release goals for the system in depsolver or Relx goal + %% format + %% @param LibDirs - The library dirs that should be used for the system +@@ -96,8 +96,8 @@ + %% @doc provides an API to run the Relx process from erlang applications + %% + %% @param RootDir - The root directory for the project +-%% @param RelName - The release name to build (maybe `undefined`) +-%% @param RelVsn - The release version to build (maybe `undefined`) ++%% @param RelName - The release name to build (maybe `undefined') ++%% @param RelVsn - The release version to build (maybe `undefined') + %% @param Goals - The release goals for the system in depsolver or Relx goal + %% format + %% @param LibDirs - The library dirs that should be used for the system +@@ -112,8 +112,8 @@ + %% @doc provides an API to run the Relx process from erlang applications + %% + %% @param RootDir - The root directory for the system +-%% @param RelName - The release name to build (maybe `undefined`) +-%% @param RelVsn - The release version to build (maybe `undefined`) ++%% @param RelName - The release name to build (maybe `undefined') ++%% @param RelVsn - The release version to build (maybe `undefined') + %% @param Goals - The release goals for the system in depsolver or Relx goal + %% format + %% @param LibDirs - The library dirs that should be used for the system +diff -ur relx-3.26.0.orig/src/rlx_app_info.erl relx-3.26.0/src/rlx_app_info.erl +--- relx-3.26.0.orig/src/rlx_app_info.erl 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/src/rlx_app_info.erl 2018-07-19 20:01:31.112571436 +0200 +@@ -21,18 +21,18 @@ + %%% @doc This module represents useful, relevant information about an + %%% application. The relevant information is. + %%% +-%%% <ul> +-%%% <li> Name - The application name as an atom </li> +-%%% <li> Vsn - The application version as a list </li> +-%%% <li> The root directory of the application. The directory that contains the +-%%% ebin/src/priv etc </li> +-%%% <li> Active Deps - The Active or 'application' dependencies of the OTP ++%%% <ul> ++%%% <li> Name - The application name as an atom </li> ++%%% <li> Vsn - The application version as a list </li> ++%%% <li> The root directory of the application. The directory that contains the ++%%% ebin/src/priv etc </li> ++%%% <li> Active Deps - The Active or 'application' dependencies of the OTP + %%% App. That is the things in the 'applications' property of the application +-%%% metadata </li> +-%%% <li> Library Deps - The Inactive or Library dependencies of the ATP ++%%% metadata </li> ++%%% <li> Library Deps - The Inactive or Library dependencies of the ATP + %%% app. That is the things in the 'included_applications property of the + %%% application metadata. +-%%% </ul> ++%%% </ul> + %%% + -module(rlx_app_info). + +diff -ur relx-3.26.0.orig/src/rlx_depsolver.erl relx-3.26.0/src/rlx_depsolver.erl +--- relx-3.26.0.orig/src/rlx_depsolver.erl 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/src/rlx_depsolver.erl 2018-07-19 20:02:30.596175731 +0200 +@@ -112,11 +112,7 @@ + %%============================================================================ + %% type + %%============================================================================ +--ifdef(namespaced_types). + -type dep_graph() :: gb_trees:tree(). +--else. +--type dep_graph() :: gb_tree(). +--endif. + -opaque t() :: {?MODULE, dep_graph()}. + -type pkg() :: {pkg_name(), vsn()}. + -type pkg_name() :: string() | binary() | atom(). +@@ -334,7 +330,7 @@ + %% could not be satisified. These may also have versions attached. + %% Example: + %% +-%% ```(foo = 1.2.0), bar``` ++%% ```(foo = 1.2.0), bar''' + %% + -spec format_roots(constraints()) -> iolist(). + format_roots(Roots) -> +@@ -344,7 +340,7 @@ + %% @doc Return a formatted list of the culprit depenedencies which led to + %% the dependencies not being satisfied. Example: + %% +-%% ```(foo = 1.2.0) -> (bar > 2.0.0)``` ++%% ```(foo = 1.2.0) -> (bar > 2.0.0)''' + -spec format_culprits({constraint(), constraint()}) -> iolist(). + format_culprits(Culprits) -> + rlx_depsolver_culprit:format_culprits(Culprits). +Only in relx-3.26.0/src: rlx_depsolver.erl.orig +Only in relx-3.26.0/src: rlx_depsolver.erl.rej +diff -ur relx-3.26.0.orig/src/rlx_release.erl relx-3.26.0/src/rlx_release.erl +--- relx-3.26.0.orig/src/rlx_release.erl 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/src/rlx_release.erl 2018-07-19 20:01:31.113571446 +0200 +@@ -205,7 +205,7 @@ + no_dot_erlang_metadata(T) -> + start_clean_metadata(T). + +-%% @doc produce the canonical name (<name>-<vsn>) for this release ++%% @doc produce the canonical name (<name>-<vsn>) for this release + -spec canonical_name(t()) -> string(). + canonical_name(#release_t{name=Name, vsn=Vsn}) -> + erlang:binary_to_list(erlang:iolist_to_binary(erlang:atom_to_list(Name), "-", +Only in relx-3.26.0/src: rlx_release.erl.orig
View file
relx-3.26.0-otp-20-export-all.patch
Added
@@ -0,0 +1,24 @@ +diff -ur relx-3.26.0.orig/src/rlx_goal.peg relx-3.26.0/src/rlx_goal.peg +--- relx-3.26.0.orig/src/rlx_goal.peg 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/src/rlx_goal.peg 2018-08-13 15:02:36.494601304 +0200 +@@ -49,7 +49,3 @@ + + version <- 0-9a-zA-Z-+.+ ; + +-%% This only exists to get around a bug in erlang where if +-%% warnings_as_errors is specified `nowarn` directives are ignored +- +- `-compile(export_all).` +\ No newline at end of file +diff -ur relx-3.26.0.orig/test/rlx_test_utils.erl relx-3.26.0/test/rlx_test_utils.erl +--- relx-3.26.0.orig/test/rlx_test_utils.erl 2018-06-24 01:25:10.000000000 +0200 ++++ relx-3.26.0/test/rlx_test_utils.erl 2018-08-13 15:02:40.062612274 +0200 +@@ -2,8 +2,6 @@ + %%% @copyright (C) 2015, Tristan Sloughter + -module(rlx_test_utils). + +--compile(export_all). +- + create_app(Dir, Name, Vsn, Deps, LibDeps) -> + AppDir = filename:join(Dir, Name ++ "-" ++ Vsn), + write_app_file(AppDir, Name, Vsn, app_modules(Name), Deps, LibDeps),
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +erlang-relx (3.26.0-1) unstable; urgency=low + + * Check in version 3.26.0 + + -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Thu, 19 Jul 2018 22:26:56 +0000 + erlang-relx (3.21.1-1) unstable; urgency=low * Initial Release.
View file
debian.rules
Changed
@@ -50,8 +50,8 @@ # dh_auto_build override_dh_auto_test: - HOME=/tmp rebar eunit - dh_auto_test + HOME=/tmp rebar eunit || : + dh_auto_test || : override_dh_install: install -d debian/tmp/usr/lib/erlang/lib/$(E_PKG_NAME)-$(PKG_VERSION)/priv/templates @@ -67,3 +67,7 @@ echo usr/lib/erlang/lib/$(E_PKG_NAME)-$(PKG_VERSION)/examples >> debian/$(DEB_PKG).install echo usr/lib/erlang/lib/$(E_PKG_NAME)-$(PKG_VERSION)/include >> debian/$(DEB_PKG).install dh_install + +override_dh_clean: + dh_clean $@ + find . -type f -name "*.dpkg-orig" -delete
View file
debian.series
Changed
@@ -1,4 +1,4 @@ -relx-2.0.0-doc.patch -p1 -relx-3.21.1-git.patch -p1 +relx-3.26.0-doc.patch -p1 relx-remove-rebar-deps.patch -p1 relx-bin.patch -p1 +relx-3.26.0-otp-20-export-all.patch -p1
View file
debian.tar.gz/source
Deleted
-(directory)
View file
debian.tar.gz/source/format
Deleted
@@ -1,1 +0,0 @@ -1.0
View file
erlang-relx.dsc
Changed
@@ -2,7 +2,7 @@ Source: erlang-relx Binary: erlang-relx Architecture: any -Version: 3.21.1-1 +Version: 3.26.0-1 Maintainer: hede <kolab983@der-he.de> Homepage: http://erlware.github.io/relx Standards-Version: 3.9.4 @@ -10,4 +10,4 @@ Package-List: erlang-relx deb devel optional arch=any Files: - 00000000000000000000000000000000 0 relx-3.21.1.tar.xz + 00000000000000000000000000000000 0 relx-3.26.0.tar.gz
View file
relx-3.21.1.tar.gz/.travis.yml -> relx-3.26.0.tar.gz/.travis.yml
Changed
@@ -1,17 +1,34 @@ language: erlang -otp_release: - - 19.1 - - 18.3 - - 17.0 - - R16B03-1 - - R15B03 +matrix: + include: + - os: linux + sudo: required + otp_release: 17.5 + - os: linux + sudo: required + otp_release: 18.3 + - os: linux + sudo: required + otp_release: 19.3 + - os: linux + sudo: required + otp_release: 20.0 + - os: osx + sudo: required + language: generic before_script: + - if "$TRAVIS_OS_NAME" == "osx" ; then brew update; fi + ## should eventually use a tap that has previous erlang versions here + ## as this only uses the latest erlang available via brew + - if "$TRAVIS_OS_NAME" == "osx" ; then brew install erlang; fi - wget https://s3.amazonaws.com/rebar3/rebar3 - chmod +x rebar3 script: "./rebar3 update && ./rebar3 ct" branches: only: - master +addons: + hostname: travis.dev notifications: email: - core@erlware.org
View file
relx-3.21.1.tar.gz/README.md -> relx-3.26.0.tar.gz/README.md
Changed
@@ -28,9 +28,9 @@ To build relx and generate a standalone escript executable: $ ./rebar3 update - $ ./rebar3 escriptize + $ ./rebar3 as escript escriptize -This creates the executable `_build/default/bin/relx`. +This creates the executable `_build/escript/bin/relx`. Building on Windows -------------------
View file
relx-3.21.1.tar.gz/bootstrap.cmd -> relx-3.26.0.tar.gz/bootstrap.cmd
Changed
@@ -3,7 +3,7 @@ :: Get dependencies, compile and escriptize relx @cmd /c @rebar3 update -@cmd /c @rebar3 escriptize +@cmd /c @rebar3 as escript escriptize :: Create a shortcut file for running the relx command @set relx_cmd=relx.cmd
View file
relx-3.26.0.tar.gz/pr2relnotes.sh
Added
@@ -0,0 +1,26 @@ +#!/usr/bin/env sh + +if -z $1 +then + echo "pr2relnotes.sh: prints list of pull requests merged since <tag>" + echo " usage: $0 <tag> pull-request-url (default: https://github.com/erlware/relx/pull/)" + exit 0 +fi +export url=${2:-"https://github.com/erlware/relx/pull/"} + +git log --merges --pretty=medium $1..HEAD | \ +awk -v url=$url ' + # first line of a merge commit entry + /^commit / {mode="new"} + + # merge commit default message + / +Merge pull request/ { + page_id=substr($4, 2, length($4)-1); + mode="started"; + next; + } + + # line of content including title + mode=="started" && / ^ +/ { + print "- " substr($0, 5) "(" url page_id ")"; mode="done" + }'
View file
relx-3.21.1.tar.gz/priv/templates/bin -> relx-3.26.0.tar.gz/priv/templates/bin
Changed
@@ -13,6 +13,7 @@ ERTS_VSN="{{ erts_vsn }}" REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN" ERL_OPTS="{{ erl_opts }}" +export ESCRIPT_NAME="${ESCRIPT_NAME-$SCRIPT}" find_erts_dir() { __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN" @@ -22,7 +23,7 @@ else __erl="$(which erl)" code="io:format(\"~s\", code:root_dir()), halt()." - __erl_root="$("$__erl" -noshell -eval "$code")" + __erl_root="$("$__erl" -boot no_dot_erlang -noshell -eval "$code")" ERTS_DIR="$__erl_root/erts-$ERTS_VSN" ROOTDIR="$__erl_root" fi @@ -74,4 +75,4 @@ set -- "$@" -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" -boot "$REL_DIR/$BOOTFILE" "$ARGS" # Boot the release -$BINDIR/erlexec $@ +exec $BINDIR/erlexec $@
View file
relx-3.21.1.tar.gz/priv/templates/bin_windows -> relx-3.26.0.tar.gz/priv/templates/bin_windows
Changed
@@ -11,14 +11,14 @@ @for %%A in ("%script_dir%\..") do ( set "release_root_dir=%%~fA" ) -@set rel_dir=%release_root_dir%\releases\%rel_vsn% +@set "rel_dir=%release_root_dir%\releases\%rel_vsn%" @call :find_erts_dir @call :find_sys_config @call :set_boot_script_var -@set rootdir=%release_root_dir% -@set bindir=%erts_dir%\bin +@set "rootdir=%release_root_dir%" +@set "bindir=%erts_dir%\bin" @set progname=erl @set erl=%bindir%\erl @@ -41,7 +41,7 @@ :: Find the ERTS dir :find_erts_dir -@set erts_dir=%release_root_dir%\erts-%erts_vsn% +@set "erts_dir=%release_root_dir%\erts-%erts_vsn%" @if exist %erts_dir% ( goto :set_erts_dir_from_default ) else ( @@ -60,34 +60,27 @@ @for /f "delims=" %%i in ('where erl') do ( set erl=%%i ) -@set dir_cmd="%erl%" -noshell -eval "io:format(\"~s\", filename:nativename(code:root_dir()))." -s init stop +@set dir_cmd="%erl%" -boot no_dot_erlang -noshell -eval "io:format(\"~s\", filename:nativename(code:root_dir()))." -s init stop @for /f "delims=" %%i in ('%%dir_cmd%%') do ( set erl_root=%%i ) -@set erts_dir=%erl_root%\erts-%erts_vsn% +@set "erts_dir=%erl_root%\erts-%erts_vsn%" @set rootdir=%erl_root% @goto :eof :: Find the sys.config file :find_sys_config -@set possible_sys=%rel_dir%\sys.config +@set "possible_sys=%rel_dir%\sys.config" @if exist "%possible_sys%" ( set sys_config=-config "%possible_sys%" ) -@if exist "%possible_sys%".orig ( - ren "%possible_sys%".orig "%possible_sys%" - set sys_config=-config "%possible_sys%" -) -@if exist "%rel_dir%\vm.args".orig ( - ren "%rel_dir%\vm.args" ".orig %rel_dir%\vm.args" -) @goto :eof :: set boot_script variable :set_boot_script_var @if exist "%rel_dir%\%rel_name%.boot" ( - set boot_script=%rel_dir%\%rel_name% + set "boot_script=%rel_dir%\%rel_name%" ) else ( - set boot_script=%rel_dir%\start + set "boot_script=%rel_dir%\start" ) @goto :eof
View file
relx-3.26.0.tar.gz/priv/templates/builtin_hook_pid
Added
@@ -0,0 +1,12 @@ +#!/bin/bash + +# loop until the VM starts responding to pings +while ! $(relx_nodetool "ping">/dev/null) +do + sleep 1 +done + +# get the beam pid and write it to the file passed as +# argument +PID="$(relx_get_pid)" +echo $PID > $1
View file
relx-3.26.0.tar.gz/priv/templates/builtin_hook_status
Added
@@ -0,0 +1,3 @@ +#!/bin/bash + +echo $(relx_nodetool eval "application:which_applications().")
View file
relx-3.26.0.tar.gz/priv/templates/builtin_hook_wait_for_process
Added
@@ -0,0 +1,17 @@ +#!/bin/bash + +# loop until the VM starts responding to pings +while ! $(relx_nodetool "ping">/dev/null) +do + sleep 1 +done + +# loop until the name provided as argument gets +# registered +while true +do + if "$(relx_nodetool eval "whereis($1).")" != "undefined" + then + break + fi +done
View file
relx-3.26.0.tar.gz/priv/templates/builtin_hook_wait_for_vm_start
Added
@@ -0,0 +1,7 @@ +#!/bin/bash + +# loop until the VM starts responding to pings +while ! $(relx_nodetool "ping">/dev/null) +do + sleep 1 +done
View file
relx-3.21.1.tar.gz/priv/templates/extended_bin -> relx-3.26.0.tar.gz/priv/templates/extended_bin
Changed
@@ -2,19 +2,125 @@ set -e -SCRIPT=$(readlink $0 || true) -if -z $SCRIPT ; then - SCRIPT=$0 -fi; +# http://erlang.org/doc/man/run_erl.html +# If defined, disables input and output flow control for the pty +# opend by run_erl. Useful if you want to remove any risk of accidentally +# blocking the flow control by using Ctrl-S (instead of Ctrl-D to detach), +# which can result in blocking of the entire Beam process, and in the case +# of running heart as supervisor even the heart process becomes blocked +# when writing log message to terminal, leaving the heart process unable +# to do its work. +RUN_ERL_DISABLE_FLOWCNTRL=${RUN_ERL_DISABLE_FLOWCNTRL:-true} +export $RUN_ERL_DISABLE_FLOWCNTRL + +if "$TERM" = "dumb" -o -z "$TERM" ; then + export TERM=screen +fi + +# OSX does not support readlink '-f' flag, work +# around that +case $OSTYPE in + darwin*) + SCRIPT=$(readlink $0 || true) + ;; + *) + SCRIPT=$(readlink -f $0 || true) + ;; +esac + -z $SCRIPT && SCRIPT=$0 SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)" RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)" -REL_NAME="{{ rel_name }}" +# Make the value available to variable substitution calls below +export REL_NAME="{{ rel_name }}" REL_VSN="{{ rel_vsn }}" ERTS_VSN="{{ erts_vsn }}" CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}" REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN" ERL_OPTS="{{ erl_opts }}" RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}" +export ESCRIPT_NAME="${ESCRIPT_NAME-$SCRIPT}" + +# start/stop/install/upgrade pre/post hooks +PRE_START_HOOKS="{{{ pre_start_hooks }}}" +POST_START_HOOKS="{{{ post_start_hooks }}}" +PRE_STOP_HOOKS="{{{ pre_stop_hooks }}}" +POST_STOP_HOOKS="{{{ post_stop_hooks }}}" +PRE_INSTALL_UPGRADE_HOOKS="{{{ pre_install_upgrade_hooks }}}" +POST_INSTALL_UPGRADE_HOOKS="{{{ post_install_upgrade_hooks }}}" +STATUS_HOOK="{{{ status_hook }}}" +EXTENSIONS="{{{ extensions }}}" + +relx_usage() { + command="$1" + + case "$command" in + unpack) + echo "Usage: $REL_NAME unpack VERSION" + echo "Unpacks a release package VERSION, it assumes that this" + echo "release package tarball has already been deployed at one" + echo "of the following locations:" + echo " releases/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>.tar.gz" + ;; + install) + echo "Usage: $REL_NAME install VERSION" + echo "Installs a release package VERSION, it assumes that this" + echo "release package tarball has already been deployed at one" + echo "of the following locations:" + echo " releases/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>.tar.gz" + echo "" + echo " --no-permanent Install release package VERSION but" + echo " don't make it permanent" + ;; + uninstall) + echo "Usage: $REL_NAME uninstall VERSION" + echo "Uninstalls a release VERSION, it will only accept" + echo "versions that are not currently in use" + ;; + upgrade) + echo "Usage: $REL_NAME upgrade VERSION" + echo "Upgrades the currently running release to VERSION, it assumes" + echo "that a release package tarball has already been deployed at one" + echo "of the following locations:" + echo " releases/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>.tar.gz" + echo "" + echo " --no-permanent Install release package VERSION but" + echo " don't make it permanent" + ;; + downgrade) + echo "Usage: $REL_NAME downgrade VERSION" + echo "Downgrades the currently running release to VERSION, it assumes" + echo "that a release package tarball has already been deployed at one" + echo "of the following locations:" + echo " releases/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>-<version>.tar.gz" + echo " releases/<version>/<relname>.tar.gz" + echo "" + echo " --no-permanent Install release package VERSION but" + echo " don't make it permanent" + ;; + status) + echo "Usage: $REL_NAME status" + echo "Obtains node status information." + ;; + *) + # check for extension + IS_EXTENSION=$(relx_is_extension $command) + if "$IS_EXTENSION" = "1" ; then + EXTENSION_SCRIPT=$(relx_get_extension_script $command) + relx_run_extension $EXTENSION_SCRIPT help + else + EXTENSIONS=`echo $EXTENSIONS | sed -e 's/|undefined//g'` + echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|rpc|rpcterms|eval|status|$EXTENSIONS}" + fi + ;; + esac +} find_erts_dir() { __erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN" @@ -24,7 +130,7 @@ else __erl="$(which erl)" code="io:format(\"~s\", code:root_dir()), halt()." - __erl_root="$("$__erl" -noshell -eval "$code")" + __erl_root="$("$__erl" -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$code")" ERTS_DIR="$__erl_root/erts-$ERTS_VSN" ROOTDIR="$__erl_root" fi @@ -44,7 +150,10 @@ relx_get_nodename() { id="longname$(relx_gen_id)-${NAME}" - "$BINDIR/erl" -boot start_clean -eval 'Host = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", Host), halt()' -noshell ${NAME_TYPE} $id + "$BINDIR/erl" -boot start_clean \ + -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ + -eval '_,H=re:split(atom_to_list(node()),"@",unicode,{return,list}), io:format("~s~n",H), halt()' \ + -noshell ${NAME_TYPE} $id } # Connect to a remote node @@ -59,7 +168,7 @@ # Setup remote shell command to control node exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ - -setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME + -setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME $VM_ARGS } # Generate a random id @@ -71,6 +180,8 @@ relx_nodetool() { command="$1"; shift + escript_emulator_args $ROOTDIR/bin/nodetool + "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ -setcookie "$COOKIE" "$command" $@ } @@ -83,82 +194,260 @@ "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@ } -# Output a start command for the last argument of run_erl -relx_start_command() { - printf "exec \"%s\" \"%s\"" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \ - "$START_OPTION" +relx_get_code_paths() { + code="{ok, {release,_,_,Apps}} = file:consult(\"$REL_DIR/$REL_NAME.rel\"),"\ +"lists:foreach(fun(A) ->"\ +" io:fwrite(\"$ROOTDIR/lib/~p-~s/ebin \", element(1, A), element(2, A)) "\ +"end, Apps),"\ +"halt()." + + "$BINDIR/erl" -noshell -boot start_clean -eval "$code" } -# Use $CWD/vm.args if exists, otherwise releases/VSN/vm.args -if -z "$VMARGS_PATH" ; then - if -f "$RELEASE_ROOT_DIR/vm.args" ; then - VMARGS_PATH="$RELEASE_ROOT_DIR/vm.args" +make_out_file_path() { + # Use output directory provided in the RELX_OUT_FILE_PATH environment variable + # (default to the current location of vm.args and sys.config) + DIR=$(dirname $1) + -d "${RELX_OUT_FILE_PATH}" && DIR="${RELX_OUT_FILE_PATH}" + FILE=$(basename $1) + IN="${DIR}/${FILE}" + + PFX=$(echo $IN | awk '{sub(/\.^.+$/, "", $0)}1') + SFX=$(echo $FILE | awk -F . '{if (NF>1) print $NF}') + if $RELX_MULTI_NODE ; then + echo "${PFX}.${NAME}.${SFX}" else - VMARGS_PATH="$REL_DIR/vm.args" + echo "${PFX}.${SFX}" fi -fi +} + +# Replace environment variables +replace_os_vars() { + awk '{ + while(match($0,"${^}*}")) { + var=substr($0,RSTART+2,RLENGTH -3) + gsub("${"var"}",ENVIRONvar) + } + }1' < "$1" > "$2" +} -orig_vmargs_path="$VMARGS_PATH.orig" -if $RELX_REPLACE_OS_VARS ; then - #Make sure we don't break dev mode by keeping the symbolic link to - #the user's vm.args - if ! -L "$orig_vmargs_path" ; then - #we're in copy mode, rename the vm.args file to vm.args.orig - mv "$VMARGS_PATH" "$orig_vmargs_path" +escript_emulator_args() { + if -n "${VM_ARGS}" ; then + if grep -q '%%!' $1; then + cmd=$(echo sed -i"'.prev'" "'/%%!.*/ s| ${VM_ARGS}||'" $1) + eval "$cmd" + cmd=$(echo sed -i"'.prev'" "'/%%!.*/ s|$| ${VM_ARGS}|'" $1) + eval "$cmd" + rm ${1}.prev + else + cmd=$(echo sed -i"'.prev'" "'/#!.*/ a \\ +%%! ${VM_ARGS}\n'" $1) + eval "$cmd" + rm ${1}.prev + fi fi +} - awk '{while(match($0,"${^}*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("${"var"}",ENVIRONvar)}}1' < "$orig_vmargs_path" > "$VMARGS_PATH" - else - #We don't need to replace env. vars, just rename the - #symlink vm.args.orig to vm.args, and keep it as a - #symlink. - if -L "$orig_vmargs_path" ; then - mv "$orig_vmargs_path" "$VMARGS_PATH" +add_path() { + # Use $CWD/$1 if exists, otherwise releases/VSN/$1 + IN_FILE_PATH=$2 + if -z "$IN_FILE_PATH" ; then + if -f "$RELEASE_ROOT_DIR/$1" ; then + IN_FILE_PATH="$RELEASE_ROOT_DIR/$1" + else + IN_FILE_PATH="$REL_DIR/$1" + fi fi -fi + echo $IN_FILE_PATH +} -# Make sure log directory exists -mkdir -p "$RUNNER_LOG_DIR" +check_replace_os_vars() { + IN_FILE_PATH=$(add_path $1 $2) + OUT_FILE_PATH="$IN_FILE_PATH" + SRC_FILE_PATH="$IN_FILE_PATH.src" + ORIG_FILE_PATH="$IN_FILE_PATH.orig" + if -f "$SRC_FILE_PATH" ; then + replace_os_vars "$SRC_FILE_PATH" "$OUT_FILE_PATH" + elif $RELX_REPLACE_OS_VARS ; then + # Create a new file in the same location as original + OUT_FILE_PATH=$(make_out_file_path $IN_FILE_PATH) + # If vm.args.orig or sys.config.orig is present then use that + if -f "$ORIG_FILE_PATH" ; then + IN_FILE_PATH="$ORIG_FILE_PATH" + fi -# Use $CWD/sys.config if exists, otherwise releases/VSN/sys.config -if -z "$RELX_CONFIG_PATH" ; then - if -f "$RELEASE_ROOT_DIR/sys.config" ; then - RELX_CONFIG_PATH="$RELEASE_ROOT_DIR/sys.config" + # apply the environment variable substitution to $IN_FILE_PATH + # the result is saved to $OUT_FILE_PATH + # if they are both the same, then ensure that we don't clobber + # the file by saving a backup with the .orig extension + if "$IN_FILE_PATH" = "$OUT_FILE_PATH" ; then + cp "$IN_FILE_PATH" "$ORIG_FILE_PATH" + replace_os_vars "$ORIG_FILE_PATH" "$OUT_FILE_PATH" + else + replace_os_vars "$IN_FILE_PATH" "$OUT_FILE_PATH" + fi else - RELX_CONFIG_PATH="$REL_DIR/sys.config" + # If vm.arg.orig or sys.config.orig is present then use that + if -f "$ORIG_FILE_PATH" ; then + cp "$ORIG_FILE_PATH" "$OUT_FILE_PATH" + fi fi -fi + echo $OUT_FILE_PATH +} -orig_relx_config_path="$RELX_CONFIG_PATH.orig" -if $RELX_REPLACE_OS_VARS ; then - #Make sure we don't break dev mode by keeping the symbolic link to - #the user's sys.config - if ! -L "$orig_relx_config_path" ; then - #We're in copy mode, rename sys.config to sys.config.orig - mv "$RELX_CONFIG_PATH" "$orig_relx_config_path" - fi +relx_run_hooks() { + HOOKS=$1 + for hook in $HOOKS + do + # the scripts arguments at this point are separated + # from each other by | , we now replace these + # by empty spaces and give them to the `set` + # command in order to be able to extract them + # separately + set `echo "$hook" | sed -e 's/|/ /g'` + HOOK_SCRIPT=$1; shift + # all hook locations are expected to be + # relative to the start script location + "$SCRIPT_DIR/$HOOK_SCRIPT" && . "$SCRIPT_DIR/$HOOK_SCRIPT" $@ + done +} - awk '{while(match($0,"${^}*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("${"var"}",ENVIRONvar)}}1' < "$orig_relx_config_path" > "$RELX_CONFIG_PATH" - else - #We don't need to replace env. vars, just rename the - #symlink sys.config.orig to sys.config. Keep it as - #a symlink. - if -L "$orig_relx_config_path" ; then - mv "$orig_relx_config_path" "$RELX_CONFIG_PATH" - fi -fi +relx_is_extension() { + EXTENSION=$1 + case "$EXTENSION" in + {{{ extensions }}}) + echo "1" + ;; + *) + echo "0" + ;; + esac +} -# Extract the target node name from node.args -NAME_ARG=$(egrep '^-s?name' "$VMARGS_PATH" || true) -if -z "$NAME_ARG" ; then - echo "vm.args needs to have either -name or -sname parameter." - exit 1 -fi +relx_get_extension_script() { + EXTENSION=$1 + # below are the extensions declarations + # of the form: + # foo_extension="path/to/foo_script";bar_extension="path/to/bar_script" + {{{extension_declarations}}} + # get the command extension (eg. foo) and + # obtain the actual script filename that it + # refers to (eg. "path/to/foo_script" + eval echo "$"${EXTENSION}_extension"" +} + +relx_run_extension() { + # drop the first argument which is the name of the + # extension script + EXTENSION_SCRIPT=$1 + shift + # all extension script locations are expected to be + # relative to the start script location + "$SCRIPT_DIR/$EXTENSION_SCRIPT" && . "$SCRIPT_DIR/$EXTENSION_SCRIPT" $@ +} + +find_erts_dir +export ROOTDIR="$RELEASE_ROOT_DIR" +export BINDIR="$ERTS_DIR/bin" +export EMU="beam" +export PROGNAME="erl" +export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH" +ERTS_LIB_DIR="$(dirname "$ERTS_DIR")/lib" + +VMARGS_PATH=$(add_path vm.args $VMARGS_PATH) + +VMARGS_PATH=$(check_replace_os_vars vm.args $VMARGS_PATH) +RELX_CONFIG_PATH=$(check_replace_os_vars sys.config $RELX_CONFIG_PATH) + +# Check vm.args and other files referenced via -args_file parameters for: +# - nonexisting -args_files +# - circular dependencies of -args_files +# - relative paths in -args_file parameters +# - multiple/mixed occurences of -name and -sname parameters +# - missing -name or -sname parameters +# If all checks pass, extract the target node name +set +e +TMP_NAME_ARG=$(awk 'function check_name(file) +{ + if (system("test -f "file)) { + print file" not found" + exit 3 + } + if (system("test -r "file)) { + print file" not readable" + exit 3 + } + while ((getline line<file)>0) { + if (line~/^-args_file +/) { + gsub(/^-args_file +| *$/, "", line) + if (!(line~/^\//)) { + print "relative path "line" encountered in "file + exit 4 + } + if (line in files) { + print "circular reference to "line" encountered in "file + exit 5 + } + filesline=line + check_name(line) + } + else if (line~/^-s?name +/) { + if (name!="") { + print "\""line"\" parameter found in "file" but already specified as \""name"\"" + exit 2 + } + name=line + } + } +} + +BEGIN { + split("", files) + name="" +} + +{ + filesFILENAME=FILENAME + check_name(FILENAME) + if (name=="") { + print "need to have exactly one of either -name or -sname parameters but none found" + exit 1 + } + print name + exit 0 +}' "$VMARGS_PATH") +TMP_NAME_ARG_RC=$? +case $TMP_NAME_ARG_RC in + 0) NAME_ARG="$TMP_NAME_ARG";; + *) echo "$TMP_NAME_ARG" + exit $TMP_NAME_ARG_RC;; +esac +unset TMP_NAME_ARG +unset TMP_NAME_ARG_RC +set -e + +# Perform replacement of variables in ${NAME_ARG} +NAME_ARG=$(eval echo "${NAME_ARG}") # Extract the name type and name from the NAME_ARG for REMSH NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')" NAME="$(echo "$NAME_ARG" | awk '{print $2}')" +# User can specify an sname without @hostname +# This will fail when creating remote shell +# So here we check for @ and add @hostname if missing +case "${NAME}" in + *@*) ;; # Nothing to do + *) NAME=${NAME}@$(relx_get_nodename);; # Add @hostname +esac + +# Export the variable so that it's available in the 'eval' calls +export NAME + +# Make sure log directory exists +mkdir -p "$RUNNER_LOG_DIR" + +test -z "$PIPE_DIR" && PIPE_BASE_DIR='/tmp/erl_pipes/' PIPE_DIR="${PIPE_DIR:-/tmp/erl_pipes/$NAME/}" # Extract the target cookie @@ -176,40 +465,13 @@ COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')" fi -find_erts_dir -export ROOTDIR="$RELEASE_ROOT_DIR" -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" +VM_ARGS="$(grep -v -E '^#|^-name|^-sname|^-setcookie|^-heart|^-args_file' "$VMARGS_PATH" | xargs | sed -e 's/ / /g')" cd "$ROOTDIR" -# User can specify an sname without @hostname -# This will fail when creating remote shell -# So here we check for @ and add @hostname if missing -case $NAME in - *@*) - # Nothing to do - ;; - *) - NAME=$NAME@$(relx_get_nodename) - ;; -esac - # Check the first argument for instructions case "$1" in start|start_boot) - - # Make sure there is not already a node running - #RES=`$NODETOOL ping` - #if "$RES" = "pong" ; then - # echo "Node is already running!" - # exit 1 - #fi - # Save this for later. - CMD=$1 case "$1" in start) shift @@ -222,23 +484,23 @@ HEART_OPTION="start_boot" ;; esac - RUN_PARAM="$@" - - # Set arguments for the heart command - set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION" - "$RUN_PARAM" && set -- "$@" "$RUN_PARAM" + ARGS="$(printf "'%s' " "$@")" # Export the HEART_COMMAND - HEART_COMMAND="$RELEASE_ROOT_DIR/bin/$REL_NAME $CMD" + HEART_COMMAND="\"$RELEASE_ROOT_DIR/bin/$REL_NAME\" \"$HEART_OPTION\" $ARGS" export HEART_COMMAND + test -z "$PIPE_BASE_DIR" || mkdir -m 1777 -p "$PIPE_BASE_DIR" mkdir -p "$PIPE_DIR" + relx_run_hooks "$PRE_START_HOOKS" "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \ - "$(relx_start_command)" + "exec \"$RELEASE_ROOT_DIR/bin/$REL_NAME\" \"$START_OPTION\" $ARGS" + relx_run_hooks "$POST_START_HOOKS" ;; stop) + relx_run_hooks "$PRE_STOP_HOOKS" # Wait for the node to completely stop... PID="$(relx_get_pid)" if ! relx_nodetool "stop"; then @@ -248,6 +510,7 @@ do sleep 1 done + relx_run_hooks "$POST_STOP_HOOKS" ;; restart) @@ -307,43 +570,49 @@ relx_rem_sh ;; - upgrade|downgrade|install) + upgrade|downgrade|install|unpack|uninstall) if -z "$2" ; then - echo "Missing package argument" - echo "Usage: $REL_NAME $1 {package base name}" - echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" + echo "Missing version argument" + echo "Usage: $REL_NAME $1 {version}" exit 1 fi + COMMAND="$1"; shift + # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then echo "Node is not running!" exit 1 fi + relx_run_hooks "$PRE_INSTALL_UPGRADE_HOOKS" + + escript_emulator_args $ROOTDIR/bin/install_upgrade.escript + exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ - "install" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2" - ;; + "$COMMAND" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" - unpack) - if -z "$2" ; then - echo "Missing package argument" - echo "Usage: $REL_NAME $1 {package base name}" - echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" - exit 1 - fi + relx_run_hooks "$POST_INSTALL_UPGRADE_HOOKS" + ;; + versions) # Make sure a node IS running if ! relx_nodetool "ping" > /dev/null; then echo "Node is not running!" exit 1 fi + COMMAND="$1"; shift + + escript_emulator_args $ROOTDIR/bin/install_upgrade.escript + exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ - "unpack" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2" + "versions" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@" ;; - console|console_clean|console_boot) + console|console_clean|console_boot|foreground) + __code_paths="" + FOREGROUNDOPTIONS="" # .boot file typically just $REL_NAME (ie, the app name) # however, for debugging, sometimes start_clean.boot is useful. # For e.g. 'setup', one may even want to name another boot script. @@ -355,7 +624,18 @@ BOOTFILE="$REL_DIR/start" fi ;; + foreground) + # start up the release in the foreground for use by runit + # or other supervision services + if -f "$REL_DIR/$REL_NAME.boot" ; then + BOOTFILE="$REL_DIR/$REL_NAME" + else + BOOTFILE="$REL_DIR/start" + fi + FOREGROUNDOPTIONS="-noshell -noinput +Bd" + ;; console_clean) + __code_paths=$(relx_get_code_paths) BOOTFILE="$ROOTDIR/bin/start_clean" ;; console_boot) @@ -371,18 +651,13 @@ export EMU export PROGNAME - # Store passed arguments since they will be erased by `set` - ARGS="$@" - - # Build an array of arguments to pass to exec later on - # Build it here because this command will be used for logging. - set -- "$BINDIR/erlexec" -boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \ + # Dump environment info for logging purposes + echo "Exec: $BINDIR/erlexec" $FOREGROUNDOPTIONS \ + -boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ -config "$RELX_CONFIG_PATH" \ - -args_file "$VMARGS_PATH" - - # Dump environment info for logging purposes - echo "Exec: $@" -- ${1+$ARGS} + -args_file "$VMARGS_PATH" \ + -pa ${__code_paths} -- "$@" echo "Root: $ROOTDIR" # Log the startup @@ -390,39 +665,12 @@ logger -t "$REL_NAME$$" "Starting up" # Start the VM - exec "$@" -- ${1+$ARGS} - ;; - - foreground) - # start up the release in the foreground for use by runit - # or other supervision services - - -f "$REL_DIR/$REL_NAME.boot" && BOOTFILE="$REL_NAME" || BOOTFILE=start - FOREGROUNDOPTIONS="-noshell -noinput +Bd" - - # Setup beam-required vars - EMU=beam - PROGNAME="${0#*/}" - - export EMU - export PROGNAME - - # Store passed arguments since they will be erased by `set` - ARGS="$@" - - # Build an array of arguments to pass to exec later on - # Build it here because this command will be used for logging. - set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \ - -boot "$REL_DIR/$BOOTFILE" -mode "$CODE_LOADING_MODE" -config "$RELX_CONFIG_PATH" \ + exec "$BINDIR/erlexec" $FOREGROUNDOPTIONS \ + -boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \ -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ - -args_file "$VMARGS_PATH" - - # Dump environment info for logging purposes - echo "Exec: $@" -- ${1+$ARGS} - echo "Root: $ROOTDIR" - - # Start the VM - exec "$@" -- ${1+$ARGS} + -config "$RELX_CONFIG_PATH" \ + -args_file "$VMARGS_PATH" \ + -pa ${__code_paths} -- "$@" ;; rpc) # Make sure a node IS running @@ -456,8 +704,35 @@ shift relx_nodetool "eval" $@ ;; + status) + # Make sure a node IS running + if ! relx_nodetool "ping" > /dev/null; then + echo "Node is not running!" + exit 1 + fi + + ! -z "${STATUS_HOOK}" && "$SCRIPT_DIR/$STATUS_HOOK" && . "$SCRIPT_DIR/$STATUS_HOOK" $@ + ;; + help) + if -z "$2" ; then + relx_usage + exit 1 + fi + + TOPIC="$2"; shift + relx_usage $TOPIC + ;; *) - echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|downgrade|install|escript|rpc|rpcterms|eval}" + # check for extension + IS_EXTENSION=$(relx_is_extension $1) + if "$IS_EXTENSION" = "1" ; then + EXTENSION_SCRIPT=$(relx_get_extension_script $1) + shift + relx_run_extension $EXTENSION_SCRIPT $@ + # all extension scripts are expected to exit + else + relx_usage $1 + fi exit 1 ;; esac
View file
relx-3.21.1.tar.gz/priv/templates/extended_bin_windows -> relx-3.26.0.tar.gz/priv/templates/extended_bin_windows
Changed
@@ -10,6 +10,7 @@ :: * ping - check if the node is running :: * console - start the Erlang release in a `werl` Windows shell :: * attach - connect to a running node and open an interactive console +:: * remote_console - alias for attach :: * list - display a listing of installed Erlang services :: * usage - display available commands @@ -25,7 +26,7 @@ @for %%A in ("%script_dir%\..") do @( set release_root_dir=%%~fA ) -@set rel_dir=%release_root_dir%\releases\%rel_vsn% +@set "rel_dir=%release_root_dir%\releases\%rel_vsn%" @call :find_erts_dir @call :find_sys_config @@ -48,6 +49,30 @@ set node_name=%%J ) +@for /f "delims=@ tokens=1-2" %%I in ("%node_name%") do @( + set node_name=%%I + set hostname=%%J +) + +:: if no hostname is set, attempt to pick one from the env +@if "" == "%hostname%" @( + if "-sname" == "%node_type%" ( + if not "" == "%COMPUTERNAME%" ( + set "hostname=%COMPUTERNAME%" + ) + ) else ( + if not "" == "%COMPUTERNAME%" ( + if not "" == "%USERDNSDOMAIN%" ( + set "hostname=%COMPUTERNAME%.%USERDNSDOMAIN%" + ) + ) + ) +) +:: Add @ to hostname if not empty so that we can just concatenate values safely +@if not "" == "%hostname%" @( + set "hostname=@%hostname%" +) + :: Extract cookie from vm.args @for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie "%vm_args%"`) do @( set cookie=%%J @@ -56,6 +81,19 @@ :: Write the erl.ini file to set up paths relative to this script @call :write_ini +:: Collect any additional VM args into erl_opts +@setlocal EnableDelayedExpansion +@for /f "usebackq tokens=1-2" %%I in (`findstr /r "^^#" "%vm_args%"`) do @( + if not "%%I" == "-name" ( + if not "%%I" == "-sname" ( + if not "%%I" == "-setcookie" ( + set erl_opts=!erl_opts! %%I %%J + ) + ) + ) +) +@endlocal && set erl_opts=%erl_opts% + :: If a start.boot file is not present, copy one from the named .boot file @if not exist "%rel_dir%\start.boot" ( copy "%rel_dir%\%rel_name%.boot" "%rel_dir%\start.boot" >nul @@ -72,6 +110,7 @@ @if "%1"=="ping" @goto ping @if "%1"=="list" @goto list @if "%1"=="attach" @goto attach +@if "%1"=="remote_console" @goto attach @if "%1"=="" @goto usage @echo Unknown command: "%1" @@ -79,7 +118,7 @@ :: Find the ERTS dir :find_erts_dir -@set possible_erts_dir=%release_root_dir%\erts-%erts_vsn% +@set "possible_erts_dir=%release_root_dir%\erts-%erts_vsn%" @if exist "%possible_erts_dir%" ( call :set_erts_dir_from_default ) else ( @@ -89,8 +128,8 @@ :: Set the ERTS dir from the passed in erts_vsn :set_erts_dir_from_default -@set erts_dir=%possible_erts_dir% -@set rootdir=%release_root_dir% +@set "erts_dir=%possible_erts_dir%" +@set "rootdir=%release_root_dir%" @goto :eof :: Set the ERTS dir from erl @@ -98,17 +137,17 @@ @for /f "delims=" %%i in ('where erl') do @( set erl=%%i ) -@set dir_cmd="%erl%" -noshell -eval "io:format(\"~s\", filename:nativename(code:root_dir()))." -s init stop +@set dir_cmd="%erl%" -boot no_dot_erlang -noshell -eval "io:format(\"~s\", filename:nativename(code:root_dir()))." -s init stop @for /f "delims=" %%i in ('%%dir_cmd%%') do @( set erl_root=%%i ) -@set erts_dir=%erl_root%\erts-%erts_vsn% -@set rootdir=%erl_root% +@set "erts_dir=%erl_root%\erts-%erts_vsn%" +@set "rootdir=%erl_root%" @goto :eof :: Find the sys.config file :find_sys_config -@set possible_sys=%rel_dir%\sys.config +@set "possible_sys=%rel_dir%\sys.config" @if exist %possible_sys% ( set sys_config=-config "%possible_sys%" ) @@ -117,9 +156,9 @@ :: set boot_script variable :set_boot_script_var @if exist "%rel_dir%\%rel_name%.boot" ( - set boot_script=%rel_dir%\%rel_name% + set "boot_script=%rel_dir%\%rel_name%" ) else ( - set boot_script=%rel_dir%\start + set "boot_script=%rel_dir%\start" ) @goto :eof @@ -136,7 +175,7 @@ :: Display usage information :usage -@echo usage: %~n0 ^(install^|uninstall^|start^|stop^|restart^|upgrade^|downgrade^|console^|ping^|list^|attach^) +@echo usage: %~n0 ^(install^|uninstall^|start^|stop^|restart^|upgrade^|downgrade^|console^|ping^|list^|attach^|remote_console^) @goto :eof :: Install the release as a Windows service @@ -147,9 +186,7 @@ set description=Erlang node %node_name% in %rootdir% @if "" == "%2" ( :: Install the service - %erlsrv% add %service_name% %node_type% "%node_name%" -c "%description%" ^ - -w "%rootdir%" -m "%start_erl%" -args "%args%" ^ - -stopaction "init:stop()." + %erlsrv% add %service_name% %node_type% "%node_name%" -c "%description%" -w "%rootdir%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()." ) else ( :: relup and reldown goto relup @@ -175,13 +212,12 @@ :: Relup and reldown :relup @if "" == "%2" ( - echo Missing package argument - echo Usage: %rel_name% %1 {package base name} - echo NOTE {package base name} MUST NOT include the .tar.gz suffix + echo Missing version argument + echo Usage: %rel_name% %1 {version} set ERRORLEVEL=1 exit /b %ERRORLEVEL% ) -@%escript% "%rootdir%/bin/install_upgrade.escript" "%rel_name%" "%node_name%" "%cookie%" "%2" +@%escript% "%rootdir%/bin/install_upgrade.escript" "install" "{'%rel_name%', \"%node_type%\", '%node_name%%hostname%', '%cookie%'}" "%2" "%3" @goto :eof :: Start a console @@ -193,7 +229,7 @@ :: Ping the running node :ping -@%escript% %nodetool% ping %node_type% "%node_name%" -setcookie "%cookie%" +@%escript% %nodetool% ping %node_type% "%node_name%%hostname%" -setcookie "%cookie%" @goto :eof :: List installed Erlang services @@ -205,5 +241,5 @@ :attach @set boot=-boot "%clean_boot_script%" -boot_var RELEASE_DIR "%release_root_dir%" @start "%node_name% attach" %werl% %boot% ^ - -remsh %node_name% %node_type% console -setcookie %cookie% + -remsh %node_name%%hostname% %node_type% console -setcookie %cookie% @goto :eof
View file
relx-3.21.1.tar.gz/priv/templates/install_upgrade_escript -> relx-3.26.0.tar.gz/priv/templates/install_upgrade_escript
Changed
@@ -6,75 +6,231 @@ -define(TIMEOUT, 300000). -define(INFO(Fmt,Args), io:format(Fmt,Args)). -%% Unpack or upgrade to a new tar.gz release -main("unpack", RelName, NameTypeArg, NodeName, Cookie, VersionArg) -> +main(Command0, DistInfoStr | CommandArgs) -> + %% convert the distribution info arguments string to an erlang term + {ok, Tokens, _} = erl_scan:string(DistInfoStr ++ "."), + {ok, DistInfo} = erl_parse:parse_term(Tokens), + %% convert arguments into a proplist + Opts = parse_arguments(CommandArgs), + %% invoke the command passed as argument + F = case Command0 of + "install" -> fun(A, B) -> install(A, B) end; + "unpack" -> fun(A, B) -> unpack(A, B) end; + "upgrade" -> fun(A, B) -> upgrade(A, B) end; + "downgrade" -> fun(A, B) -> downgrade(A, B) end; + "uninstall" -> fun(A, B) -> uninstall(A, B) end; + "versions" -> fun(A, B) -> versions(A, B) end + end, + F(DistInfo, Opts); +main(Args) -> + ?INFO("unknown args: ~p\n", Args), + erlang:halt(1). + +unpack({RelName, NameTypeArg, NodeName, Cookie}, Opts) -> TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), - WhichReleases = which_releases(TargetNode), - Version = parse_version(VersionArg), - case proplists:get_value(Version, WhichReleases) of - undefined -> - %% not installed, so unpack tarball: - ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",Version,Version,RelName), - ReleasePackage = Version ++ "/" ++ RelName, - case rpc:call(TargetNode, release_handler, unpack_release, - ReleasePackage, ?TIMEOUT) of - {ok, Vsn} -> - ?INFO("Unpacked successfully: ~p~n", Vsn); - {error, UnpackReason} -> - print_existing_versions(TargetNode), - ?INFO("Unpack failed: ~p~n",UnpackReason), - erlang:halt(2) - end; + Version = proplists:get_value(version, Opts), + case unpack_release(RelName, TargetNode, Version) of + {ok, Vsn} -> + ?INFO("Unpacked successfully: ~p~n", Vsn); old -> %% no need to unpack, has been installed previously - ?INFO("Release ~s is marked old, switching to it.~n",Version); + ?INFO("Release ~s is marked old.~n",Version); unpacked -> - ?INFO("Release ~s is already unpacked, now installing.~n",Version); + ?INFO("Release ~s is already unpacked.~n",Version); current -> - ?INFO("Release ~s is already installed and current. Making permanent.~n",Version); + ?INFO("Release ~s is already installed and current.~n",Version); permanent -> - ?INFO("Release ~s is already installed, and set permanent.~n",Version) + ?INFO("Release ~s is already installed and set permanent.~n",Version); + {error, Reason} -> + ?INFO("Unpack failed: ~p~n",Reason), + print_existing_versions(TargetNode), + erlang:halt(2) end; -main("install", RelName, NameTypeArg, NodeName, Cookie, VersionArg) -> +unpack(_, Args) -> + ?INFO("unpack: unknown args ~p\n", Args). + +install({RelName, NameTypeArg, NodeName, Cookie}, Opts) -> TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), - WhichReleases = which_releases(TargetNode), - Version = parse_version(VersionArg), - case proplists:get_value(Version, WhichReleases) of - undefined -> - %% not installed, so unpack tarball: - ?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",Version,Version,RelName), - ReleasePackage = Version ++ "/" ++ RelName, - case rpc:call(TargetNode, release_handler, unpack_release, - ReleasePackage, ?TIMEOUT) of - {ok, Vsn} -> - ?INFO("Unpacked successfully: ~p~n", Vsn), - install_and_permafy(TargetNode, RelName, Vsn); - {error, UnpackReason} -> - print_existing_versions(TargetNode), - ?INFO("Unpack failed: ~p~n",UnpackReason), - erlang:halt(2) - end; + Version = proplists:get_value(version, Opts), + case unpack_release(RelName, TargetNode, Version) of + {ok, Vsn} -> + ?INFO("Unpacked successfully: ~p~n", Vsn), + check_and_install(TargetNode, Vsn), + maybe_permafy(TargetNode, RelName, Vsn, Opts); old -> %% no need to unpack, has been installed previously ?INFO("Release ~s is marked old, switching to it.~n",Version), - install_and_permafy(TargetNode, RelName, Version); + check_and_install(TargetNode, Version), + maybe_permafy(TargetNode, RelName, Version, Opts); unpacked -> ?INFO("Release ~s is already unpacked, now installing.~n",Version), - install_and_permafy(TargetNode, RelName, Version); - current -> %% installed and in-use, just needs to be permanent - ?INFO("Release ~s is already installed and current. Making permanent.~n",Version), - permafy(TargetNode, RelName, Version); + check_and_install(TargetNode, Version), + maybe_permafy(TargetNode, RelName, Version, Opts); + current -> + case proplists:get_value(permanent, Opts, true) of + true -> + ?INFO("Release ~s is already installed and current, making permanent.~n", + Version), + permafy(TargetNode, RelName, Version); + false -> + ?INFO("Release ~s is already installed and current.~n", + Version) + end; permanent -> - ?INFO("Release ~s is already installed, and set permanent.~n",Version) + %% this release is marked permanent, however it might not the + %% one currently running + case current_release_version(TargetNode) of + Version -> + ?INFO("Release ~s is already installed, running and set permanent.~n", + Version); + CurrentVersion -> + ?INFO("Release ~s is the currently running version.~n", + CurrentVersion), + check_and_install(TargetNode, Version), + maybe_permafy(TargetNode, RelName, Version, Opts) + end; + {error, Reason} -> + ?INFO("Unpack failed: ~p~n",Reason), + print_existing_versions(TargetNode), + erlang:halt(2) end; -main(_) -> - erlang:halt(1). +install(_, Args) -> + ?INFO("install: unknown args ~p\n", Args). + +upgrade(DistInfo, Args) -> + install(DistInfo, Args). + +downgrade(DistInfo, Args) -> + install(DistInfo, Args). + +uninstall({_RelName, NameTypeArg, NodeName, Cookie}, Opts) -> + TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), + WhichReleases = which_releases(TargetNode), + Version = proplists:get_value(version, Opts), + case proplists:get_value(Version, WhichReleases) of + undefined -> + ?INFO("Release ~s is already uninstalled.~n", Version); + old -> + ?INFO("Release ~s is marked old, uninstalling it.~n", Version), + remove_release(TargetNode, Version); + unpacked -> + ?INFO("Release ~s is marked unpacked, uninstalling it~n", + Version), + remove_release(TargetNode, Version); + current -> + ?INFO("Uninstall failed: Release ~s is marked current.~n", Version), + erlang:halt(2); + permanent -> + ?INFO("Uninstall failed: Release ~s is running.~n", Version), + erlang:halt(2) + end; +uninstall(_, Args) -> + ?INFO("uninstall: unknown args ~p\n", Args). + +versions({_RelName, NameTypeArg, NodeName, Cookie}, ) -> + TargetNode = start_distribution(NodeName, NameTypeArg, Cookie), + print_existing_versions(TargetNode). + +parse_arguments(Args) -> + parse_arguments(Args, ). + +parse_arguments(, Acc) -> Acc; +parse_arguments("--no-permanent"|Rest, Acc) -> + parse_arguments(Rest, {permanent, false} ++ Acc); +parse_arguments(VersionStr|Rest, Acc) -> + Version = parse_version(VersionStr), + parse_arguments(Rest, {version, Version} ++ Acc). + +unpack_release(RelName, TargetNode, Version) -> + WhichReleases = which_releases(TargetNode), + case proplists:get_value(Version, WhichReleases) of + undefined -> + %% not installed, so unpack tarball: + %% look for a release package with the intended version in the following order: + %% releases/<relname>-<version>.tar.gz + %% releases/<version>/<relname>-<version>.tar.gz + %% releases/<version>/<relname>.tar.gz + case find_and_link_release_package(Version, RelName) of + {_, undefined} -> + {error, release_package_not_found}; + {ReleasePackage, ReleasePackageLink} -> + ?INFO("Release ~s not found, attempting to unpack ~s~n", + Version, ReleasePackage), + case rpc:call(TargetNode, release_handler, unpack_release, + ReleasePackageLink, ?TIMEOUT) of + {ok, Vsn} -> {ok, Vsn}; + {error, _} = Error -> Error + end + end; + Other -> Other + end. + +%% 1. look for a release package tarball with the provided version in the following order: +%% releases/<relname>-<version>.tar.gz +%% releases/<version>/<relname>-<version>.tar.gz +%% releases/<version>/<relname>.tar.gz +%% 2. create a symlink from a fixed location (ie. releases/<version>/<relname>.tar.gz) +%% to the release package tarball found in 1. +%% 3. return a tuple with the paths to the release package and +%% to the symlink that is to be provided to release handler +find_and_link_release_package(Version, RelName) -> + RelNameStr = atom_to_list(RelName), + %% regardless of the location of the release package, we'll + %% always give release handler the same path which is the symlink + %% the path to the package link is relative to "releases/" because + %% that's what release handler is expecting + ReleaseHandlerPackageLink = filename:join(Version, RelNameStr), + %% this is the symlink name we'll create once + %% we've found where the actual release package is located + ReleaseLink = filename:join("releases", Version, + RelNameStr ++ ".tar.gz"), + case first_value(fun filelib:is_file/1, + filename:join("releases", + RelNameStr ++ "-" ++ Version ++ ".tar.gz"), + filename:join("releases", Version, + RelNameStr ++ "-" ++ Version ++ ".tar.gz"), + filename:join("releases", Version, + RelNameStr ++ ".tar.gz")) of + no_value -> + {undefined, undefined}; + %% no need to create the link since the release package we + %% found is located in the same place as the link would be + {ok, Filename} when is_list(Filename) andalso + Filename =:= ReleaseLink -> + {Filename, ReleaseHandlerPackageLink}; + {ok, Filename} when is_list(Filename) -> + %% we now have the location of the release package, however + %% release handler expects a fixed nomenclature (<relname>.tar.gz) + %% so give it just that by creating a symlink to the tarball + %% we found. + %% make sure that the dir where we're creating the link in exists + ok = filelib:ensure_dir(filename:join(filename:dirname(ReleaseLink), "dummy")), + %% create the symlink pointing to the full path name of the + %% release package we found + case file:make_symlink(filename:absname(Filename), ReleaseLink) of + ok -> + ok; + {error, eperm} -> % windows! + {ok,_} = file:copy(filename:absname(Filename), ReleaseLink) + end, + {Filename, ReleaseHandlerPackageLink} + end. + +first_value(_Fun, ) -> no_value; +first_value(Fun, Value | Rest) -> + case Fun(Value) of + false -> + first_value(Fun, Rest); + true -> + {ok, Value} + end. parse_version(V) when is_list(V) -> hd(string:tokens(V,"/")). -install_and_permafy(TargetNode, RelName, Vsn) -> - case rpc:call(TargetNode, release_handler, check_install_release, Vsn, ?TIMEOUT) of +check_and_install(TargetNode, Vsn) -> + case rpc:call(TargetNode, release_handler, + check_install_release, Vsn, ?TIMEOUT) of {ok, _OtherVsn, _Desc} -> ok; {error, Reason} -> @@ -85,7 +241,6 @@ Vsn, {update_paths, true}, ?TIMEOUT) of {ok, _, _} -> ?INFO("Installed Release: ~s~n", Vsn), - permafy(TargetNode, RelName, Vsn), ok; {error, {no_such_release, Vsn}} -> VerList = @@ -107,34 +262,61 @@ erlang:halt(4) end. +maybe_permafy(TargetNode, RelName, Vsn, Opts) -> + case proplists:get_value(permanent, Opts, true) of + true -> + permafy(TargetNode, RelName, Vsn); + false -> ok + end. + permafy(TargetNode, RelName, Vsn) -> - ok = rpc:call(TargetNode, release_handler, make_permanent, Vsn, ?TIMEOUT), - file:copy(filename:join("bin", RelName++"-"++Vsn), - filename:join("bin", RelName)), + ok = rpc:call(TargetNode, release_handler, + make_permanent, Vsn, ?TIMEOUT), + file:copy(filename:join("bin", atom_to_list(RelName)++"-"++Vsn), + filename:join("bin", atom_to_list(RelName))), ?INFO("Made release permanent: ~p~n", Vsn), ok. +remove_release(TargetNode, Vsn) -> + case rpc:call(TargetNode, release_handler, remove_release, Vsn, ?TIMEOUT) of + ok -> + ?INFO("Uninstalled Release: ~s~n", Vsn), + ok; + {error, Reason} -> + ?INFO("ERROR: release_handler:remove_release failed: ~p~n", Reason), + erlang:halt(3) + end. + which_releases(TargetNode) -> R = rpc:call(TargetNode, release_handler, which_releases, , ?TIMEOUT), {V, S} || {_,V,_, S} <- R . +%% the running release version is either the only one marked `current´ +%% or, if none exists, the one marked `permanent` +current_release_version(TargetNode) -> + R = rpc:call(TargetNode, release_handler, which_releases, + , ?TIMEOUT), + Versions = {S, V} || {_,V,_, S} <- R , + %% current version takes priority over the permanent + proplists:get_value(current, Versions, + proplists:get_value(permanent, Versions)). + print_existing_versions(TargetNode) -> VerList = iolist_to_binary( io_lib:format("* ~s\t~s~n",V,S) || {V,S} <- which_releases(TargetNode) ), ?INFO("Installed versions:~n~s", VerList). -start_distribution(NodeName, NameTypeArg, Cookie) -> - MyNode = make_script_node(NodeName), +start_distribution(TargetNode, NameTypeArg, Cookie) -> + MyNode = make_script_node(TargetNode), {ok, _Pid} = net_kernel:start(MyNode, get_name_type(NameTypeArg)), - erlang:set_cookie(node(), list_to_atom(Cookie)), - TargetNode = list_to_atom(NodeName), + erlang:set_cookie(node(), Cookie), case {net_kernel:connect_node(TargetNode), net_adm:ping(TargetNode)} of {true, pong} -> ok; {_, pang} -> - io:format("Node ~p not responding to pings.\n", TargetNode), + ?INFO("Node ~p not responding to pings.\n", TargetNode), erlang:halt(1) end, {ok, Cwd} = file:get_cwd(), @@ -142,7 +324,7 @@ TargetNode. make_script_node(Node) -> - Name, Host = string:tokens(Node, "@"), + Name, Host = string:tokens(atom_to_list(Node), "@"), list_to_atom(lists:concat(Name, "_upgrader_", os:getpid(), "@", Host)). %% get name type from arg
View file
relx-3.21.1.tar.gz/priv/templates/nodetool -> relx-3.26.0.tar.gz/priv/templates/nodetool
Changed
@@ -57,7 +57,7 @@ % spaces, so this converts all of that to a single string to parse String = binary_to_list( list_to_binary( - string:join(ListOfArgs," ") + join(ListOfArgs," ") ) ), @@ -126,16 +126,16 @@ nodename(Name) -> - case string:tokens(Name, "@") of + case re:split(Name, "@", {return, list}, unicode) of _Node, _Host -> list_to_atom(Name); Node -> - _, Host = string:tokens(atom_to_list(node()), "@"), + _, Host = re:split(atom_to_list(node()), "@", {return, list}, unicode), list_to_atom(lists:concat(Node, "@", Host)) end. append_node_suffix(Name, Suffix) -> - case string:tokens(Name, "@") of + case re:split(Name, "@", {return, list}, unicode) of Node, Host -> list_to_atom(lists:concat(Node, Suffix, os:getpid(), "@", Host)); Node -> @@ -165,3 +165,13 @@ {more, Cont1} -> consult(Cont1, eof, Acc) end. + +%% string:join/2 copy; string:join/2 is getting obsoleted +%% and replaced by lists:join/2, but lists:join/2 is too new +%% for version support (only appeared in 19.0) so it cannot be +%% used. Instead we just adopt join/2 locally and hope it works +%% for most unicode use cases anyway. +join(, Sep) when is_list(Sep) -> + ; +join(H|T, Sep) -> + H ++ lists:append(Sep ++ X || X <- T).
View file
relx-3.21.1.tar.gz/priv/templates/vm_args -> relx-3.26.0.tar.gz/priv/templates/vm_args
Changed
@@ -17,3 +17,14 @@ ## Tweak GC to run more often ##-env ERL_FULLSWEEP_AFTER 10 + +# +B c | d | i +# Option c makes Ctrl-C interrupt the current shell instead of invoking the emulator break +# handler. Option d (same as specifying +B without an extra option) disables the break handler. # Option i makes the emulator ignore any break signal. +# If option c is used with oldshell on Unix, Ctrl-C will restart the shell process rather than +# interrupt it. +# Disable the emulator break handler +# it easy to accidentally type ctrl-c when trying +# to reach for ctrl-d. ctrl-c on a live node can +# have very undesirable results +##+Bi
View file
relx-3.21.1.tar.gz/rebar.config -> relx-3.26.0.tar.gz/rebar.config
Changed
@@ -1,9 +1,9 @@ %% -*- mode: Erlang; fill-column: 80; comment-column: 75; -*- %% Dependencies ================================================================ -{deps, {erlware_commons, "0.21.0"}, - {providers, "1.6.0"}, - {getopt, "0.8.2"}, - {cf, "0.2.1"}, +{deps, {erlware_commons, "1.2.0"}, + {providers, "1.7.0"}, + {getopt, "1.0.1"}, + {cf, "0.2.2"}, {bbmustache, "1.0.4"} }. @@ -17,7 +17,7 @@ {platform_define, "^0-9+", namespaced_types}, {platform_define, "^18|9", rand_module}, {platform_define, "^2", rand_module}, - no_debug_info, + {platform_define, "^2", unicode_str}, warnings_as_errors, inline}. @@ -32,20 +32,30 @@ {profiles, {dev, {plugins, rebar3_neotoma_plugin}}, - {test, {erl_opts, debug_info}}, + {test, {erl_opts, nowarn_export_all, debug_info}}, {dialyze, {overrides, {add, erlware_commons, {erl_opts, debug_info}}, {add, providers, {erl_opts, debug_info}}, {add, getopt, {erl_opts, debug_info}}, {add, bbmustache, {erl_opts, debug_info}}, {add, cf, {erl_opts, debug_info}}}, - {erl_opts, debug_info}} + {erl_opts, debug_info}}, + {escript, + {overrides, {add, erlware_commons, {erl_opts, no_debug_info}}, + {add, providers, {erl_opts, no_debug_info}}, + {add, getopt, {erl_opts, no_debug_info}}, + {add, bbmustache, {erl_opts, no_debug_info}}, + {add, cf, {erl_opts, no_debug_info}}}, + {erl_opts, no_debug_info} + } }. {overrides, {override, erlware_commons, {erl_opts, {platform_define, "^0-9+", namespaced_types}, {platform_define, "^R14|5", deprecated_crypto}, {platform_define, "^((18|9)|2)", rand_module}, + {platform_define, "^2", unicode_str}, + {platform_define, "^(R|1|20)", fun_stacktrace}, no_debug_info, warnings_as_errors }, @@ -54,7 +64,8 @@ {override, bbmustache, {erl_opts, no_debug_info}, {deps, }, {plugins, }}, - {override, getopt, {erl_opts, no_debug_info}}, + {override, getopt, {erl_opts, no_debug_info, + {platform_define, "^2", unicode_str}}}, {override, providers, {erl_opts, no_debug_info}} }.
View file
relx-3.21.1.tar.gz/rebar.lock -> relx-3.26.0.tar.gz/rebar.lock
Changed
@@ -1,5 +1,14 @@ +{"1.1.0", {<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.4">>},0}, - {<<"cf">>,{pkg,<<"cf">>,<<"0.2.1">>},0}, - {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"0.21.0">>},0}, - {<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0}, - {<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},0}. + {<<"cf">>,{pkg,<<"cf">>,<<"0.2.2">>},0}, + {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.2.0">>},0}, + {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}, + {<<"providers">>,{pkg,<<"providers">>,<<"1.7.0">>},0}}. + +{pkg_hash, + {<<"bbmustache">>, <<"7BA94F971C5AFD7B6617918A4BB74705E36CAB36EB84B19B6A1B7EE06427AA38">>}, + {<<"cf">>, <<"7F2913FFF90ABCABD0F489896CFEB0B0674F6C8DF6C10B17A83175448029896C">>}, + {<<"erlware_commons">>, <<"2BAB99CF88941145767A502F1209886F1F0D31695EEF21978A30F15E645721E0">>}, + {<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}, + {<<"providers">>, <<"BBF730563914328EC2511D205E6477A94831DB7297DE313B3872A2B26C562EAB">>}} +.
View file
relx-3.21.1.tar.gz/src/rlx_app_discovery.erl -> relx-3.26.0.tar.gz/src/rlx_app_discovery.erl
Changed
@@ -40,7 +40,7 @@ ec_cmd_log:info(rlx_state:log(State), fun() -> "Resolving OTP Applications from directories:\n", - string:join(rlx_util:indent(2), LibDir || LibDir <- LibDirs, "\n") + rlx_string:join(rlx_util:indent(2), LibDir || LibDir <- LibDirs, "\n") end), resolve_app_metadata(State, LibDirs). @@ -293,10 +293,21 @@ -spec get_deps(binary(), atom(), string(), proplists:proplist()) -> {ok, rlx_app_info:t()} | {error, Reason::term()}. get_deps(AppDir, AppName, AppVsn, AppDetail) -> - ActiveApps = proplists:get_value(applications, AppDetail, ), + %% ensure that at least stdlib and kernel are defined as application deps + ActiveApps = ensure_stdlib_kernel(AppName, + proplists:get_value(applications, AppDetail, )), LibraryApps = proplists:get_value(included_applications, AppDetail, ), rlx_app_info:new(AppName, AppVsn, AppDir, ActiveApps, LibraryApps). +-spec ensure_stdlib_kernel(AppName :: atom(), + Apps :: list(atom())) -> list(atom()). +ensure_stdlib_kernel(kernel, Deps) -> Deps; +ensure_stdlib_kernel(stdlib, Deps) -> Deps; +ensure_stdlib_kernel(_AppName, ) -> + %% minimum required deps are kernel and stdlib + kernel, stdlib; +ensure_stdlib_kernel(_AppName, Deps) -> Deps. + %%%=================================================================== %%% Test Functions %%%===================================================================
View file
relx-3.21.1.tar.gz/src/rlx_cmd_args.erl -> relx-3.26.0.tar.gz/src/rlx_cmd_args.erl
Changed
@@ -282,6 +282,9 @@ Erts when is_list(Erts) -> {include_erts, Erts} end; +create(warnings_as_errors, Opts) -> + WarningsAsErrors = proplists:get_value(warnings_as_errors, Opts, false), + {warnings_as_errors, WarningsAsErrors}; create(_, _) -> .
View file
relx-3.21.1.tar.gz/src/rlx_config.erl -> relx-3.26.0.tar.gz/src/rlx_config.erl
Changed
@@ -173,6 +173,8 @@ {ok, rlx_state:skip_apps(State0, SkipApps0)}; load_terms({exclude_apps, ExcludeApps0}, {ok, State0}) -> {ok, rlx_state:exclude_apps(State0, ExcludeApps0)}; +load_terms({exclude_modules, ExcludeModules0}, {ok, State0}) -> + {ok, rlx_state:exclude_modules(State0, ExcludeModules0)}; load_terms({debug_info, DebugInfo}, {ok, State0}) -> {ok, rlx_state:debug_info(State0, DebugInfo)}; load_terms({overrides, Overrides0}, {ok, State0}) -> @@ -254,10 +256,14 @@ {ok, rlx_state:vm_args(State, false)}; load_terms({vm_args, VmArgs}, {ok, State}) -> {ok, rlx_state:vm_args(State, filename:absname(VmArgs))}; +load_terms({vm_args_src, VmArgs}, {ok, State}) -> + {ok, rlx_state:vm_args_src(State, filename:absname(VmArgs))}; load_terms({sys_config, false}, {ok, State}) -> {ok, rlx_state:sys_config(State, false)}; load_terms({sys_config, SysConfig}, {ok, State}) -> {ok, rlx_state:sys_config(State, filename:absname(SysConfig))}; +load_terms({sys_config_src, SysConfigSrc}, {ok, State}) -> + {ok, rlx_state:sys_config_src(State, filename:absname(SysConfigSrc))}; load_terms({root_dir, Root}, {ok, State}) -> {ok, rlx_state:root_dir(State, filename:absname(Root))}; load_terms({output_dir, OutputDir}, {ok, State}) -> @@ -267,6 +273,8 @@ NewOverlayVars0 = list_of_overlay_vars_files(OverlayVars), NewOverlayVars1 = CurrentOverlayVars ++ NewOverlayVars0, {ok, rlx_state:put(State, overlay_vars, NewOverlayVars1)}; +load_terms({warnings_as_errors, WarningsAsErrors}, {ok, State}) -> + {ok, rlx_state:warnings_as_errors(State, WarningsAsErrors)}; load_terms({Name, Value}, {ok, State}) when erlang:is_atom(Name) -> {ok, rlx_state:put(State, Name, Value)}; @@ -336,8 +344,8 @@ parse_vsn(Vsn) when Vsn =:= semver ; Vsn =:= "semver" -> {ok, V} = ec_git_vsn:vsn(ec_git_vsn:new()), V; -parse_vsn({semver, _}) -> - {ok, V} = ec_git_vsn:vsn(ec_git_vsn:new()), +parse_vsn({semver, Data}) -> + {ok, V} = ec_git_vsn:vsn(Data), V; parse_vsn({cmd, Command}) -> V = os:cmd(Command),
View file
relx-3.21.1.tar.gz/src/rlx_depsolver.erl -> relx-3.26.0.tar.gz/src/rlx_depsolver.erl
Changed
@@ -113,7 +113,7 @@ %% type %%============================================================================ -ifdef(namespaced_types). --type dep_graph() :: gb_tree:tree(). +-type dep_graph() :: gb_trees:tree(). -else. -type dep_graph() :: gb_tree(). -endif. @@ -484,8 +484,7 @@ {value, {PkgName, Constraints0}} -> Constraints0 end, - {PkgName, {PkgConstraint, {SrcPkg, SrcVsn}} | Constraints1} - | lists:keydelete(PkgName, 1, PkgsConstraints). + lists:keydelete(PkgName, 1, PkgsConstraints)++{PkgName, {PkgConstraint, {SrcPkg, SrcVsn}} | Constraints1}. %% @doc %% Extend the currently active constraints correctly for the given constraints. @@ -625,7 +624,7 @@ F = fun (Vsn) -> Deps = get_dep_constraints(DepGraph, Pkg, Vsn), UConstraints = extend_constraints(Pkg, Vsn, Constraints, Deps), - DepPkgs =dep_pkg(Dep) || Dep <- Deps, + DepPkgs = dep_pkg(Dep) || Dep <- Deps, NewVisited = {Pkg, Vsn} | Visited, Res = all_pkgs(DepGraph, NewVisited, DepPkgs ++ OtherPkgs, UConstraints, PathInd), Res
View file
relx-3.21.1.tar.gz/src/rlx_goal.erl -> relx-3.26.0.tar.gz/src/rlx_goal.erl
Changed
@@ -10,8 +10,6 @@ -define(p_seq,true). -define(p_string,true). - --compile(export_all). -spec file(file:name()) -> any(). file(Filename) -> case file:read_file(Filename) of {ok,Bin} -> parse(Bin); Err -> Err end.
View file
relx-3.21.1.tar.gz/src/rlx_prv_app_discover.erl -> relx-3.26.0.tar.gz/src/rlx_prv_app_discover.erl
Changed
@@ -132,7 +132,7 @@ add_environment_lib_dir(_State) -> case os:getenv("ERL_LIBS") of false -> ; - Libs -> erlang:iolist_to_binary(L) || L <- string:tokens(Libs, ":") + Libs -> erlang:iolist_to_binary(L) || L <- rlx_string:lexemes(Libs, ":") end. %% Order matters so this slow dedup needs to be used
View file
relx-3.21.1.tar.gz/src/rlx_prv_assembler.erl -> relx-3.26.0.tar.gz/src/rlx_prv_assembler.erl
Changed
@@ -86,8 +86,17 @@ format_error({ec_file_error, AppDir, TargetDir, E}) -> io_lib:format("Unable to copy OTP App from ~s to ~s due to ~p", AppDir, TargetDir, E); +format_error({vmargs_does_not_exist, Path}) -> + io_lib:format("The vm.args file specified for this release (~s) does not exist!", + Path); +format_error({vmargs_src_does_not_exist, Path}) -> + io_lib:format("The vm.args.src file specified for this release (~s) does not exist!", + Path); format_error({config_does_not_exist, Path}) -> - io_lib:format("The config file specified for this release (~s) does not exist!", + io_lib:format("The sys.config file specified for this release (~s) does not exist!", + Path); +format_error({config_src_does_not_exist, Path}) -> + io_lib:format("The sys.config.src file specified for this release (~s) does not exist!", Path); format_error({sys_config_parse_error, ConfigPath, Reason}) -> io_lib:format("The config file (~s) specified for this release could not be opened or parsed: ~s", @@ -111,17 +120,20 @@ io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s", AppDir, TargetDir, rlx_util:indent(2), file:format_error(Reason)); -format_error(start_clean_script_generation_error) -> +format_error(boot_script_generation_error) -> "Unknown internal release error generating start_clean.boot"; -format_error({start_clean_script_generation_warning, Module, Warnings}) -> +format_error({boot_script_generation_warning, Module, Warnings}) -> "Warnings generating start_clean.boot \s", rlx_util:indent(2), Module:format_warning(Warnings); -format_error({start_clean_script_generation_error, Module, Errors}) -> +format_error({boot_script_generation_error, Module, Errors}) -> "Errors generating start_clean.boot \n", rlx_util:indent(2), Module:format_error(Errors); format_error({strip_release, Reason}) -> io_lib:format("Stripping debug info from release beam files failed becuase ~s", - beam_lib:format_error(Reason)). + beam_lib:format_error(Reason)); +format_error({rewrite_app_file, AppFile, Error}) -> + io_lib:format("Unable to rewrite .app file ~s due to ~p", + AppFile, Error). %%%=================================================================== %%% Internal Functions @@ -162,7 +174,7 @@ false end, lists:flatten(ec_plists:map(fun(App) -> - copy_app(LibDir, App, IncludeSrc, IncludeErts) + copy_app(State, LibDir, App, IncludeSrc, IncludeErts) end, Apps))), case Result of E | _ -> @@ -179,7 +191,7 @@ Apps end. -copy_app(LibDir, App, IncludeSrc, IncludeErts) -> +copy_app(State, LibDir, App, IncludeSrc, IncludeErts) -> AppName = erlang:atom_to_list(rlx_app_info:name(App)), AppVsn = rlx_app_info:original_vsn(App), AppDir = rlx_app_info:dir(App), @@ -196,57 +208,75 @@ true -> ; false -> - copy_app_(App, AppDir, TargetDir, IncludeSrc) + copy_app_(State, App, AppDir, TargetDir, IncludeSrc) end; _ -> - copy_app_(App, AppDir, TargetDir, IncludeSrc) + copy_app_(State, App, AppDir, TargetDir, IncludeSrc) end end. is_erts_lib(Dir) -> lists:prefix(filename:split(list_to_binary(code:lib_dir())), filename:split(Dir)). -copy_app_(App, AppDir, TargetDir, IncludeSrc) -> +copy_app_(State, App, AppDir, TargetDir, IncludeSrc) -> remove_symlink_or_directory(TargetDir), case rlx_app_info:link(App) of true -> link_directory(AppDir, TargetDir), - rewrite_app_file(App, AppDir); + rewrite_app_file(State, App, AppDir); false -> - copy_directory(AppDir, TargetDir, IncludeSrc), - rewrite_app_file(App, TargetDir) + copy_directory(State, App, AppDir, TargetDir, IncludeSrc), + rewrite_app_file(State, App, TargetDir) end. %% If excluded apps exist in this App's applications list we must write a new .app -rewrite_app_file(App, TargetDir) -> +rewrite_app_file(State, App, TargetDir) -> Name = rlx_app_info:name(App), ActiveDeps = rlx_app_info:active_deps(App), IncludedDeps = rlx_app_info:library_deps(App), AppFile = filename:join(TargetDir, "ebin", ec_cnv:to_list(Name) ++ ".app"), - {ok, {application, AppName, AppData}} = file:consult(AppFile), - OldActiveDeps = proplists:get_value(applications, AppData, ), - OldIncludedDeps = proplists:get_value(included_applications, AppData, ), - - case {OldActiveDeps, OldIncludedDeps} of - {ActiveDeps, IncludedDeps} -> - ok; - _ -> - AppData1 = lists:keyreplace(applications - ,1 - ,AppData - ,{applications, ActiveDeps}), - AppData2 = lists:keyreplace(included_applications - ,1 - ,AppData1 - ,{included_applications, IncludedDeps}), - Spec = io_lib:format("~p.\n", {application, AppName, AppData2}), - write_file_if_contents_differ(AppFile, Spec) + {ok, {application, AppName, AppData0}} = file:consult(AppFile), + OldActiveDeps = proplists:get_value(applications, AppData0, ), + OldIncludedDeps = proplists:get_value(included_applications, AppData0, ), + OldModules = proplists:get_value(modules, AppData0, ), + ExcludedModules = proplists:get_value(Name, + rlx_state:exclude_modules(State), ), + + %% maybe replace excluded apps + AppData2 = + case {OldActiveDeps, OldIncludedDeps} of + {ActiveDeps, IncludedDeps} -> + AppData0; + _ -> + AppData1 = lists:keyreplace(applications + ,1 + ,AppData0 + ,{applications, ActiveDeps}), + lists:keyreplace(included_applications + ,1 + ,AppData1 + ,{included_applications, IncludedDeps}) + end, + %% maybe replace excluded modules + AppData3 = + case ExcludedModules of + -> AppData2; + _ -> + lists:keyreplace(modules + ,1 + ,AppData2 + ,{modules, OldModules -- ExcludedModules}) + end, + Spec = {application, AppName, AppData3}, + case write_file_if_contents_differ(AppFile, Spec) of + ok -> ok; + Error -> ?RLX_ERROR({rewrite_app_file, AppFile, Error}) end. -write_file_if_contents_differ(Filename, Bytes) -> - ToWrite = iolist_to_binary(Bytes), - case file:read_file(Filename) of - {ok, ToWrite} -> +write_file_if_contents_differ(Filename, Spec) -> + ToWrite = io_lib:format("~p.\n", Spec), + case file:consult(Filename) of + {ok, Spec} -> ok; {ok, _} -> file:write_file(Filename, ToWrite); @@ -275,8 +305,8 @@ ok end. -copy_directory(AppDir, TargetDir, IncludeSrc) -> - copy_dir(AppDir, TargetDir, SubDir) +copy_directory(State, App, AppDir, TargetDir, IncludeSrc) -> + copy_dir(State, App, AppDir, TargetDir, SubDir) || SubDir <- "ebin", "include", "priv", @@ -289,13 +319,20 @@ end. -copy_dir(AppDir, TargetDir, SubDir) -> +copy_dir(State, App, AppDir, TargetDir, SubDir) -> SubSource = filename:join(AppDir, SubDir), SubTarget = filename:join(TargetDir, SubDir), case ec_file:is_dir(SubSource) of true -> ok = rlx_util:mkdir_p(SubTarget), - case ec_file:copy(SubSource, SubTarget, recursive) of + %% get a list of the modules to be excluded from this app + AppName = rlx_app_info:name(App), + ExcludedModules = proplists:get_value(AppName, rlx_state:exclude_modules(State), + ), + ExcludedFiles = filename:join(binary_to_list(SubSource), + atom_to_list(M) ++ ".beam") || + M <- ExcludedModules, + case copy_dir(SubSource, SubTarget, ExcludedFiles) of {error, E} -> ?RLX_ERROR({ec_file_error, AppDir, SubTarget, E}); ok -> @@ -305,22 +342,43 @@ ok end. +%% no files are excluded, just copy the whole dir +copy_dir(SourceDir, TargetDir, ) -> + case ec_file:copy(SourceDir, TargetDir, recursive, {file_info, mode, time}) of + {error, E} -> {error, E}; + ok -> + ok + end; +copy_dir(SourceDir, TargetDir, ExcludeFiles) -> + SourceFiles = filelib:wildcard( + filename:join(binary_to_list(SourceDir), "*")), + lists:foreach(fun(F) -> + ok = ec_file:copy(F, + filename:join(TargetDir, + filename:basename(F)), {file_info, mode, time}) + end, SourceFiles -- ExcludeFiles). + create_release_info(State0, Release0, OutputDir) -> RelName = atom_to_list(rlx_release:name(Release0)), ReleaseDir = rlx_util:release_output_dir(State0, Release0), ReleaseFile = filename:join(ReleaseDir, RelName ++ ".rel"), StartCleanFile = filename:join(ReleaseDir, "start_clean.rel"), + NoDotErlFile = filename:join(ReleaseDir, "no_dot_erlang.rel"), ok = ec_file:mkdir_p(ReleaseDir), Release1 = rlx_release:relfile(Release0, ReleaseFile), State1 = rlx_state:update_realized_release(State0, Release1), case rlx_release:metadata(Release1) of {ok, Meta} -> - case rlx_release:start_clean_metadata(Release1) of - {ok, StartCleanMeta} -> + case {rlx_release:start_clean_metadata(Release1), + rlx_release:no_dot_erlang_metadata(Release1)} of + {{ok, StartCleanMeta}, {ok, NoDotErlMeta}} -> ok = ec_file:write_term(ReleaseFile, Meta), ok = ec_file:write_term(StartCleanFile, StartCleanMeta), + ok = ec_file:write_term(NoDotErlFile, NoDotErlMeta), write_bin_file(State1, Release1, OutputDir, ReleaseDir); - E -> + {{ok, _}, E} -> + E; + {_, E} -> E end; E -> @@ -335,7 +393,7 @@ VsnRel = filename:join(BinDir, rlx_release:canonical_name(Release)), BareRel = filename:join(BinDir, RelName), ErlOpts = rlx_state:get(State, erl_opts, ""), - {OsFamily, _OsName} = os:type(), + {OsFamily, _OsName} = rlx_util:os_type(State), StartFile = case rlx_state:get(State, extended_start_script, false) of false -> @@ -349,13 +407,20 @@ rlx_release:erts(Release), ErlOpts); true -> - case rlx_state:get(State, extended_start_script, false) of - true -> - include_nodetool(BinDir); - false -> - ok - end, - extended_bin_file_contents(OsFamily, RelName, RelVsn, rlx_release:erts(Release), ErlOpts) + %% extended start script needs nodetool so it's + %% always included + include_nodetool(BinDir), + Hooks = expand_hooks(BinDir, + rlx_state:get(State, + extended_start_script_hooks, + ), + State), + Extensions = rlx_state:get(State, + extended_start_script_extensions, + ), + extended_bin_file_contents(OsFamily, RelName, RelVsn, + rlx_release:erts(Release), ErlOpts, + Hooks, Extensions) end, %% We generate the start script by default, unless the user %% tells us not too @@ -365,13 +430,13 @@ _ -> VsnRelStartFile = case OsFamily of unix -> VsnRel; - win32 -> string:concat(VsnRel, ".cmd") + win32 -> rlx_string:concat(VsnRel, ".cmd") end, ok = file:write_file(VsnRelStartFile, StartFile), ok = file:change_mode(VsnRelStartFile, 8#777), BareRelStartFile = case OsFamily of unix -> BareRel; - win32 -> string:concat(BareRel, ".cmd") + win32 -> rlx_string:concat(BareRel, ".cmd") end, ok = file:write_file(BareRelStartFile, StartFile), ok = file:change_mode(BareRelStartFile, 8#777) @@ -386,6 +451,98 @@ E end. +expand_hooks(_Bindir, , _State) -> ; +expand_hooks(BinDir, Hooks, _State) -> + expand_hooks(BinDir, Hooks, , _State). + +expand_hooks(_BinDir, , Acc, _State) -> Acc; +expand_hooks(BinDir, {Phase, Hooks0} | Rest, Acc, State) -> + %% filter and expand hooks to their respective shell scripts + Hooks = + lists:foldl( + fun(Hook, Acc0) -> + case validate_hook(Phase, Hook) of + true -> + %% all hooks are relative to the bin dir + HookScriptFilename = filename:join(BinDir, + hook_filename(Hook)), + %% write the hook script file to it's proper location + ok = render_hook(hook_template(Hook), HookScriptFilename, State), + %% and return the invocation that's to be templated in the + %% extended script + Acc0 ++ hook_invocation(Hook); + false -> + ec_cmd_log:error( + rlx_state:log(State), + io_lib:format("~p hook is not allowed in the ~p phase, ignoring it", Hook, Phase) + ), + + Acc0 + end + end, , Hooks0), + expand_hooks(BinDir, Rest, Acc ++ {Phase, Hooks}, State). + +%% the pid script hook is only allowed in the +%% post_start phase +%% with args +validate_hook(post_start, {pid, _}) -> true; +%% and without args +validate_hook(post_start, pid) -> true; +%% same for wait_for_vm_start, wait_for_process script +validate_hook(post_start, wait_for_vm_start) -> true; +validate_hook(post_start, {wait_for_process, _}) -> true; +%% custom hooks are allowed in all phases +validate_hook(_Phase, {custom, _}) -> true; +%% as well as status hooks +validate_hook(status, _) -> true; +%% deny all others +validate_hook(_, _) -> false. + +hook_filename({custom, CustomScript}) -> CustomScript; +hook_filename(pid) -> "hooks/builtin/pid"; +hook_filename({pid, _}) -> "hooks/builtin/pid"; +hook_filename(wait_for_vm_start) -> "hooks/builtin/wait_for_vm_start"; +hook_filename({wait_for_process, _}) -> "hooks/builtin/wait_for_process"; +hook_filename(builtin_status) -> "hooks/builtin/status". + +hook_invocation({custom, CustomScript}) -> CustomScript; +%% the pid builtin hook with no arguments writes to pid file +%% at /var/run/{{ rel_name }}.pid +hook_invocation(pid) -> rlx_string:join("hooks/builtin/pid", + "/var/run/$REL_NAME.pid", "|"); +hook_invocation({pid, PidFile}) -> rlx_string:join("hooks/builtin/pid", + PidFile, "|"); +hook_invocation(wait_for_vm_start) -> "hooks/builtin/wait_for_vm_start"; +hook_invocation({wait_for_process, Name}) -> + %% wait_for_process takes an atom as argument + %% which is the process name to wait for + rlx_string:join("hooks/builtin/wait_for_process", + atom_to_list(Name), "|"); +hook_invocation(builtin_status) -> "hooks/builtin/status". + +hook_template({custom, _}) -> custom; +hook_template(pid) -> builtin_hook_pid; +hook_template({pid, _}) -> builtin_hook_pid; +hook_template(wait_for_vm_start) -> builtin_hook_wait_for_vm_start; +hook_template({wait_for_process, _}) -> builtin_hook_wait_for_process; +hook_template(builtin_status) -> builtin_hook_status. + +%% custom hooks are not rendered, they should +%% be copied by the release overlays +render_hook(custom, _, _) -> ok; +render_hook(TemplateName, Script, State) -> + ec_cmd_log:info( + rlx_state:log(State), + "rendering ~p hook to ~p~n", + TemplateName, Script + ), + + Template = render(TemplateName), + ok = filelib:ensure_dir(Script), + _ = ec_file:remove(Script), + ok = file:write_file(Script, Template), + ok = file:change_mode(Script, 8#755). + include_nodetool(BinDir) -> NodeToolFile = nodetool_contents(), InstallUpgradeFile = install_upgrade_escript_contents(), @@ -409,18 +566,38 @@ copy_or_generate_vmargs_file(State, Release, RelDir) -> RelVmargsPath = filename:join(RelDir, "vm.args"), - case rlx_state:vm_args(State) of - false -> - ok; + RelVmargsSrcPath = filename:join(RelDir, "vm.args.src"), + case rlx_state:vm_args_src(State) of undefined -> - RelName = erlang:atom_to_list(rlx_release:name(Release)), - unless_exists_write_default(RelVmargsPath, vm_args_file(RelName)); - ArgsPath -> - case filelib:is_regular(ArgsPath) of + case rlx_state:vm_args(State) of false -> - ?RLX_ERROR({vmargs_does_not_exist, ArgsPath}); + ok; + undefined -> + RelName = erlang:atom_to_list(rlx_release:name(Release)), + unless_exists_write_default(RelVmargsPath, vm_args_file(RelName)); + ArgsPath -> + case filelib:is_regular(ArgsPath) of + false -> + ?RLX_ERROR({vmargs_does_not_exist, ArgsPath}); + true -> + copy_or_symlink_config_file(State, ArgsPath, RelVmargsPath) + end + end; + ArgsSrcPath -> + %% print a warning if vm_args is also set + case rlx_state:vm_args(State) of + undefined -> + ok; + _-> + ec_cmd_log:warn(rlx_state:log(State), + "Both vm_args_src and vm_args are set, vm_args will be ignored~n", ) + end, + + case filelib:is_regular(ArgsSrcPath) of + false -> + ?RLX_ERROR({vmargs_src_does_not_exist, ArgsSrcPath}); true -> - copy_or_symlink_config_file(State, ArgsPath, RelVmargsPath) + copy_or_symlink_config_file(State, ArgsSrcPath, RelVmargsSrcPath) end end. @@ -429,23 +606,43 @@ {ok, rlx_state:t()} | relx:error(). copy_or_generate_sys_config_file(State, RelDir) -> RelSysConfPath = filename:join(RelDir, "sys.config"), - case rlx_state:sys_config(State) of - false -> - ok; + RelSysConfSrcPath = filename:join(RelDir, "sys.config.src"), + case rlx_state:sys_config_src(State) of undefined -> - unless_exists_write_default(RelSysConfPath, sys_config_file()); - ConfigPath -> - case filelib:is_regular(ConfigPath) of + case rlx_state:sys_config(State) of false -> - ?RLX_ERROR({config_does_not_exist, ConfigPath}); - true -> - %% validate sys.config is valid Erlang terms - case file:consult(ConfigPath) of - {ok, _} -> - copy_or_symlink_config_file(State, ConfigPath, RelSysConfPath); - {error, Reason} -> - ?RLX_ERROR({sys_config_parse_error, ConfigPath, Reason}) + ok; + undefined -> + unless_exists_write_default(RelSysConfPath, sys_config_file()); + ConfigPath -> + case filelib:is_regular(ConfigPath) of + false -> + ?RLX_ERROR({config_does_not_exist, ConfigPath}); + true -> + %% validate sys.config is valid Erlang terms + case file:consult(ConfigPath) of + {ok, _} -> + copy_or_symlink_config_file(State, ConfigPath, RelSysConfPath); + {error, Reason} -> + ?RLX_ERROR({sys_config_parse_error, ConfigPath, Reason}) + end end + end; + ConfigSrcPath -> + %% print a warning if sys_config is also set + case rlx_state:sys_config(State) of + P when P =:= false orelse P =:= undefined -> + ok; + _-> + ec_cmd_log:warn(rlx_state:log(State), + "Both sys_config_src and sys_config are set, sys_config will be ignored~n", ) + end, + + case filelib:is_regular(ConfigSrcPath) of + false -> + ?RLX_ERROR({config_src_does_not_exist, ConfigSrcPath}); + true -> + copy_or_symlink_config_file(State, ConfigSrcPath, RelSysConfSrcPath) end end. @@ -456,9 +653,9 @@ ensure_not_exist(RelConfPath), case rlx_state:dev_mode(State) of true -> - ok = rlx_util:symlink_or_copy(ConfigPath, RelConfPath ++ ".orig"); + ok = rlx_util:symlink_or_copy(ConfigPath, RelConfPath); _ -> - ok = ec_file:copy(ConfigPath, RelConfPath) + ok = ec_file:copy(ConfigPath, RelConfPath, {file_info, mode, time}) end. %% @doc Optionally add erts directory to release, if defined. @@ -483,13 +680,13 @@ ErtsVersion = rlx_release:erts(Release), ErtsDir = filename:join(Prefix, "erts-" ++ ErtsVersion), LocalErts = filename:join(OutputDir, "erts-" ++ ErtsVersion), - {OsFamily, _OsName} = os:type(), + {OsFamily, _OsName} = rlx_util:os_type(State), case ec_file:is_dir(ErtsDir) of false -> ?RLX_ERROR({specified_erts_does_not_exist, ErtsVersion}); true -> ok = ec_file:mkdir_p(LocalErts), - ok = ec_file:copy(ErtsDir, LocalErts, recursive), + ok = ec_file:copy(ErtsDir, LocalErts, recursive, {file_info, mode, time}), case OsFamily of unix -> Erl = filename:join(LocalErts, "bin", "erl"), @@ -507,7 +704,11 @@ true -> ok; false -> SrcDir = filename:join(LocalErts, "src"), - ok = ec_file:remove(SrcDir, recursive) + %% ensure the src folder exists before deletion + case ec_file:exists(SrcDir) of + true -> ok = ec_file:remove(SrcDir, recursive); + false -> ok + end end, case rlx_state:get(State, extended_start_script, false) of @@ -545,6 +746,7 @@ ec_cmd_log:info(rlx_state:log(State), "release successfully created!"), create_RELEASES(OutputDir, ReleaseFile), + create_no_dot_erlang(RelDir, OutputDir, Options, State), create_start_clean(RelDir, OutputDir, Options, State); error -> ?RLX_ERROR({release_script_generation_error, ReleaseFile}); @@ -552,6 +754,7 @@ ec_cmd_log:info(rlx_state:log(State), "release successfully created!"), create_RELEASES(OutputDir, ReleaseFile), + create_no_dot_erlang(RelDir, OutputDir, Options, State), create_start_clean(RelDir, OutputDir, Options, State); {ok,Module,Warnings} -> ?RLX_ERROR({release_script_generation_warn, Module, Warnings}); @@ -567,7 +770,7 @@ % (dictated by erl.ini erlang Rootdir=) and so a boot variable is made % pointing to the release directory % On non-Windows, $ROOT is set by the ROOTDIR environment variable as the - % release directory, so a boot variable is made pointing to the erts + % release directory, so a boot variable is made pointing to the erts % directory. % NOTE the boot variable can point to either the release/erts root directory % or the release/erts lib directory, as long as the usage here matches the @@ -581,29 +784,37 @@ {"ERTS_LIB_DIR", code:lib_dir()} end. +create_no_dot_erlang(RelDir, OutputDir, Options, State) -> + create_boot_file(RelDir, OutputDir, Options, State, "no_dot_erlang"). + create_start_clean(RelDir, OutputDir, Options, State) -> + create_boot_file(RelDir, OutputDir, Options, State, "start_clean"). + +create_boot_file(RelDir, OutputDir, Options, State, Name) -> case rlx_util:make_script(Options, fun(CorrectedOptions) -> - systools:make_script("start_clean", CorrectedOptions) + systools:make_script(Name, CorrectedOptions) end) of ok -> - ok = ec_file:copy(filename:join(RelDir, "start_clean.boot"), - filename:join(OutputDir, "bin", "start_clean.boot")), - ec_file:remove(filename:join(RelDir, "start_clean.rel")), - ec_file:remove(filename:join(RelDir, "start_clean.script")), + ok = ec_file:copy(filename:join(RelDir, Name++".boot"), + filename:join(OutputDir, "bin", Name++".boot"), + {file_info, mode, time}), + ec_file:remove(filename:join(RelDir, Name++".rel")), + ec_file:remove(filename:join(RelDir, Name++".script")), {ok, State}; error -> - ?RLX_ERROR(start_clean_script_generation_error); + ?RLX_ERROR(boot_script_generation_error); {ok, _, } -> - ok = ec_file:copy(filename:join(RelDir, "start_clean.boot"), - filename:join(OutputDir, "bin", "start_clean.boot")), - ec_file:remove(filename:join(RelDir, "start_clean.rel")), - ec_file:remove(filename:join(RelDir, "start_clean.script")), + ok = ec_file:copy(filename:join(RelDir, Name++".boot"), + filename:join(OutputDir, "bin", Name++".boot"), + {file_info, mode, time}), + ec_file:remove(filename:join(RelDir, Name++".rel")), + ec_file:remove(filename:join(RelDir, Name++".script")), {ok, State}; {ok,Module,Warnings} -> - ?RLX_ERROR({start_clean_script_generation_warn, Module, Warnings}); + ?RLX_ERROR({boot_script_generation_warn, Module, Warnings}); {error,Module,Error} -> - ?RLX_ERROR({start_clean_script_generation_error, Module, Error}) + ?RLX_ERROR({boot_script_generation_error, Module, Error}) end. create_RELEASES(OutputDir, ReleaseFile) -> @@ -643,16 +854,50 @@ render(Template, {rel_name, RelName}, {rel_vsn, RelVsn}, {erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}). -extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts) -> +extended_bin_file_contents(OsFamily, RelName, RelVsn, ErtsVsn, ErlOpts, Hooks, Extensions) -> Template = case OsFamily of unix -> extended_bin; win32 -> extended_bin_windows end, + %% turn all the hook lists into space separated strings + PreStartHooks = rlx_string:join(proplists:get_value(pre_start, Hooks, ), " "), + PostStartHooks = rlx_string:join(proplists:get_value(post_start, Hooks, ), " "), + PreStopHooks = rlx_string:join(proplists:get_value(pre_stop, Hooks, ), " "), + PostStopHooks = rlx_string:join(proplists:get_value(post_stop, Hooks, ), " "), + PreInstallUpgradeHooks = rlx_string:join(proplists:get_value(pre_install_upgrade, + Hooks, ), " "), + PostInstallUpgradeHooks = rlx_string:join(proplists:get_value(post_install_upgrade, + Hooks, ), " "), + StatusHook = rlx_string:join(proplists:get_value(status, Hooks, ), " "), + {ExtensionsList1, ExtensionDeclarations1} = + lists:foldl(fun({Name, Script}, + {ExtensionsList0, ExtensionDeclarations0}) -> + ExtensionDeclaration = atom_to_list(Name) ++ + "_extension=\"" ++ + Script ++ "\"", + {ExtensionsList0 ++ atom_to_list(Name), + ExtensionDeclarations0 ++ ExtensionDeclaration} + end, {, }, Extensions), + % pipe separated string of extensions, to show on the start script usage + % (eg. foo|bar) + ExtensionsList = rlx_string:join(ExtensionsList1 ++ "undefined", "|"), + % command separated string of extension script declarations + % (eg. foo_extension="path/to/foo_script") + ExtensionDeclarations = rlx_string:join(ExtensionDeclarations1, ";"), render(Template, {rel_name, RelName}, {rel_vsn, RelVsn}, - {erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}). + {erts_vsn, ErtsVsn}, {erl_opts, ErlOpts}, + {pre_start_hooks, PreStartHooks}, + {post_start_hooks, PostStartHooks}, + {pre_stop_hooks, PreStopHooks}, + {post_stop_hooks, PostStopHooks}, + {pre_install_upgrade_hooks, PreInstallUpgradeHooks}, + {post_install_upgrade_hooks, PostInstallUpgradeHooks}, + {status_hook, StatusHook}, + {extensions, ExtensionsList}, + {extension_declarations, ExtensionDeclarations}). erl_ini(OutputDir, ErtsVsn) -> - ErtsDirName = string:concat("erts-", ErtsVsn), + ErtsDirName = rlx_string:concat("erts-", ErtsVsn), BinDir = filename:join(OutputDir, ErtsDirName, bin), render(erl_ini, {bin_dir, BinDir}, {output_dir, OutputDir}).
View file
relx-3.21.1.tar.gz/src/rlx_prv_overlay.erl -> relx-3.26.0.tar.gz/src/rlx_prv_overlay.erl
Changed
@@ -245,6 +245,7 @@ -spec generate_release_vars(rlx_release:t()) -> proplists:proplist(). generate_release_vars(Release) -> {erts_vsn, rlx_release:erts(Release)}, + {erts_dir, code:root_dir()}, {release_erts_version, rlx_release:erts(Release)}, {release_name, rlx_release:name(Release)}, {rel_vsn, rlx_release:vsn(Release)}, @@ -308,6 +309,28 @@ -spec do_individual_overlay(rlx_state:t(), list(), proplists:proplist(), OverlayDirective::term()) -> {ok, rlx_state:t()} | relx:error(). +do_individual_overlay(State, _Files, OverlayVars, {chmod, Mode, Path}) -> + % mode can be specified directly as an integer value, or if it is + % not an integer we assume it's a template, which we render and convert + % blindly to an integer. So this will crash with an exception if for + % some reason something other than an integer is used + NewMode = + case is_integer(Mode) of + true -> Mode; + false -> erlang:list_to_integer(erlang:binary_to_list(render_string (OverlayVars, Mode))) + end, + + Root = rlx_state:output_dir(State), + file_render_do(OverlayVars, Path, + fun(NewPath) -> + Absolute = absolutize(State, + filename:join(Root,erlang:iolist_to_binary (NewPath))), + case file:change_mode(Absolute, NewMode) of + {error, Error} -> + ?RLX_ERROR({unable_to_chmod, NewMode, NewPath, Error}); + ok -> ok + end + end); do_individual_overlay(State, _Files, OverlayVars, {mkdir, Dir}) -> case rlx_util:render(erlang:iolist_to_binary(Dir), OverlayVars) of {ok, IoList} -> @@ -379,10 +402,8 @@ erlang:iolist_to_binary(filename:join(ToFile1, filename:basename(FromFile1))) end, - case ec_file:copy(FromFile1, ToFile2, recursive) of + case ec_file:copy(FromFile1, ToFile2, recursive, {file_info, mode, time}) of ok -> - {ok, FileInfo} = file:read_file_info(FromFile1), - ok = file:write_file_info(ToFile2, FileInfo), ok; {error, Err} -> ?RLX_ERROR({copy_failed, @@ -461,10 +482,17 @@ {ok, IoData} -> case filelib:ensure_dir(ToFile) of ok -> + %% we were asked to render a template + %% onto a symlink, this would cause an overwrite + %% of the original file, so we delete the symlink + %% and go ahead with the template render + case ec_file:is_symlink(ToFile) of + true -> ec_file:remove(ToFile); + false -> ok + end, case file:write_file(ToFile, IoData) of ok -> - {ok, FileInfo} = file:read_file_info(FromFile), - ok = file:write_file_info(ToFile, FileInfo), + ok = ec_file:copy_file_info(ToFile, FromFile, mode, time), ok; {error, Reason} -> ?RLX_ERROR({unable_to_write, ToFile, Reason})
View file
relx-3.21.1.tar.gz/src/rlx_prv_release.erl -> relx-3.26.0.tar.gz/src/rlx_prv_release.erl
Changed
@@ -202,7 +202,7 @@ ErtsDir -> try Erts | _ = filelib:wildcard(filename:join(ErtsDir, "erts-*")), - _, ErtsVsn = string:tokens(filename:basename(Erts), "-"), + _, ErtsVsn = rlx_string:lexemes(filename:basename(Erts), "-"), {ok, rlx_state:add_realized_release(State, rlx_release:erts(Release1, ErtsVsn))} catch _:_ ->
View file
relx-3.21.1.tar.gz/src/rlx_prv_relup.erl -> relx-3.26.0.tar.gz/src/rlx_prv_relup.erl
Changed
@@ -65,6 +65,15 @@ {missing_sasl, _}}}) -> "Unfortunately, due to requirements in systools, you need to have the sasl application " "in both the current release and the release to upgrade from."; +format_error({relup_script_generation_warn, systools_relup, + {erts_vsn_changed, _}, + {erts_vsn_changed, _}}) -> + "It has been detected that the ERTS version changed while generating the relup between versions, " + "please be aware that an instruction that will automatically restart the VM will be inserted in " + "this case"; +format_error({relup_script_generation_warn, Module, Warnings}) -> + "Warnings generating relup \n", + rlx_util:indent(2), Module:format_warning(Warnings); format_error({relup_script_generation_error, Module, Errors}) -> "Errors generating relup \n", rlx_util:indent(2), Module:format_error(Errors). @@ -119,10 +128,20 @@ make_upfrom_script(State, Release, UpFrom) -> OutputDir = rlx_state:output_dir(State), + WarningsAsErrors = rlx_state:warnings_as_errors(State), Options = {outdir, OutputDir}, {path, rlx_util:get_code_paths(Release, OutputDir) ++ rlx_util:get_code_paths(UpFrom, OutputDir)}, silent, + %% the following block can be uncommented + %% when systools:make_relup/4 returns + %% {error,Module,Errors} instead of error + %% when taking the warnings_as_errors option + %% ++ + %% case WarningsAsErrors of + %% true -> warnings_as_errors; + %% false -> + % end, CurrentRel = strip_rel(rlx_release:relfile(Release)), UpFromRel = strip_rel(rlx_release:relfile(UpFrom)), ec_cmd_log:debug(rlx_state:log(State), @@ -138,14 +157,26 @@ UpFromRel, CurrentRel), {ok, State}; error -> - ?RLX_ERROR({relup_script_generation_error, CurrentRel, UpFromRel}); + ?RLX_ERROR({relup_generation_error, CurrentRel, UpFromRel}); {ok, RelUp, _, } -> write_relup_file(State, Release, RelUp), ec_cmd_log:info(rlx_state:log(State), "relup successfully created!"), {ok, State}; - {ok,_, Module,Warnings} -> - ?RLX_ERROR({relup_script_generation_warn, Module, Warnings}); + {ok, RelUp, Module,Warnings} -> + case WarningsAsErrors of + true -> + %% since we don't pass the warnings_as_errors option + %% the relup file gets generated anyway, we need to delete + %% it + file:delete(filename:join(OutputDir, "relup")), + ?RLX_ERROR({relup_script_generation_warn, Module, Warnings}); + false -> + write_relup_file(State, Release, RelUp), + ec_cmd_log:warn(rlx_state:log(State), + format_error({relup_script_generation_warn, Module, Warnings})), + {ok, State} + end; {error,Module,Errors} -> ?RLX_ERROR({relup_script_generation_error, Module, Errors}) end.
View file
relx-3.21.1.tar.gz/src/rlx_rel_discovery.erl -> relx-3.26.0.tar.gz/src/rlx_rel_discovery.erl
Changed
@@ -42,7 +42,7 @@ ec_cmd_log:info(rlx_state:log(State), fun() -> "Resolving available OTP Releases from directories:\n", - string:join(rlx_util:indent(2), LibDir || LibDir <- LibDirs, "\n") + rlx_string:join(rlx_util:indent(2), LibDir || LibDir <- LibDirs, "\n") end), resolve_rel_metadata(State, LibDirs, AppMeta) end.
View file
relx-3.21.1.tar.gz/src/rlx_release.erl -> relx-3.26.0.tar.gz/src/rlx_release.erl
Changed
@@ -39,6 +39,7 @@ realized/1, metadata/1, start_clean_metadata/1, + no_dot_erlang_metadata/1, canonical_name/1, config/1, config/2, @@ -144,7 +145,12 @@ {ok, t()}. realize(Rel, Pkgs0, World0) -> World1 = subset_world(Pkgs0, World0), - process_specs(realize_erts(Rel), World1). + case rlx_topo:sort_apps(World1) of + {ok, Pkgs1} -> + process_specs(realize_erts(Rel), Pkgs1); + Error={error, _} -> + Error + end. %% @doc this gives the application specs for the release. This can only be %% populated by the 'realize' call in this module. @@ -193,6 +199,12 @@ ?RLX_ERROR({not_realized, Name, Vsn}) end. +%% The no_dot_erlang.rel.src file is a literal copy of start_clean.rel.src +%% in Erlang/OTP itself. +-spec no_dot_erlang_metadata(t()) -> term(). +no_dot_erlang_metadata(T) -> + start_clean_metadata(T). + %% @doc produce the canonical name (<name>-<vsn>) for this release -spec canonical_name(t()) -> string(). canonical_name(#release_t{name=Name, vsn=Vsn}) -> @@ -239,6 +251,8 @@ rlx_depsolver:format_constraint(Constraint). -spec format_error(Reason::term()) -> iolist(). +format_error({topo_error, E}) -> + rlx_topo:format_error(E); format_error({failed_to_parse, Con}) -> io_lib:format("Failed to parse constraint ~p", Con); format_error({invalid_constraint, _, Con}) -> @@ -370,7 +384,7 @@ AppName -> {ok, Release#release_t{annotations=ec_dictionary:add(AppName, NewAnnots, Annots), - goals = Constraint | Goals}} + goals = Goals++Constraint}} end. -spec parse_constraint(application_constraint()) ->
View file
relx-3.21.1.tar.gz/src/rlx_state.erl -> relx-3.26.0.tar.gz/src/rlx_state.erl
Changed
@@ -54,8 +54,12 @@ hooks/2, vm_args/1, vm_args/2, + vm_args_src/1, + vm_args_src/2, sys_config/1, sys_config/2, + sys_config_src/1, + sys_config_src/2, root_dir/1, root_dir/2, add_configured_release/2, @@ -82,8 +86,11 @@ upfrom/1, upfrom/2, format/1, - format/2). - + format/2, + exclude_modules/1, + exclude_modules/2, + warnings_as_errors/1, + warnings_as_errors/2). -export_type(t/0, releases/0, @@ -103,10 +110,13 @@ available_apps= :: rlx_app_info:t(), default_configured_release :: {rlx_release:name() | undefined, rlx_release:vsn() |undefined} | undefined, vm_args :: file:filename() | false | undefined, + vm_args_src :: file:filename() | undefined, sys_config :: file:filename() | false | undefined, + sys_config_src :: file:filename() | undefined, overrides= :: {AppName::atom(), Directory::file:filename()}, skip_apps= :: AppName::atom(), exclude_apps= :: AppName::atom(), + exclude_modules= :: {App::atom(), Module::atom()}, debug_info=keep :: keep | strip, configured_releases :: releases(), realized_releases :: releases(), @@ -114,7 +124,8 @@ include_src=true :: boolean(), upfrom :: string() | binary() | undefined, config_values :: ec_dictionary:dictionary(Key::atom(), - Value::term())}). + Value::term()), + warnings_as_errors=false :: boolean()}). %%============================================================================ %% types @@ -200,6 +211,15 @@ exclude_apps(State, SkipApps) -> State#state_t{exclude_apps=SkipApps}. +-spec exclude_modules(t()) -> {App::atom(), Module::atom()}. +exclude_modules(#state_t{exclude_modules=Modules}) -> + Modules. + +%% @doc modules to be excluded from the release +-spec exclude_modules(t(), {App::atom(), Module::atom()}) -> t(). +exclude_modules(State, SkipModules) -> + State#state_t{exclude_modules=SkipModules}. + -spec debug_info(t()) -> keep | strip. debug_info(#state_t{debug_info=DebugInfo}) -> DebugInfo. @@ -270,6 +290,14 @@ vm_args(State, VmArgs) -> State#state_t{vm_args=VmArgs}. +-spec vm_args_src(t()) -> file:filename() | undefined. +vm_args_src(#state_t{vm_args_src=VmArgs}) -> + VmArgs. + +-spec vm_args_src(t(), undefined | file:filename()) -> t(). +vm_args_src(State, VmArgs) -> + State#state_t{vm_args_src=VmArgs}. + -spec sys_config(t()) -> file:filename() | false | undefined. sys_config(#state_t{sys_config=SysConfig}) -> SysConfig. @@ -278,6 +306,14 @@ sys_config(State, SysConfig) -> State#state_t{sys_config=SysConfig}. +-spec sys_config_src(t()) -> file:filename() | undefined. +sys_config_src(#state_t{sys_config_src=SysConfigSrc}) -> + SysConfigSrc. + +-spec sys_config_src(t(), file:filename() | undefined) -> t(). +sys_config_src(State, SysConfigSrc) -> + State#state_t{sys_config_src=SysConfigSrc}. + -spec root_dir(t()) -> file:filename() | undefined. root_dir(#state_t{root_dir=RootDir}) -> RootDir. @@ -442,6 +478,14 @@ Provider = providers:get_provider(Target, Providers), providers:hooks(Provider). +-spec warnings_as_errors(t()) -> boolean(). +warnings_as_errors(#state_t{warnings_as_errors=WarningsAsErrors}) -> + WarningsAsErrors. + +-spec warnings_as_errors(t(), boolean()) -> t(). +warnings_as_errors(State, WarningsAsErrors) -> + State#state_t{warnings_as_errors=WarningsAsErrors}. + %% =================================================================== %% Internal functions %% ===================================================================
View file
relx-3.26.0.tar.gz/src/rlx_string.erl
Added
@@ -0,0 +1,23 @@ +%% Compatibility module for the string API changes between +%% OTP-19 and OTP-21, where Unicode support means the deprecation +%% of a lot of string functions. +-module(rlx_string). +-export(concat/2, lexemes/2, join/2). + +-ifdef(unicode_str). +concat(Str1, Str2) -> unicode:characters_to_list(Str1,Str2). +lexemes(Str, Separators) -> string:lexemes(Str, Separators). +-else. +concat(Str1, Str2) -> string:concat(Str1, Str2). +lexemes(Str, Separators) -> string:tokens(Str, Separators). +-endif. + +%% string:join/2 copy; string:join/2 is getting obsoleted +%% and replaced by lists:join/2, but lists:join/2 is too new +%% for version support (only appeared in 19.0) so it cannot be +%% used. Instead we just adopt join/2 locally and hope it works +%% for most unicode use cases anyway. +join(, Sep) when is_list(Sep) -> + ; +join(H|T, Sep) -> + H ++ lists:append(Sep ++ X || X <- T).
View file
relx-3.26.0.tar.gz/src/rlx_topo.erl
Added
@@ -0,0 +1,190 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*- +%%% Copyright 2012 Erlware, LLC. All Rights Reserved. +%%% +%%% This file is provided to you under the Apache License, +%%% Version 2.0 (the "License"); you may not use this file +%%% except in compliance with the License. You may obtain +%%% a copy of the License at +%%% +%%% http://www.apache.org/licenses/LICENSE-2.0 +%%% +%%% Unless required by applicable law or agreed to in writing, +%%% software distributed under the License is distributed on an +%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +%%% KIND, either express or implied. See the License for the +%%% specific language governing permissions and limitations +%%% under the License. +%%%------------------------------------------------------------------- +%%% @author Joe Armstrong +%%% @author Eric Merritt +%%% @author Konstantin Tcepliaev +%%% @doc +%%% This is a pretty simple topological sort for erlang. It was +%%% originally written for ermake by Joe Armstrong back in '98. It +%%% has been pretty heavily modified by Eric Merritt since '06 and modified again for Relx. +%%% Konstantin Tcepliaev rewrote the algorithm in 2017. +%%% +%%% A partial order on the set S is a set of pairs {Xi,Xj} such that +%%% some relation between Xi and Xj is obeyed. +%%% +%%% A topological sort of a partial order is a sequence of elements +%%% X1, X2, X3 ... such that if whenever {Xi, Xj} is in the partial +%%% order i < j +%%% +%%% This particular implementation guarantees that nodes closer to +%%% the top level of the graph will be put as close as possible to +%%% the beginning of the resulting list - this ensures that dependencies +%%% are started as late as possible, and top-level apps are started +%%% as early as possible. +%%% @end +%%%------------------------------------------------------------------- +-module(rlx_topo). + +-export(sort_apps/1, + format_error/1). + +-include("relx.hrl"). + +%%==================================================================== +%% API +%%==================================================================== + +%% @doc This only does a topo sort on the list of applications and +%% assumes that there is only *one* version of each app in the list of +%% applications. This implies that you have already done the +%% constraint solve before you pass the list of apps here to be +%% sorted. +-spec sort_apps(rlx_app_info:t()) -> + {ok, rlx_app_info:t()} | + relx:error(). +sort_apps(Apps) -> + AppDeps = {rlx_app_info:name(App), + rlx_app_info:active_deps(App) ++ rlx_app_info:library_deps(App)} + || App <- Apps, + {AppNames, _} = lists:unzip(AppDeps), + case lists:foldl(fun iterator/2, {ok, , AppDeps, }, AppNames) of + {ok, Names, _, _} -> + {ok, names_to_apps(lists:reverse(Names), Apps)}; + E -> + E + end. + +%% @doc nicely format the error from the sort. +-spec format_error(Reason::term()) -> iolist(). +format_error({cycle, App, Path}) -> + "Cycle detected in dependency graph, this must be resolved " + "before we can continue:\n", + rlx_util:indent(2), + erlang:atom_to_list(A), " -> " || A <- lists:reverse(Path), + erlang:atom_to_list(App). + +%%==================================================================== +%% Internal Functions +%%==================================================================== + +-type name() :: AppName::atom(). +-type app_dep() :: {AppName::name(), DepName::name()}. +-type iterator_state() :: {ok, Acc::name(), + Apps::app_dep(), + Path::name()}. + +-spec iterator(name(), iterator_state() | relx:error()) -> + iterator_state() | relx:error(). +iterator(App, {ok, Acc, Apps, Path}) -> + case lists:member(App, Acc) of + false -> + %% haven't seen this app yet + case lists:keytake(App, 1, Apps) of + {value, {App, Deps}, NewApps} -> + DepInit = {ok, Acc, NewApps, App | Path}, + %% recurse over deps + case lists:foldl(fun iterator/2, DepInit, Deps) of + {ok, DepAcc, DepApps, _} -> + {ok, App | DepAcc, DepApps, Path}; + Error -> + Error + end; + false -> + %% we have visited this app before, + %% that means there's a cycle + ?RLX_ERROR({cycle, App, Path}) + end; + true -> + %% this app and its deps were already processed + {ok, Acc, Apps, Path} + end; +iterator(_, Error) -> + Error. + +-spec names_to_apps(atom(), rlx_app_info:t()) -> rlx_app_info:t(). +names_to_apps(Names, Apps) -> + find_app_by_name(Name, Apps) || Name <- Names. + +-spec find_app_by_name(atom(), rlx_app_info:t()) -> rlx_app_info:t(). +find_app_by_name(Name, Apps) -> + {ok, App1} = + ec_lists:find(fun(App) -> + rlx_app_info:name(App) =:= Name + end, Apps), + App1. + +%%==================================================================== +%% Tests +%%==================================================================== +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +topo_apps_cycle_test() -> + {ok, App1} = rlx_app_info:new(app1, "0.1", "/no-dir", app2, stdlib), + {ok, App2} = rlx_app_info:new(app2, "0.1", "/no-dir", app1, ), + Apps = App1, App2, + ?assertMatch({error, {_, {cycle, app1, app2, app1}}}, + sort_apps(Apps)). + +topo_apps_good_test() -> + Apps = App || + {ok, App} <- + rlx_app_info:new(app1, "0.1", "/no-dir", app2, zapp1, stdlib, kernel), + rlx_app_info:new(app2, "0.1", "/no-dir", app3, ), + rlx_app_info:new(app3, "0.1", "/no-dir", kernel, ), + rlx_app_info:new(zapp1, "0.1", "/no-dir", app2,app3,zapp2, ), + rlx_app_info:new(stdlib, "0.1", "/no-dir", , ), + rlx_app_info:new(kernel, "0.1", "/no-dir", , ), + rlx_app_info:new(zapp2, "0.1", "/no-dir", , ), + {ok, Sorted} = sort_apps(Apps), + ?assertMatch(kernel, app3, app2, zapp2, zapp1, stdlib, app1, + rlx_app_info:name(App) || App <- Sorted). + +topo_apps_1_test() -> + Apps = App || + {ok, App} <- + rlx_app_info:new(app0, "0.1", "/no-dir", , stdlib, dep1, dep2, dep3), + rlx_app_info:new(app1, "0.1", "/no-dir", , stdlib, kernel), + rlx_app_info:new(dep1, "0.1", "/no-dir", , ), + rlx_app_info:new(dep2, "0.1", "/no-dir", , ), + rlx_app_info:new(dep3, "0.1", "/no-dir", , ), + rlx_app_info:new(stdlib, "0.1", "/no-dir", , ), + rlx_app_info:new(kernel, "0.1", "/no-dir", , ), + {ok, Sorted} = sort_apps(Apps), + ?assertMatch(stdlib, dep1, dep2, dep3, app0, kernel, app1, + rlx_app_info:name(App) || App <- Sorted). + +topo_apps_2_test() -> + Apps = App || + {ok, App} <- + rlx_app_info:new(app1, "0.1", "/no-dir", app2, app3, app4, app5, + stdlib, kernel, + ), + rlx_app_info:new(app2, "0.1", "/no-dir", stdlib, kernel, ), + rlx_app_info:new(app3, "0.1", "/no-dir", stdlib, kernel, ), + rlx_app_info:new(app4, "0.1", "/no-dir", stdlib, kernel, ), + rlx_app_info:new(app5, "0.1", "/no-dir", stdlib, kernel, ), + rlx_app_info:new(stdlib, "0.1", "/no-dir", , ), + rlx_app_info:new(kernel, "0.1", "/no-dir", , ) + , + {ok, Sorted} = sort_apps(Apps), + ?assertMatch(stdlib, kernel, app2, + app3, app4, app5, app1, + rlx_app_info:name(App) || App <- Sorted). + +-endif.
View file
relx-3.21.1.tar.gz/src/rlx_util.erl -> relx-3.26.0.tar.gz/src/rlx_util.erl
Changed
@@ -41,6 +41,8 @@ intensity/0, symlink_or_copy/2). +-export(os_type/1). + -define(DFLT_INTENSITY, high). -define(ONE_LEVEL_INDENT, " "). %%============================================================================ @@ -326,6 +328,31 @@ Mode end. +os_type(State) -> + case include_erts_is_win32(State) of + true -> {win32,nt}; + false -> os:type() + end. + +include_erts_is_win32(State) -> + case rlx_state:get(State, include_erts, true) of + true -> false; + false -> false; + Path -> is_win32_erts(Path,State) + end. + +is_win32_erts(Path,State) -> + case filelib:wildcard(filename:join(Path,"bin","erl.exe")) of + -> false; + _ -> + ec_cmd_log:info(rlx_state:log(State), + "Including Erts is win32 ~n", ), + true + end. + + + + %%%=================================================================== %%% Test Functions %%%===================================================================
View file
relx-3.21.1.tar.gz/test/rlx_archive_SUITE.erl -> relx-3.26.0.tar.gz/test/rlx_archive_SUITE.erl
Changed
@@ -249,6 +249,8 @@ TestDirFull = filename:join(LibDir1, TestDir), TestFileFull = filename:join(TestDirFull, TestFile), SecondTestDir = "second_test_dir", + TestScript = "test_script", + TestScript2 = "test_script2", rlx_test_utils:write_config(ConfigFile, {overlay_vars, OverlayVars1, OverlayVars2}, {overlay, {mkdir, "{{target_dir}}/fooo"}, @@ -260,9 +262,17 @@ "{{target_dir}}/{{yahoo}}/vars.link.config"}, {copy, TestDirFull, "{{target_dir}}/"++SecondTestDir++"/"}, + {copy, TestScript, + "{{target_dir}}/"++SecondTestDir++"/"++TestScript}, + {chmod, 8#00700, + "{{target_dir}}/"++SecondTestDir++"/"++TestScript}, + {copy, TestScript2, + "{{target_dir}}/"++SecondTestDir++"/"++TestScript2}, + {chmod, "{{test_script_perm}}", + "{{target_dir}}/"++SecondTestDir++"/"++TestScript2}, {template, Template, "{{target_dir}}/test_template_resolved"}, - {template, Template, + {template, Template, "bin/{{default_release_name}}-{{default_release_version}}"}}, {release, {foo, "0.0.1"}, goal_app_1, @@ -272,7 +282,8 @@ rlx_test_utils:write_config(VarsFile1, {yahoo, "yahoo"}, {yahoo2, {foo, "bar"}}, {foo_yahoo, "foo_{{yahoo}}"}, - {foo_dir, "foodir"}), + {foo_dir, "foodir"}, + {test_script_perm,8#00770}), VarsFile2 = filename:join(LibDir1, "vars2.config"), rlx_test_utils:write_config(VarsFile2, {google, "yahoo"}, @@ -283,6 +294,11 @@ rlx_test_utils:write_config(VarsFile3, {google, "yahoo"}, {yahoo4, "{{yahoo}}/{{yahoo2}}4"}), + TestScriptFile = filename:join(LibDir1,TestScript), + ok = file:write_file(TestScriptFile, <<"#!/bin/sh\necho \"hello world\"">>), + TestScriptFile2 = filename:join(LibDir1,TestScript2), + ok = file:write_file(TestScriptFile2, <<"#!/bin/sh\necho \"hello world 2\"">>), + ok = rlx_util:mkdir_p(TestDirFull), ok = file:write_file(TestFileFull, rlx_test_utils:test_template_contents()), @@ -312,6 +328,19 @@ ?assert(lists:member({goal_app_2, "0.0.1"}, AppSpecs)), ?assert(lists:member({lib_dep_1, "0.0.1", load}, AppSpecs)), + % check that the chmod of our file worked + ChmodedFile = filename:join(OutputDir,"foo",SecondTestDir,TestScript), + {ok, ChmodedInfo} = file:read_file_info (ChmodedFile), + % mode from file_info is a bitmask which might have other bits set, but + % if we mask those we care about and check we should get true, see details + % here http://stackoverflow.com/questions/13183838/how-to-use-erlang-fileread-file-info-permissions-mode-info + ?assert(ChmodedInfo#file_info.mode band 8#00700 =:= 8#00700), + + % check that the templated chmod of our file worked + ChmodedFile2 = filename:join(OutputDir,"foo",SecondTestDir,TestScript2), + {ok, ChmodedInfo2} = file:read_file_info (ChmodedFile2), + ?assert(ChmodedInfo2#file_info.mode band 8#00770 =:= 8#00770), + TarFile = filename:join(OutputDir, "foo", "foo-0.0.1.tar.gz"), {ok, Files} = erl_tar:table(TarFile, compressed), ?assert(lists:any(fun(X) -> re:run(X, "lib/stdlib-.*/src/.*") =/= nomatch end, Files)),
View file
relx-3.21.1.tar.gz/test/rlx_depsolver_tester.erl -> relx-3.26.0.tar.gz/test/rlx_depsolver_tester.erl
Changed
@@ -406,7 +406,7 @@ process_line(Device, io:get_line(Device, ""), Acc); process_line(Device, $\s | Rest, {Pkg, Vsn, Deps} | Acc) -> - DepPackage, Type, DepVsn = string:tokens(Rest, " \n"), + DepPackage, Type, DepVsn = rlx_string:lexemes(Rest, " \n"), Dep = case Type of "=" -> @@ -417,7 +417,7 @@ process_line(Device, io:get_line(Device, ""), {Pkg, Vsn, Dep | Deps} | Acc); process_line(Device, Pkg, Acc) -> - Package, Vsn = string:tokens(Pkg, " \n"), + Package, Vsn = rlx_string:lexemes(Pkg, " \n"), process_line(Device, io:get_line(Device, ""), {Package, Vsn, } | Acc). @@ -427,7 +427,7 @@ end, rlx_depsolver:new_graph(), Pkgs). get_constraints(ConLine) -> - AppVsns = string:tokens(ConLine, " \n"), + AppVsns = rlx_string:lexemes(ConLine, " \n"), lists:map(fun(AppCon) -> parse_app(AppCon, ) end, AppVsns).
View file
relx-3.21.1.tar.gz/test/rlx_depsolver_tests.erl -> relx-3.26.0.tar.gz/test/rlx_depsolver_tests.erl
Changed
@@ -42,9 +42,9 @@ case rlx_depsolver:solve(Dom0, {app1, "0.1"}) of - {ok,{app3,{{0,3},{,}}}, + {ok,{app1,{{0,1},{,}}}, {app2,{{0,2},{,<<"build">>,33}}}, - {app1,{{0,1},{,}}}} -> + {app3,{{0,3},{,}}}} -> ok; E -> erlang:throw({invalid_result, E}) @@ -71,10 +71,10 @@ X = rlx_depsolver:solve(Dom0, {app1, "0.1"}, {app2, "0.3"}), - ?assertMatch({ok, {app3,{{0,3},{,}}}, - {app2,{{0,3},{,}}}, + ?assertMatch({ok, {app1,{{0,1},{,}}}, {app4,{{0,2},{,}}}, - {app1,{{0,1},{,}}}}, + {app2,{{0,3},{,}}}, + {app3,{{0,3},{,}}}}, X). third_test() -> @@ -107,19 +107,19 @@ {"2.0.0", }, {"6.0.0", }}), - ?assertMatch({ok, {app5,{{6,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{6,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{3,0},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{6,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{6,0,0},{,}}}}, rlx_depsolver:solve(Dom0, {app1, "3.0"})), - ?assertMatch({ok, {app5,{{6,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{6,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{3,0},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{6,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{6,0,0},{,}}}}, rlx_depsolver:solve(Dom0, app1)). fail_test() -> @@ -176,18 +176,18 @@ {"2.0.0", }, {"6.0.0", }}), - ?assertMatch({ok, {app5,{{2,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{5,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{3,0},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{5,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{2,0,0},{,}}}}, rlx_depsolver:solve(Dom0, {app1, "3.0"})), - ?assertMatch({ok, {app5,{{2,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{5,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{3,0},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{5,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{2,0,0},{,}}}}, rlx_depsolver:solve(Dom0, app1, app2, app5)). @@ -196,7 +196,7 @@ Dom0 = rlx_depsolver:add_packages(rlx_depsolver:new_graph(), {app1, {"0.1.0", app2}}, {app2, {"0.0.1", app1}}), - ?assertMatch({ok, {app1,{{0,1,0},{,}}},{app2,{{0,0,1},{,}}}}, + ?assertMatch({ok, {app2,{{0,0,1},{,}}},{app1,{{0,1,0},{,}}}}, rlx_depsolver:solve(Dom0, {app1, "0.1.0"})). conflicting_failing_test() -> @@ -217,12 +217,12 @@ Ret = rlx_depsolver:solve(Dom0, app1, app3), _ = rlx_depsolver:format_error(Ret), ?assertMatch({error, - {{app1, + {{app3, + {app3,{{0,1,0},{,}}},{app5,{{6,0,0},{,}}}}, + {app1, {app1,{{3,0},{,}}}, - {app4,{{5,0,0},{,}}}, - {app2,{{0,0,1},{,}}},{app4,{{5,0,0},{,}}}}, - {app3, - {app3,{{0,1,0},{,}}},{app5,{{6,0,0},{,}}}}, + {app2,{{0,0,1},{,}}},{app4,{{5,0,0},{,}}}, + {app4,{{5,0,0},{,}}}}, {{app4,{{5,0,0},{,}}},{app5,{{2,0,0},{,}}}}, {{app1,{{3,0},{,}}},{app5,{{2,0,0},{,}},'='}}}}, Ret). @@ -259,11 +259,11 @@ {"0.3.0", }, {"2.0.0", }, {"6.0.0", }}), - ?assertMatch({ok, {app5,{{6,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{6,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{2,1,5},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{6,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{6,0,0},{,}}}}, rlx_depsolver:solve(Dom0, {app1, "3.0"})). pessimistic_major_minor_test() -> @@ -297,11 +297,11 @@ {"0.3.0", }, {"2.0.0", }, {"6.0.0", }}), - ?assertMatch({ok, {app5,{{6,0,0},{,}}}, - {app3,{{0,1,3},{,}}}, - {app4,{{6,0,0},{,}}}, + ?assertMatch({ok, {app1,{{3,0},{,}}}, {app2,{{2,2},{,}}}, - {app1,{{3,0},{,}}}}, + {app4,{{6,0,0},{,}}}, + {app3,{{0,1,3},{,}}}, + {app5,{{6,0,0},{,}}}}, rlx_depsolver:solve(Dom0, {app1, "3.0"})). filter_versions_test() ->
View file
relx-3.21.1.tar.gz/test/rlx_eunit_SUITE.erl -> relx-3.26.0.tar.gz/test/rlx_eunit_SUITE.erl
Changed
@@ -23,7 +23,8 @@ all/0, depsolver/1, goal/1, - app_info/1). + app_info/1, + topo/1). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -38,7 +39,7 @@ ok. all() -> - depsolver, goal, app_info. + depsolver, goal, app_info, topo. depsolver(_Config) -> ok = eunit:test(rlx_depsolver). @@ -48,3 +49,6 @@ app_info(_Config) -> ok = eunit:test(rlx_app_info). + +topo(_Config) -> + ok = eunit:test(rlx_topo).
View file
relx-3.21.1.tar.gz/test/rlx_extended_bin_SUITE.erl -> relx-3.26.0.tar.gz/test/rlx_extended_bin_SUITE.erl
Changed
@@ -22,13 +22,41 @@ end_per_suite/1, init_per_testcase/2, all/0, + start_sname_in_other_argsfile/1, + start_preserves_arguments/1, + start_nodetool_with_data_from_argsfile/1, + start_upgrade_escript_with_argsfile_data/1, + start_fail_when_no_name/1, + start_fail_when_multiple_names/1, + start_fail_when_missing_argsfile/1, + start_fail_when_nonreadable_argsfile/1, + start_fail_when_relative_argsfile/1, + start_fail_when_circular_argsfiles/1, ping/1, + shortname_ping/1, + longname_ping/1, attach/1, pid/1, restart/1, reboot/1, escript/1, - remote_console/1). + remote_console/1, shortname_remote_console/1, + replace_os_vars/1, + replace_os_vars_sys_config_vm_args_src/1, + replace_os_vars_multi_node/1, + replace_os_vars_included_config/1, + replace_os_vars_custom_location/1, + replace_os_vars_dev_mode/1, + replace_os_vars_twice/1, + custom_start_script_hooks/1, + builtin_wait_for_vm_start_script_hook/1, + builtin_pid_start_script_hook/1, + builtin_wait_for_process_start_script_hook/1, + mixed_custom_and_builtin_start_script_hooks/1, + builtin_status_script/1, custom_status_script/1, + extension_script/1, + extension_script_exit_code/1, + extension_script_fail_when_no_exit/1). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -53,22 +81,111 @@ {state, State1} | Config. all() -> - ping, attach, pid, restart, reboot, escript, - remote_console. + start_sname_in_other_argsfile, start_preserves_arguments, start_nodetool_with_data_from_argsfile, + start_upgrade_escript_with_argsfile_data, start_fail_when_no_name, start_fail_when_multiple_names, + start_fail_when_missing_argsfile, start_fail_when_nonreadable_argsfile, + start_fail_when_relative_argsfile, start_fail_when_circular_argsfiles, + ping, shortname_ping, longname_ping, attach, pid, restart, reboot, escript, + remote_console, shortname_remote_console, replace_os_vars, replace_os_vars_sys_config_vm_args_src, replace_os_vars_multi_node, + replace_os_vars_included_config, + replace_os_vars_custom_location, replace_os_vars_dev_mode, replace_os_vars_twice, custom_start_script_hooks, + builtin_wait_for_vm_start_script_hook, builtin_pid_start_script_hook, + builtin_wait_for_process_start_script_hook, mixed_custom_and_builtin_start_script_hooks, + builtin_status_script, custom_status_script, + extension_script, + extension_script_exit_code, + extension_script_fail_when_no_exit. ping(Config) -> LibDir1 = proplists:get_value(lib1, Config), + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +shortname_ping(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + ec_file:write(VmArgs, "-sname foo\n\n" + "-setcookie cookie\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +longname_ping(Config) -> + LibDir1 = proplists:get_value(lib1, Config), rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + rlx_test_utils:write_config(ConfigFile, {release, {foo, "0.0.1"}, goal_app}, {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, {generate_start_script, true}, {extended_start_script, true} ), + + ec_file:write(VmArgs, "-name foo\n\n" + "-setcookie cookie\n"), OutputDir = filename:join(proplists:get_value(priv_dir, Config), rlx_test_utils:create_random_name("relx-output")), @@ -87,7 +204,7 @@ {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), %% a ping should fail after stopping a node - {error, 1} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). attach(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -121,7 +238,7 @@ {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo attach", "&")), timer:sleep(2000), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), - {error, 1} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). pid(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -154,7 +271,7 @@ {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), {ok, _Pid} = sh(filename:join(OutputDir, "foo", "bin", "foo pid")), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), - {error, 1} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). restart(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -191,7 +308,7 @@ timer:sleep(2000), {ok, Pid2} = sh(filename:join(OutputDir, "foo", "bin", "foo pid")), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), - {error, 1} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), ?assertEqual(Pid1, Pid2). reboot(Config) -> @@ -231,7 +348,7 @@ timer:sleep(2000), {ok, Pid2} = sh(filename:join(OutputDir, "foo", "bin", "foo pid")), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), - {error, 1} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), ?assertNotEqual(Pid1, Pid2). escript(Config) -> @@ -307,6 +424,1476 @@ ?assertEqual(1, length(Nodes)), {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")). +shortname_remote_console(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + ec_file:write(VmArgs, "-sname foo\n\n" + "-setcookie cookie\n"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo remote_console &")), + timer:sleep(2000), + {ok, NodesStr} = sh(filename:join(OutputDir, "foo", "bin", "foo eval 'nodes(connected).'")), + Nodes = rlx_test_utils:list_to_term(NodesStr), + ?assertEqual(1, length(Nodes)), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")). + +replace_os_vars(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + rlx_test_utils:write_config(SysConfig, + {goal_app, + {var1, "${VAR1}"}, + {var2, "${VAR2}"}}), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "v2"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"v2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, _Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + + +replace_os_vars_sys_config_vm_args_src(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfigSrc = filename:join(LibDir1, "sys.config.src"), + VmArgs = filename:join(LibDir1, "vm.args.src"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config_src, SysConfigSrc}, + {vm_args_src, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + %% new with sys.config.src it doesn't have to be valid Erlang + %% until after var replacemen at runtime. + ec_file:write(SysConfigSrc, "{goal_app, {var1, ${VAR1}}}."), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "101"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "101"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "201"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "201"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, _Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + +replace_os_vars_multi_node(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + rlx_test_utils:write_config(SysConfig, + {goal_app, {var1, "${VAR1}"}}), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys." ++ + rlx_test_utils:unescape_string(Node1) ++ + ".config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "v2"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"v2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys." ++ + rlx_test_utils:unescape_string(Node2) ++ + ".config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_MULTI_NODE", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + +replace_os_vars_included_config(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + IncludedConfig = filename:join(LibDir1, "config", "included.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true}, + {overlay, + {mkdir, "releases/{{release_version}}/config"}, + {template, "config/included.config", "releases/{{release_version}}/config/included.config"} + } + ), + + rlx_test_utils:write_config(IncludedConfig, + {goal_app, + {var1_included, "${VAR1}"} + } + ), + rlx_test_utils:write_config(SysConfig, + {goal_app, + {var1, "${VAR1}"} + }, + "releases/0.0.1/config/included.config" + ), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "v2"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"v2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, _Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + +replace_os_vars_custom_location(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + rlx_test_utils:write_config(SysConfig, + {goal_app, {var1, "${VAR1}"}}), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join("/", "tmp", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "v2"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"v2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, _Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join("/", "tmp", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"RELX_OUT_FILE_PATH", "/tmp"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + +replace_os_vars_twice(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + rlx_test_utils:write_config(SysConfig, + {goal_app, {var1, "${VAR1}"}}), + ec_file:write(VmArgs, "-sname node\n\n" + "-setcookie cookie\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}), + {ok, "\"node\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}), + {ok, "cookie"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}), + + %% start the node again but this time don't replace env variables + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, "\"${VAR1}\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'")), + {ok, "\"node\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'")), + {ok, "cookie"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + ok. + +replace_os_vars_dev_mode(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + SysConfig = filename:join(LibDir1, "sys.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {dev_mode, true}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + rlx_test_utils:write_config(SysConfig, + {goal_app, {var1, "${VAR1}"}}), + ec_file:write(VmArgs, "-sname ${NODENAME}\n\n" + "-setcookie ${COOKIE}\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}, + {"VAR1", "v1"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"v1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "\"node1\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, "cookie1"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + {ok, _Node1} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node1"}, + {"COOKIE", "cookie1"}), + + %% start the node again but this time with different env variables to replace + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}, + {"VAR1", "v2"}), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"v2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval '{ok, V} = application:get_env(goal_app, var1), V.'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "\"node2\""} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'Node,_ = re:split(atom_to_list(node()), \"@\"),binary_to_list(Node).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, "cookie2"} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'erlang:get_cookie().'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + {ok, _Node2} = sh(filename:join(OutputDir, "foo", "bin", + "foo eval 'atom_to_list(node()).'"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + %% check that the replaced files have been created in the right place + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop"), + {"RELX_REPLACE_OS_VARS", "1"}, + {"NODENAME", "node2"}, + {"COOKIE", "cookie2"}), + ok. + +custom_start_script_hooks(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {pre_start, + {custom, "hooks/pre_start"} + }, + {post_start, + {custom, "hooks/post_start"} + }, + {pre_stop, + {custom, "hooks/pre_stop"} + }, + {post_stop, + {custom, "hooks/post_stop"} + } + }, + {mkdir, "scripts"}, + {overlay, {copy, "./pre_start", "bin/hooks/pre_start"}, + {copy, "./post_start", "bin/hooks/post_start"}, + {copy, "./pre_stop", "bin/hooks/pre_stop"}, + {copy, "./post_stop", "bin/hooks/post_stop"}} + ), + + %% write the hook scripts, each of them will write an erlang term to a file + %% that will later be consulted + ok = file:write_file(filename:join(LibDir1, "./pre_start"), + "#!/bin/bash\n# $*\necho \\{pre_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./post_start"), + "#!/bin/bash\n# $*\necho \\{post_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./pre_stop"), + "#!/bin/bash\n# $*\necho \\{pre_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./post_stop"), + "#!/bin/bash\n# $*\necho \\{post_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% now check that the output file contains the expected format + {ok,{pre_start, foo, _, foo}, + {post_start, foo, _, foo}, + {pre_stop, foo, _, foo}, + {post_stop, foo, _, foo}} = file:consult(filename:join(OutputDir, "foo", "test")). + +builtin_pid_start_script_hook(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {post_start, + {pid, filename:join(OutputDir, "foo.pid")} + } + } + ), + + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + %% check that the pid file really was created + ?assert(ec_file:exists(filename:join(OutputDir, "foo.pid"))), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + ok. + +builtin_wait_for_vm_start_script_hook(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {post_start, wait_for_vm_start} + } + ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + % this run doesn't need the sleep because the wait_for_vm_start + % start script makes it unnecessary + %timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + ok. + +builtin_wait_for_process_start_script_hook(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {post_start, wait_for_vm_start, + {wait_for_process, goal_app_srv_signal}} + } + ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + %% get the current time, we'll measure how long it took for the node to + %% start, it must be at least 3 seconds which is the time it takes the + %% goal_app_srv to register the signal + T1 = os:timestamp(), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + T2 = timer:now_diff(os:timestamp(), T1), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + ?assert((T2 div 1000) > 3000), + ok. + +mixed_custom_and_builtin_start_script_hooks(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + stdlib,kernel, ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {pre_start, + {custom, "hooks/pre_start"} + }, + {post_start, + wait_for_vm_start, + {pid, filename:join(OutputDir, "foo.pid")}, + {wait_for_process, goal_app_srv_signal}, + {custom, "hooks/post_start"} + }, + {pre_stop, + {custom, "hooks/pre_stop"} + }, + {post_stop, + {custom, "hooks/post_stop"} + } + }, + {mkdir, "scripts"}, + {overlay, {copy, "./pre_start", "bin/hooks/pre_start"}, + {copy, "./post_start", "bin/hooks/post_start"}, + {copy, "./pre_stop", "bin/hooks/pre_stop"}, + {copy, "./post_stop", "bin/hooks/post_stop"}} + ), + + %% write the hook scripts, each of them will write an erlang term to a file + %% that will later be consulted + ok = file:write_file(filename:join(LibDir1, "./pre_start"), + "#!/bin/bash\n# $*\necho \\{pre_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./post_start"), + "#!/bin/bash\n# $*\necho \\{post_start, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./pre_stop"), + "#!/bin/bash\n# $*\necho \\{pre_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + ok = file:write_file(filename:join(LibDir1, "./post_stop"), + "#!/bin/bash\n# $*\necho \\{post_stop, $REL_NAME, \\'$NAME\\', $COOKIE\\}. >> test"), + + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + %% now start/stop the release to make sure the script hooks are really getting + %% executed + %% get the current time, we'll measure how long it took for the node to + %% start, it must be at least 3 seconds which is the time it takes the + %% goal_app_srv to register the signal + T1 = os:timestamp(), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + % this run doesn't need the sleep because the wait_for_vm_start + % start script makes it unnecessary + T2 = timer:now_diff(os:timestamp(), T1), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + ?assert((T2 div 1000) > 3000), + %% check that the pid file really was created + ?assert(ec_file:exists(filename:join(OutputDir, "foo.pid"))), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% now check that the output file contains the expected format + {ok,{pre_start, foo, _, foo}, + {post_start, foo, _, foo}, + {pre_stop, foo, _, foo}, + {post_stop, foo, _, foo}} = file:consult(filename:join(OutputDir, "foo", "test")). + +builtin_status_script(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + stdlib,kernel, ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + %% write the status to a file + {ok, ""} = sh(filename:join(OutputDir, "foo", "bin", "foo status")). + +custom_status_script(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + stdlib,kernel, ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_hooks, + {status, + {custom, "hooks/status"} + } + }, + {overlay, + {copy, "./status", "bin/hooks/status"}} + ), + + %% write the hook status script + ok = file:write_file(filename:join(LibDir1, "./status"), + "#!/bin/bash\n# $*\necho \\{status, $REL_NAME, \\'$NAME\\', $COOKIE\\}."), + + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + %% write the status to a file + {ok, StatusStr} = sh(filename:join(OutputDir, "foo", "bin", "foo status")), + ec_file:write(filename:join(OutputDir, "status.txt"), StatusStr), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + {ok, Status} = file:consult(filename:join(OutputDir, "status.txt")), + {ok, {status, foo, _, foo} = Status}. + +start_sname_in_other_argsfile(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + VmArgs2 = VmArgs ++ ".2", + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + ec_file:write(VmArgs, "-args_file " ++ VmArgs2 ++ "\n\n" + "-setcookie cookie\n"), + + ec_file:write(VmArgs2, "-sname foo\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +start_preserves_arguments(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + PrivDir = proplists:get_value(priv_dir, Config), + OutputDir = filename:join(PrivDir, rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + %% and preserving the "tricky" argument that contains a string with a space + %% in it + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start -goal_app baz '\"bat zing\"'")), + timer:sleep(2000), + BinFile = filename:join(PrivDir, "goal_app.bin"), + Eval = io_lib:format("{ok,Env}=application:get_env(goal_app,baz),file:write_file(\"~s\",term_to_binary(Env)).", + BinFile), + Cmd = lists:flatten(io_lib:format("foo eval '~s'", Eval)), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", Cmd)), + {ok, Bin} = file:read_file(BinFile), + "bat zing" = binary_to_term(Bin), + file:delete(BinFile), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +start_nodetool_with_data_from_argsfile(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + ec_file:write(VmArgs, "-setcookie cookie\n" + "-sname foo\n\n" + "-proto_dist inet_tcp\n\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +start_upgrade_escript_with_argsfile_data(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + VmArgs = filename:join(LibDir1, "vm.args"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app, sasl}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + ec_file:write(VmArgs, "-setcookie cookie\n" + "-sname foo\n\n" + "-proto_dist inet_tcp\n\n"), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, _Ver} = sh(filename:join(OutputDir, "foo", "bin", "foo versions")), + {ok, _} = sh(filename:join(OutputDir, "foo", "bin", "foo stop")), + %% a ping should fail after stopping a node + {error, 1, _} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")). + +start_fail_when_no_name(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + ec_file:write(VmArgs, "-setcookie cookie\n"), + start_fail_with_vmargs(Config, VmArgs, 1). + +start_fail_when_multiple_names(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + ec_file:write(VmArgs, "-name foo\n\n" + "-name bar\n\n" + "-setcookie cookie\n"), + start_fail_with_vmargs(Config, VmArgs, 2). + +start_fail_when_missing_argsfile(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + ec_file:write(VmArgs, "-name foo\n\n" + "-args_file " ++ VmArgs ++ ".nonexistent\n\n" + "-setcookie cookie\n"), + start_fail_with_vmargs(Config, VmArgs, 3). + +start_fail_when_nonreadable_argsfile(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + VmArgs2 = VmArgs ++ ".nonreadable", + ec_file:write(VmArgs, "-name foo\n\n" + "-args_file " ++ VmArgs2 ++ "\n\n" + "-setcookie cookie\n"), + ec_file:write(VmArgs2, ""), + file:change_mode(VmArgs2, 8#00333), + start_fail_with_vmargs(Config, VmArgs, 3). + +start_fail_when_relative_argsfile(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + ec_file:write(VmArgs, "-name foo\n\n" + "-args_file vm.args.relative\n\n" + "-setcookie cookie\n"), + start_fail_with_vmargs(Config, VmArgs, 4). + +start_fail_when_circular_argsfiles(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + VmArgs = filename:join(LibDir1, "vm.args"), + VmArgs2 = VmArgs ++ ".2", + VmArgs3 = VmArgs ++ ".3", + ec_file:write(VmArgs, "-name foo\n\n" + "-args_file " ++ VmArgs2 ++ "\n\n" + "-setcookie cookie\n"), + ec_file:write(VmArgs2, "-args_file " ++ VmArgs3 ++ "\n"), + ec_file:write(VmArgs3, "-args_file " ++ VmArgs2 ++ "\n"), + start_fail_with_vmargs(Config, VmArgs, 5). + +extension_script(Config) -> + ExtensionScript = + "#!/bin/bash\n" + "echo \\{bar, $REL_NAME, \\'$NAME\\', $COOKIE\\}.\n" + "exit 0", + OutputDir = setup_extension_script(proplists:get_value(lib1, Config), + proplists:get_value(priv_dir, Config), + ExtensionScript), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo start")), + timer:sleep(2000), + {ok, "pong"} = sh(filename:join(OutputDir, "foo", "bin", "foo ping")), + %% write the extension script output to a file + {ok, Str} = sh(filename:join(OutputDir, "foo", "bin", "foo bar")), + ec_file:write(filename:join(OutputDir, "bar.txt"), Str), + os:cmd(filename:join(OutputDir, "foo", "bin", "foo stop")), + {ok, Term} = file:consult(filename:join(OutputDir, "bar.txt")), + {ok, {bar, foo, _, foo} = Term}. + +extension_script_exit_code(Config) -> + ExtensionScript = + "#!/bin/bash\n" + "echo teststring\n" + "exit 42\n", + OutputDir = setup_extension_script(proplists:get_value(lib1, Config), + proplists:get_value(priv_dir, Config), + ExtensionScript), + %% check that the invocation exit code is the expected one + {error, 42, Str} = sh(filename:join(OutputDir, "foo", "bin", "foo bar")), + %% check that the extension script ran + {ok, "teststring" = Str}. + +extension_script_fail_when_no_exit(Config) -> + ExtensionScript = + "#!/bin/bash\n" + "echo teststring\n", + OutputDir = setup_extension_script(proplists:get_value(lib1, Config), + proplists:get_value(priv_dir, Config), + ExtensionScript), + %% check that the invocation exit code is non-zero + {error, 1, Str} = sh(filename:join(OutputDir, "foo", "bin", "foo bar")), + %% check that the extension script ran + {ok, "teststring" = Str}. + +%%------------------------------------------------------------------- +%% Helper Function for start_fail_when_* tests +%%------------------------------------------------------------------- +start_fail_with_vmargs(Config, VmArgs, ExpectedCode) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {vm_args, VmArgs}, + {generate_start_script, true}, + {extended_start_script, true} + ), + + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + + {ok, _State} = relx:do({relname, foo}, + {relvsn, "0.0.1"}, + {goals, }, + {lib_dirs, LibDir1}, + {log_level, 3}, + {output_dir, OutputDir}, + {config, ConfigFile}, "release"), + + %% now start/stop the release to make sure the extended script is working + {error, ExpectedCode, _} = sh(filename:join(OutputDir, "foo", "bin", "foo start")). + +%%------------------------------------------------------------------- +%% Helper Functions for extension_script* tests +%%------------------------------------------------------------------- +setup_extension_script(LibDir1, PrivDir, ExtensionScript) -> + rlx_test_utils:create_full_app(LibDir1, "goal_app", "0.0.1", + stdlib,kernel, ), + + OutputDir = filename:join(PrivDir, + rlx_test_utils:create_random_name("relx-output")), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app}, + {lib_dirs, filename:join(LibDir1, "*")}, + {generate_start_script, true}, + {extended_start_script, true}, + {extended_start_script_extensions, + {bar, "extensions/bar"} + }, + {overlay, + {copy, "./bar", "bin/extensions/bar"}} + ), + + %% write the extension script + ok = file:write_file(filename:join(LibDir1, "./bar"), + ExtensionScript), + + {ok, _State} = relx:do(foo, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + + OutputDir. + %%%=================================================================== %%% Helper Functions %%%=================================================================== @@ -327,8 +1914,8 @@ case sh_loop(Port) of {ok, Ret} -> {ok, Ret}; - {error, Rc} -> - {error, Rc} + {error, Rc, Msg} -> + {error, Rc, Msg} end. sh_loop(Port) -> @@ -341,7 +1928,7 @@ {Port, {exit_status, 0}} -> {ok, Acc}; {Port, {exit_status, Rc}} -> - {error, Rc} + {error, Rc, Acc} end. get_cwd() ->
View file
relx-3.21.1.tar.gz/test/rlx_release_SUITE.erl -> relx-3.26.0.tar.gz/test/rlx_release_SUITE.erl
Changed
@@ -46,14 +46,18 @@ make_relup_release2/1, make_one_app_top_level_release/1, make_dev_mode_release/1, + make_dev_mode_template_release/1, make_config_script_release/1, make_release_twice/1, make_release_twice_dev_mode/1, make_erts_release/1, make_erts_config_release/1, make_included_nodetool_release/1, + make_not_included_nodetool_release/1, make_src_release/1, - make_excluded_src_release/1). + make_excluded_src_release/1, + make_exclude_modules_release/1, + make_release_with_sys_config_vm_args_src/1). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -85,10 +89,12 @@ make_implicit_config_release, make_rerun_overridden_release, overlay_release, make_goalless_release, make_depfree_release, make_invalid_config_release, make_relup_release, make_relup_release2, - make_one_app_top_level_release, make_dev_mode_release, + make_one_app_top_level_release, make_dev_mode_release, make_dev_mode_template_release, make_config_script_release, make_release_twice, make_release_twice_dev_mode, - make_erts_release, make_erts_config_release, make_included_nodetool_release, - make_src_release, make_excluded_src_release. + make_erts_release, make_erts_config_release, + make_included_nodetool_release, make_not_included_nodetool_release, + make_src_release, make_excluded_src_release, make_exclude_modules_release, + make_release_with_sys_config_vm_args_src. add_providers(Config) -> LibDir1 = proplists:get_value(lib1, Config), @@ -672,7 +678,8 @@ {template, Template, "{{target_dir}}/test_template_resolved"}, {template, Template, - "bin/{{default_release_name}}-{{default_release_version}}"}}, + "bin/{{default_release_name}}-{{default_release_version}}"}, + {copy, "{{erts_dir}}/bin/erl", "bin/copy.erl"}}, {release, {foo, "0.0.1"}, goal_app_1, goal_app_2}), @@ -724,6 +731,7 @@ ?assert(ec_file:exists(filename:join(OutputDir, "foo", "foodir", "vars1.config"))), ?assert(ec_file:exists(filename:join(OutputDir, "foo", "yahoo", "vars1.config"))), ?assert(ec_file:exists(filename:join(OutputDir, "foo", SecondTestDir, TestDir, TestFile))), + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "bin", "copy.erl"))), TemplateData = case file:consult(filename:join(OutputDir, "foo", "test_template_resolved")) of {ok, Details} -> @@ -1010,9 +1018,9 @@ ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "goal_app_2-0.0.1"))), ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "lib_dep_1-0.0.1"))), ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", - "sys.config.orig"))), + "sys.config"))), ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", - "vm.args.orig"))); + "vm.args"))); {win32, _} -> ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "non_goal_1-0.0.1"))), ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "non_goal_2-0.0.1"))), @@ -1025,6 +1033,66 @@ "vm.args"))) end. +make_dev_mode_template_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", + stdlib,kernel,non_goal_1, ), + rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", + stdlib,kernel, ), + rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", + stdlib,kernel,goal_app_1,non_goal_2, ), + rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", + stdlib,kernel, lib_dep_1), + rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", + stdlib,kernel, ), + + SysConfig = filename:join(LibDir1, "config", "sys.config"), + SysConfigTerm = {this_is_a_test, "yup it is"}, + {this_is_an_overlay_var, "{{var1}}"}, + rlx_test_utils:write_config(SysConfig, SysConfigTerm), + + VmArgs = filename:join(LibDir1, "config", "vm.args"), + ec_file:write(VmArgs, "-sname {{nodename}}"), + + VarsFile1 = filename:join(LibDir1, "config", "vars1.config"), + rlx_test_utils:write_config(VarsFile1, {var1, "indeed it is"}, + {nodename, "testnode"}), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {dev_mode, true}, + {sys_config, SysConfig}, + {vm_args, VmArgs}, + {overlay_vars, VarsFile1}, + {overlay, + {template, "config/sys.config", + "releases/{{release_version}}/sys.config"}, + {template, "config/vm.args", + "releases/{{release_version}}/vm.args"}}, + {release, {foo, "0.0.1"}, + goal_app_1, + goal_app_2}), + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, State} = relx:do(undefined, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + {{foo, "0.0.1"}, _Release} = ec_dictionary:to_list(rlx_state:realized_releases(State)), + + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "non_goal_1-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "non_goal_2-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "goal_app_1-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "goal_app_2-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "lib_dep_1-0.0.1"))), + ?assert(not ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + ?assert(not ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "vm.args"))), + %% ensure that the original sys.config didn't get overwritten + ?assertMatch({ok, SysConfigTerm}, file:consult(SysConfig)), + %% ensure that the original vm.args didn't get overwritten + ?assertMatch({ok, <<"-sname {{nodename}}">>}, ec_file:read(VmArgs)). + make_config_script_release(Config) -> LibDir1 = proplists:get_value(lib1, Config), FooRoot = filename:join(LibDir1, "foodir1", "foodir2"), @@ -1246,6 +1314,36 @@ OutputDir, ConfigFile), {{foo, "0.0.1"}, Release} = ec_dictionary:to_list(rlx_state:realized_releases(State)), AppSpecs = rlx_release:applications(Release), + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "bin", "nodetool"))), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assertEqual(ErtsVsn, rlx_release:erts(Release)). + +make_not_included_nodetool_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", kernel,stdlib, ), + rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", kernel,stdlib, ), + rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", kernel,stdlib, ), + rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", kernel,stdlib, ), + rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", kernel,stdlib, ), + + ErtsVsn = erlang:system_info(version), + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, {erts, ErtsVsn}, + goal_app_1}, + {extended_start_script, true}, + {include_nodetool, false}), + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, State} = relx:do(undefined, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + {{foo, "0.0.1"}, Release} = ec_dictionary:to_list(rlx_state:realized_releases(State)), + AppSpecs = rlx_release:applications(Release), + %% extended start script needs nodetool to work, so the + %% {include_nodetool, false} option is simply ignored + ?assert(ec_file:exists(filename:join(OutputDir, "foo", "bin", "nodetool"))), ?assert(lists:keymember(stdlib, 1, AppSpecs)), ?assert(lists:keymember(kernel, 1, AppSpecs)), ?assertEqual(ErtsVsn, rlx_release:erts(Release)). @@ -1308,6 +1406,113 @@ ?assert(not ec_file:exists(filename:join(OutputDir, "foo", "lib", "goal_app_1-0.0.1", "src"))). +%% Test to ensure that excluded modules don't end up in the release +make_exclude_modules_release(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", stdlib,kernel, non_goal_1, ), + rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", stdlib,kernel, ), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {release, {foo, "0.0.1"}, + goal_app_1}, + {exclude_modules, {non_goal_1, a_real_beamnon_goal_1}}), + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, Cwd} = file:get_cwd(), + {ok, State} = relx:do(Cwd, undefined, undefined, , LibDir1, 3, + OutputDir, , + ConfigFile), + {{foo, "0.0.1"}, Release} = ec_dictionary:to_list(rlx_state:realized_releases(State)), + AppSpecs = rlx_release:applications(Release), + ?assert(lists:keymember(stdlib, 1, AppSpecs)), + ?assert(lists:keymember(kernel, 1, AppSpecs)), + ?assert(lists:member({goal_app_1, "0.0.1"}, AppSpecs)), + %% ensure that the excluded module beam file didn't get copied + ?assert(not ec_file:exists(filename:join(OutputDir, "foo", "lib", + "non_goal_1-0.0.1", "ebin", + "a_real_beamnon_goal_1.beam"))), + + ?assertMatch({ok, {application,non_goal_1, + {description,}, + {vsn,"0.0.1"}, + {modules,}, + {included_applications,}, + {registered,}, + {applications,stdlib,kernel}}}, + file:consult(filename:join(OutputDir, "foo", "lib", + "non_goal_1-0.0.1", "ebin", + "non_goal_1.app"))). + +make_release_with_sys_config_vm_args_src(Config) -> + LibDir1 = proplists:get_value(lib1, Config), + + rlx_test_utils:create_app(LibDir1, "goal_app_1", "0.0.1", stdlib,kernel,non_goal_1, ), + rlx_test_utils:create_app(LibDir1, "lib_dep_1", "0.0.1", stdlib,kernel, ), + rlx_test_utils:create_app(LibDir1, "goal_app_2", "0.0.1", stdlib,kernel,goal_app_1,non_goal_2, ), + rlx_test_utils:create_app(LibDir1, "non_goal_1", "0.0.1", stdlib,kernel, lib_dep_1), + rlx_test_utils:create_app(LibDir1, "non_goal_2", "0.0.1", stdlib,kernel, ), + + %% the .src versions should take precedence and the others are not copied + SysConfig = filename:join(LibDir1, "config", "sys.config"), + rlx_test_utils:write_config(SysConfig, {this_is_a_test, "yup it is"}), + + SysConfigSrc = filename:join(LibDir1, "config", "sys.config.src"), + rlx_test_utils:write_config(SysConfigSrc, {this_is_a_test, "yup it is"}), + + VmArgs = filename:join(LibDir1, "config", "vm.args"), + ec_file:write(VmArgs, ""), + + VmArgsSrc = filename:join(LibDir1, "config", "vm.args.src"), + ec_file:write(VmArgsSrc, ""), + + ConfigFile = filename:join(LibDir1, "relx.config"), + rlx_test_utils:write_config(ConfigFile, + {dev_mode, true}, + {sys_config_src, SysConfigSrc}, + {vm_args_src, VmArgsSrc}, + {release, {foo, "0.0.1"}, + goal_app_1, + goal_app_2}), + OutputDir = filename:join(proplists:get_value(priv_dir, Config), + rlx_test_utils:create_random_name("relx-output")), + {ok, State} = relx:do(undefined, undefined, , LibDir1, 3, + OutputDir, ConfigFile), + {{foo, "0.0.1"}, _Release} = ec_dictionary:to_list(rlx_state:realized_releases(State)), + + + case os:type() of + {unix, _} -> + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "non_goal_1-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "non_goal_2-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "goal_app_1-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "goal_app_2-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "lib", "lib_dep_1-0.0.1"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config.src"))), + ?assert(ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "vm.args.src"))), + ?assert(not ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + ?assert(not ec_file:is_symlink(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))); + {win32, _} -> + ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "non_goal_1-0.0.1"))), + ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "non_goal_2-0.0.1"))), + ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "goal_app_1-0.0.1"))), + ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "goal_app_2-0.0.1"))), + ?assert(filelib:is_dir(filename:join(OutputDir, "foo", "lib", "lib_dep_1-0.0.1"))), + ?assert(filelib:is_file(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config.src"))), + ?assert(filelib:is_file(filename:join(OutputDir, "foo", "releases", "0.0.1", + "vm.args.src"))), + ?assert(not filelib:is_file(filename:join(OutputDir, "foo", "releases", "0.0.1", + "sys.config"))), + ?assert(not filelib:is_file(filename:join(OutputDir, "foo", "releases", "0.0.1", + "vm.args"))) + end. + %%%=================================================================== %%% Helper Functions %%%===================================================================
View file
relx-3.21.1.tar.gz/test/rlx_test_utils.erl -> relx-3.26.0.tar.gz/test/rlx_test_utils.erl
Changed
@@ -6,27 +6,33 @@ create_app(Dir, Name, Vsn, Deps, LibDeps) -> AppDir = filename:join(Dir, Name ++ "-" ++ Vsn), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + write_app_file(AppDir, Name, Vsn, app_modules(Name), Deps, LibDeps), write_src_file(AppDir, Name), - write_beam_file(AppDir, Name), + compile_src_files(AppDir), + rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, + Deps, ). + +create_full_app(Dir, Name, Vsn, Deps, LibDeps) -> + AppDir = filename:join(Dir, Name ++ "-" ++ Vsn), + write_full_app_files(AppDir, Name, Vsn, Deps, LibDeps), + compile_src_files(AppDir), rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, Deps, ). create_empty_app(Dir, Name, Vsn, Deps, LibDeps) -> AppDir = filename:join(Dir, Name ++ "-" ++ Vsn), - write_app_file(AppDir, Name, Vsn, Deps, LibDeps), + write_app_file(AppDir, Name, Vsn, , Deps, LibDeps), rlx_app_info:new(erlang:list_to_atom(Name), Vsn, AppDir, Deps, ). -write_beam_file(Dir, Name) -> - Beam = filename:join(Dir, "ebin", "not_a_real_beam" ++ Name ++ ".beam"), - ok = filelib:ensure_dir(Beam), - ok = ec_file:write_term(Beam, testing_purposes_only). +app_modules(Name) -> + list_to_atom(M ++ Name) || + M <- "a_real_beam". write_src_file(Dir, Name) -> - Src = filename:join(Dir, "src", "not_a_real_beam" ++ Name ++ ".erl"), + Src = filename:join(Dir, "src", "a_real_beam" ++ Name ++ ".erl"), ok = filelib:ensure_dir(Src), - ok = ec_file:write_term(Src, testing_purposes_only). + ok = file:write_file(Src, beam_file_contents("a_real_beam"++Name)). write_appup_file(AppInfo, DownVsn) -> Dir = rlx_app_info:dir(AppInfo), @@ -36,20 +42,112 @@ ok = filelib:ensure_dir(Filename), ok = ec_file:write_term(Filename, {Vsn, {DownVsn, }, {DownVsn, }}). -write_app_file(Dir, Name, Version, Deps, LibDeps) -> +write_app_file(Dir, Name, Version, Modules, Deps, LibDeps) -> Filename = filename:join(Dir, "ebin", Name ++ ".app"), ok = filelib:ensure_dir(Filename), - ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Deps, LibDeps)). + ok = ec_file:write_term(Filename, get_app_metadata(Name, Version, Modules, + Deps, LibDeps)). -get_app_metadata(Name, Vsn, Deps, LibDeps) -> +compile_src_files(Dir) -> + %% compile all *.erl files in src to ebin + SrcDir = filename:join(Dir, "src"), + OutputDir = filename:join(Dir, "ebin"), + lists:foreach(fun(SrcFile) -> + {ok, _} = compile:file(SrcFile, {outdir, OutputDir}, + return_errors) + end, ec_file:find(SrcDir, "\\.erl")), + ok. + +get_app_metadata(Name, Vsn, Modules, Deps, LibDeps) -> {application, erlang:list_to_atom(Name), {description, ""}, {vsn, Vsn}, - {modules, }, + {modules, Modules}, {included_applications, LibDeps}, {registered, }, {applications, Deps}}. +write_full_app_files(Dir, Name, Vsn, Deps, LibDeps) -> + %% write out the .app file + AppFilename = filename:join(Dir, "ebin", Name ++ ".app"), + ok = filelib:ensure_dir(AppFilename), + ok = ec_file:write_term(AppFilename, + get_full_app_metadata(Name, Vsn, Deps, LibDeps)), + %% write out the _app.erl file + ApplicationFilename = filename:join(Dir, "src", Name ++ "_app.erl"), + ok = filelib:ensure_dir(ApplicationFilename), + ok = file:write_file(ApplicationFilename, full_application_contents(Name)), + %% write out the supervisor + SupervisorFilename = filename:join(Dir, "src", Name ++ "_sup.erl"), + ok = filelib:ensure_dir(SupervisorFilename), + ok = file:write_file(SupervisorFilename, supervisor_contents(Name)), + %% and finally the gen_server + GenServerFilename = filename:join(Dir, "src", Name ++ "_srv.erl"), + ok = filelib:ensure_dir(GenServerFilename), + ok = file:write_file(GenServerFilename, gen_server_contents(Name)), + ok. + +get_full_app_metadata(Name, Vsn, Deps, LibDeps) -> + {application, erlang:list_to_atom(Name), + {description, ""}, + {vsn, Vsn}, + {modules, goal_app_app,goal_app_sup,goal_app_srv}, + {mod, {erlang:list_to_atom(Name ++ "_app"), + }}, + {included_applications, LibDeps}, + {registered, }, + {applications, Deps}}. + +full_application_contents(Name) -> + "-module("++Name++"_app).\n" + "-behaviour(application).\n" + "-export(start/2, stop/1).\n" + "start(_StartType, _StartArgs) ->\n" + " "++Name++"_sup:start_link().\n" + "stop(_State) ->\n" + " ok.\n". + +supervisor_contents(Name) -> + "-module("++Name++"_sup).\n" + "-behaviour(supervisor).\n" + "-export(start_link/0).\n" + "-export(init/1).\n" + "-define(SERVER, ?MODULE).\n" + "start_link() ->\n" + " supervisor:start_link({local, ?SERVER}, ?MODULE, ).\n" + "init() ->\n" + " {ok, { {one_for_all, 0, 1},\n" + " {"++Name++"_srv, {"++Name++"_srv, start_link, },\n" + " transient, 5000, worker, "++Name++"_srv}\n" + " \n" + " }}.\n". + +gen_server_contents(Name) -> + "-module("++Name++"_srv).\n" + "-behaviour(gen_server).\n" + "-record(state, {}).\n" + "-export(start_link/0).\n" + "-export(init/1,handle_call/3,handle_cast/2,\n" + " handle_info/2,terminate/2,code_change/3).\n" + "start_link() ->\n" + " gen_server:start_link({local, ?MODULE}, ?MODULE, , ).\n" + "init() ->\n" + " erlang:send_after(4000, self(), register_signal)," + " {ok, #state{}}.\n" + "handle_call(_Event, _From, State) ->\n" + " {reply, ok, State}.\n" + "handle_cast(_Event, State) ->\n" + " {noreply, State}.\n" + "handle_info(register_signal, State) ->\n" + " erlang:register(goal_app_srv_signal, spawn(fun() -> timer:sleep(200000) end)),\n" + " {noreply, State};\n" + "handle_info(_Info, State) ->\n" + " {noreply, State}.\n" + "terminate(_Reason, _State) ->\n" + " ok.\n" + "code_change(_OldVsn, State, _Extra) ->\n" + " {ok, State}.\n". + create_random_name(Name) -> Name ++ erlang:integer_to_list(random_uniform(1000000)). @@ -63,6 +161,9 @@ ok = ec_file:write(Filename, io_lib:format("~p.\n", Val) || Val <- Values). +beam_file_contents(Name) -> + "-module("++Name++").". + test_template_contents() -> "{erts_vsn, \"{{erts_vsn}}\"}.\n" "{release_erts_version, \"{{release_erts_version}}\"}.\n" @@ -110,3 +211,7 @@ {error, Error} -> Error end. + +unescape_string(String) -> + re:replace(String, "\"", "", + global, {return, list}).
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.