Skip to content

Instantly share code, notes, and snippets.

@rambocoder
Created April 4, 2012 18:46
Show Gist options
  • Save rambocoder/2304656 to your computer and use it in GitHub Desktop.
Save rambocoder/2304656 to your computer and use it in GitHub Desktop.
Windows Support. Updated start-server.bat for ChicaboBoss skeleton, and ChicagoBoss\priv\rebar\boss_rebar.erl with windows support
%%%-------------------------------------------------------------------
%%% @author Jose Luis Gordo Romero <[email protected]>
%%% @doc Chicago Boss rebar functions, called from boss_plugin
%%% Managing compilation/configuration/scripts stuff, the boss way
%%% @end
%%%-------------------------------------------------------------------
-module(boss_rebar).
-export([run/4,
help/0,
help/3,
compile/3,
compile/4,
test_eunit/3,
test_functional/3,
start_cmd/3,
start_dev_cmd/3,
stop_cmd/3,
reload_cmd/3,
boss_config_value/3,
boss_config_value/4,
boss_load/2,
boss_start/1,
all_ebin_dirs/2,
init_conf/1,
init_conf_test/1]).
-define(COMMANDS,
[{help, "Lists all commands"},
{compile, "Compile (boss way)"},
{test_eunit, "Run src/test/eunit tests"},
{test_functional, "Run src/test/functional tests"},
{start_cmd, "Generates the start shell command"},
{start_dev_cmd, "Generates the start-dev shell command"},
{stop_cmd, "Generates the stop shell command"},
{reload_cmd, "Generates the hot reload shell command"}
]).
-define(BOSS_TEST_CONFIG, "boss.test.config").
%%--------------------------------------------------------------------
%% @doc run
%% @spec run(Command, RebarConf, BossConf, AppFile) -> ok | {error, Reason}
%% Rebar Commands Router
%% @end
%%--------------------------------------------------------------------
run(Command, RebarConf, BossConf, AppFile) when is_list(Command)->
run(list_to_atom(Command), RebarConf, BossConf, AppFile);
run(Command, RebarConf, BossConf, AppFile) ->
rebar_log:log(debug, "About to run command '~s'~n", [Command]),
case lists:keyfind(Command, 1, ?COMMANDS) of
false ->
{error, command_not_found};
_ ->
apply(boss_rebar, Command, [RebarConf, BossConf, AppFile])
end.
%%--------------------------------------------------------------------
%% @doc compile
%% @spec compile(RebarConf, BossConf, AppFile) -> ok | {error, Reason}
%% Chicago Boss compilation, handling all cb special needs
%% @end
%%--------------------------------------------------------------------
compile(RebarConf, BossConf, AppFile) ->
compile(RebarConf, BossConf, AppFile, "ebin").
%%--------------------------------------------------------------------
%% @doc compile
%% @spec compile(_RebarConf, _BossConf, AppFile, Dest) ->
%% ok | {error, Reason}
%% Chicago Boss compilation, handling all cb special needs
%% @end
%%--------------------------------------------------------------------
compile(_RebarConf, BossConf, AppFile, Dest) ->
init_conf(BossConf),
boss_load(BossConf, AppFile),
AppName = app_name(AppFile),
Res = boss_load:load_all_modules_and_emit_app_file(AppName, Dest),
rebar_log:log(info, "Chicago Boss compilation of app ~s on ~s (~s)~n",
[AppName, Dest, Res]).
%%--------------------------------------------------------------------
%% @doc test_eunit
%% @spec test_eunit(_RebarConf, _BossConf, AppFile) ->
%% ok | {error, Reason}
%% Chicago Boss eunit integration
%% @end
%%--------------------------------------------------------------------
test_eunit(RebarConf, BossConf, AppFile) ->
boss_rebar_eunit:eunit(RebarConf, BossConf, AppFile).
%%--------------------------------------------------------------------
%% @doc test_functional
%% @spec test_functional(_RebarConf, _BossConf, AppFile) ->
%% ok | {error, Reason}
%% Chicago Boss functionals test
%% API: http://www.chicagoboss.org/api-test.html
%% @end
%%--------------------------------------------------------------------
test_functional(RebarConf, BossConf, AppFile) ->
%% Compile, load all boss ebin dir and start boss
init_conf_test(BossConf),
boss_rebar:compile(RebarConf, BossConf, AppFile),
boss_rebar:boss_load(BossConf, AppFile),
boss_rebar:boss_start(BossConf),
AppName = app_name(AppFile),
boss_web_test:start([atom_to_list(AppName)]).
%%--------------------------------------------------------------------
%% @doc start_cmd
%% @spec start_cmd(RebarConf, BossConf, AppFile) ->
%% ok | {error, Reason}
%% Generate start shell command (production)
%% @end
%%--------------------------------------------------------------------
start_cmd(_RebarConf, BossConf, AppFile) ->
rebar_log:log(info, "Generating dynamic start command~n", []),
EbinDirs = all_ebin_dirs(BossConf, AppFile),
MaxProcesses = max_processes(BossConf),
SName = sname(BossConf, AppFile),
Cookie = cookie(BossConf),
io:format("exec erl +K true +P ~B -pa ~s -boot start_sasl -config boss -s boss -setcookie ~s -detached -sname ~s",
[MaxProcesses, string:join(EbinDirs, " -pa "), Cookie, SName]),
ok.
%%--------------------------------------------------------------------
%% @doc start_dev_cmd
%% @spec start_dev_cmd(RebarConf, BossConf, AppFile) ->
%% ok | {error, Reason}
%% Generate start-dev shell command (development)
%% @end
%%--------------------------------------------------------------------
start_dev_cmd(_RebarConf, BossConf, AppFile) ->
rebar_log:log(info, "Generating dynamic start-dev command~n", []),
AppName = app_name(AppFile),
SName = sname(BossConf, AppFile),
case os:type() of
false -> EbinDirs = all_ebin_dirs(BossConf, AppFile),
io:format("exec erl -pa ~s -boss developing_app ~s -boot start_sasl -config boss -s reloader -s boss -sname ~s",
[string:join(EbinDirs, " -pa "), AppName, SName]);
{win32, _ } -> EbinDirs = all_ebin_dirs(windows, BossConf, AppFile),
Dirs = io_lib:format("~p", [lists:flatten(EbinDirs)]), %EbinDirs come back as a list of lists [[],[],[]]
Cmd = io_lib:format("werl -pa ~s -boss developing_app ~s -boot start_sasl -config boss -s reloader -s boss -sname ~s", [string:join(lists:append(EbinDirs), " -pa "), AppName, SName]),
io:format("~s~n", [Cmd])
end,
ok.
%%--------------------------------------------------------------------
%% @doc stop_cmd
%% @spec stop_cmd(RebarConf, BossConf, AppFile) -> ok | {error, Reason}
%% Generate stop shell command (production)
%% @end
%%--------------------------------------------------------------------
stop_cmd(_RebarConf, BossConf, AppFile) ->
rebar_log:log(info, "Generating dynamic stop command~n", []),
SName = sname(BossConf, AppFile),
Cookie = cookie(BossConf),
StopCommand = io_lib:format("rpc:call('~s', init, stop, []).", [SName]),
io:format("erl -noshell -pa ebin -setcookie ~s -sname stopper_~s -eval \"~s\" -s init stop",
[Cookie, SName, StopCommand]),
ok.
%%--------------------------------------------------------------------
%% @doc reload_cmd
%% @spec reload_cmd(RebarConf, BossConf, AppFile) -> ok | {error, Reason}
%% Generate hot reload shell command (production)
%% @end
%%--------------------------------------------------------------------
reload_cmd(_RebarConf, BossConf, AppFile) ->
rebar_log:log(info, "Generating dynamic reload command~n", []),
SName = sname(BossConf, AppFile),
Cookie = cookie(BossConf),
ReloadCode = io_lib:format("rpc:call('~s', boss_load, reload_all, [])", [SName]),
ReloadRoutes = io_lib:format("rpc:call('~s', boss_web, reload_routes, [])", [SName]),
ReloadLangs = io_lib:format("rpc:call('~s', boss_web, reload_all_translations, [])", [SName]),
io:format("erl -noshell -pa ebin -setcookie ~s -sname reloader_~s -eval \"~s, ~s, ~s.\" -s init stop",
[Cookie, SName, ReloadCode, ReloadRoutes, ReloadLangs]),
ok.
%%--------------------------------------------------------------------
%% @doc help print known commands
%% @spec help(_RebarConf, _BossConf, _AppFile) -> Help
%% print known commands
%% @end
%%--------------------------------------------------------------------
help() -> help(true, true, true).
help(_RebarConf, _BossConf, _AppFile) ->
S = <<"
# Chicago Boss rebar commands
# ----------------------------------------------------------------------------
#
# For init commands (autogenerated) from boss.config, run:
# ./init.sh
# Compilation
compile Compile sources (compat.)
boss c=compile Compile sources (called from compile)
# Tests
eunit [suite=foo] Run src/test/eunit tests (compat.)
boss c=test_eunit [suite=foo] Run src/test/eunit tests
boss c=test_functional Run src/test/functional tests
# Help
boss Show this help
boss c=help Show this help
">>,
io:put_chars(S).
%%--------------------------------------------------------------------
%% @doc Get Boss config value app, key, default
%% @spec boss_config_value(BossConfig, App, Key, Default) ->
%% Value | Default
%% Searchs in boss config for a given App and Key,
%% Don't return an error, return Default
%% @end
%%--------------------------------------------------------------------
boss_config_value(BossConf, App, Key, Default) ->
case boss_config_value(BossConf, App, Key) of
{error, _} -> Default;
Value -> Value
end.
%%--------------------------------------------------------------------
%% @doc Get Boss config value app, key
%% @spec boss_config_value(BossConfig, App, Key) ->
%% Value | {error, Reason}
%% Searchs in boss config for a given App and Key
%% @end
%%--------------------------------------------------------------------
boss_config_value(BossConf, App, Key) ->
case lists:keyfind(App, 1, BossConf) of
false ->
{error, boss_config_app_not_found};
{App, AppConf} ->
case lists:keyfind(Key, 1, AppConf) of
false ->
{error, boss_config_app_setting_not_found};
{Key, KeyConf} ->
KeyConf
end
end.
%%--------------------------------------------------------------------
%% @doc Load all boss and app beam code
%% @spec boss_load(BossConfig)
%% @end
%%--------------------------------------------------------------------
boss_load(BossConf, AppFile) ->
%% Get all path-defined apps from boss config
%% Exclude current boss app if allready loaded
AppCurrent = app_name(AppFile),
AllDirs = lists:foldl(fun({App, Config}, Dirs) ->
case {lists:keyfind(path, 1, Config), AppCurrent =:= App} of
{false, _} ->
Dirs;
{{path, Path}, true} ->
case filelib:is_regular(filename:join(["ebin", atom_to_list(App) ++ ".app"])) of
true -> Dirs;
false -> [Path|Dirs]
end;
{{path, Path}, _} -> [Path|Dirs]
end end, [], lists:reverse(BossConf)),
lists:map(fun(Dir) ->
lists:map(fun(B) ->
F = string:substr(B, 1, string:len(B) - string:len(".beam")),
case code:is_loaded(list_to_atom(filename:basename(F))) of
false ->
code:load_abs(F);
{file, _} ->
ok
end
end, rebar_utils:beams(Dir))
end, AllDirs).
%%--------------------------------------------------------------------
%% @doc Start the boss app
%% @spec boss_start(BossConfig)
%% @end
%%--------------------------------------------------------------------
boss_start(_BossConf) ->
io:format("Starting boss and waiting all apps to initilize...~n"),
ok = boss:start(),
BossApps = boss_env:get_env(applications, []),
timer:sleep(50),
boss_start_wait(BossApps),
rebar_log:log(info, "All Boss Apps started~n", []),
ok.
%%--------------------------------------------------------------------
%% @doc Checks that all boss apps (not core) is started
%% @spec boss_start_wait(BossApps::list())
%% @end
%%--------------------------------------------------------------------
boss_start_wait([]) -> ok;
boss_start_wait([App|Rest]) ->
CurrentApps = application:which_applications(),
case lists:keyfind(App, 1, CurrentApps) of
false ->
rebar_log:log(info, "Boss App ~p still not started, waiting...~n", [App]),
timer:sleep(50),
boss_start_wait([App|Rest]);
_ ->
rebar_log:log(info, "Boss App ~p started~n", [App]),
boss_start_wait(Rest)
end.
%%--------------------------------------------------------------------
%% @doc Start the boss app
%% @spec all_ebin_dirs(BossConf, _AppFile)
%% Gets all ebin dirs for the apps defined in boss.config
%% @end
%%--------------------------------------------------------------------
all_ebin_dirs(BossConf, _AppFile) ->
lists:foldl(fun({_App, Config}, EbinDirs) ->
case lists:keyfind(path, 1, Config) of
false -> EbinDirs;
{path, Path} ->
MainEbin = filename:join([Path, "ebin"]),
filelib:ensure_dir(filename:join([MainEbin, "foobar"])),
DepsEbin = filename:join([Path, "deps", "*", "ebin"]),
[MainEbin, DepsEbin | EbinDirs]
end end, [], lists:reverse(BossConf)).
all_ebin_dirs(windows, BossConf, _AppFile) ->
lists:foldl(fun({_App, Config}, EbinDirs) ->
case lists:keyfind(path, 1, Config) of
false -> EbinDirs;
{path, Path} ->
MainEbin = filename:join([Path, "ebin"]),
filelib:ensure_dir(filename:join([MainEbin, "foobar"])),
%io:format("Path ~p~n", [Path]),
DepsEbins = case file:list_dir(Path++"/deps") of
{ok, Dirs} -> lists:map(fun(Dir) -> Path ++ "/deps/" ++ Dir ++ "/ebin" end, Dirs);
{error, _Reason} -> []
end,
%io:format("DepsEbin count: ~s~n", [lists:map(fun(Dir) -> string:concat(" -pa ", Dir) end, lists:flatten(DepsEbins))]),
[lists:append([MainEbin] , DepsEbins) | EbinDirs] % DepsEbins is a list, while MainEbin is a string
end end, [], lists:reverse(BossConf)).
%%--------------------------------------------------------------------
%% @doc Injects the boss.conf configuration to the boss application
%% @spec init_conf(BossConf)
%% @end
%%--------------------------------------------------------------------
init_conf(BossConf) ->
lists:map(fun(AppLine) ->
{App, AppConf} = AppLine,
lists:map(fun({Conf, Val}) ->
application:set_env(App, Conf, Val)
end, AppConf)
end, BossConf).
%%--------------------------------------------------------------------
%% @doc Injects the boss.test.conf configuration file if test file exists
%% @spec init_conf_test(BossConf)
%% @end
%%--------------------------------------------------------------------
init_conf_test(BossConf) ->
case file:consult(?BOSS_TEST_CONFIG) of
{error,enoent} ->
io:format("WARNING: ~p not found, using default boss.config.~n", [?BOSS_TEST_CONFIG]),
init_conf(BossConf);
{ok, [BossTestConfig]} ->
init_conf(BossTestConfig)
end.
%% ===================================================================
%% Internal functions
%% ===================================================================
app_config(AppFile) ->
{ok, AppConfig} = file:consult(AppFile),
AppConfig.
app_name(AppFile) ->
[{application, AppName, _}] = app_config(AppFile),
AppName.
host_name() ->
{ok, Host} = inet:gethostname(),
Host.
sname(BossConf, AppFile) ->
boss_config_value(BossConf, boss, vm_name, io_lib:format("~s@~s", [app_name(AppFile), host_name()])).
cookie(BossConf) ->
boss_config_value(BossConf, boss, vm_cookie, "abc123").
max_processes(BossConf) ->
boss_config_value(BossConf, boss, vm_max_processes, 32768).
@ECHO OFF
FOR /F "tokens=*" %%i in ('"rebar.cmd boss c=start_dev_cmd ^| findstr werl"') do set myvar=%%i
START "Windows Erlang" %myvar%
@ECHO OFF
@echo 1st:%1 2nd:%2 3rd:%3 4th:%4
SET PWD=%cd%
SET APPNAME=%3
for %%* in (.) do set PARENTDIR=%%~n*
IF /I "%1"=="all" CALL :all
IF /I "%1"=="app" IF /I "%2"=="project" IF [%3] NEQ [] CALL :app
:: End of main program
GOTO End
:: Sub5 subroutine starts here
:all
CALL rebar.cmd get-deps
CALL rebar.cmd compile
:: Unfortunatelly on Windows I could not get erl.exe -eval to do anything complicated
REM CALL erl.exe -pa ebin -pa deps/erlydtl/ebin -eval 'erlydtl:compile("src/boss/boss_html_error_template.dtl", boss_html_error_template, [{out_dir, "ebin"}])' -eval 'erlydtl:compile("src/boss/boss_html_doc_template.dtl", boss_html_doc_template, [{out_dir, "ebin"}])' -noshell -s init stop
:: End of Sub5 subroutine
GOTO :EOF
:clean
GOTO :EOF
:: example how to invoke: windows-make.cmd app PROJECT=awesomenamess
:app
CALL rebar.cmd create template=skel dest=../%APPNAME% src=../%PARENTDIR% appid=%APPNAME% skip_deps=true
GOTO :EOF
:End
:: End of batch file
@Kozlov-V
Copy link

Hello!
Please, tell me.
I cant dont start erlang app using start-server.bat on windows 7 x64
On command line exec "erl" and "werl" commands, system path is install for erlang.
Exec rebar.cmd and compile erl files.
But when i exec start-server.bat i have nothing, only open new comand line windows and its all...

@mariodev
Copy link

@Kozlov-V: did you figured it out already?, I have the same problem here..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment