-module(rebar3_docker_build). %%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -export([init/1]). -export([do/1]). -export([format_error/1]). %%% MACROS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(PROVIDER, docker). -define(DEPS, [app_discovery]). %%% API FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec init(rebar_state:t()) -> {ok, rebar_state:t()}. init(RState) -> Provider = providers:create([ {name, ?PROVIDER}, % The 'user friendly' name of the task {module, ?MODULE}, % The module implementation of the task {bare, true}, % The task can be run by the user, always true {deps, ?DEPS}, % The list of dependencies {example, "rebar3 docker build"}, % How to use the plugin {opts, [ % list of options understood by the plugin ]}, {short_desc, "A rebar plugin to generate docker containers"}, {desc, "A rebar plugin to generate docker containers"} ]), {ok, rebar_state:add_provider(RState, Provider)}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(RState) -> case rebar_prv_lock:do(RState) of {ok, RState2} -> Config = rebar3_docker_util:config(RState2), Params = template_parameters(RState2, Config), TemplateFile = filename:join([code:priv_dir(rebar3_docker), "templates", "Dockerfile"]), Template = bbmustache:parse_file(TemplateFile), Data = bbmustache:compile(Template, Params, [{key_type, atom}, {escape_fun, fun(X) -> X end}]), ContainerDir = rebar3_docker_util:container_dir(RState2), DataFilename = filename:join(ContainerDir, "Dockerfile"), filelib:ensure_dir(DataFilename), file:write_file(DataFilename, Data), Args = ["build", ".", "-f", DataFilename, "--progress=plain", "--tag", binary_to_list(maps:get(tag, Config))], Args2 = case os:getenv("SSH_AUTH_SOCK") of false -> Args; Value -> Args ++ ["--ssh=default=" ++ Value] end, CmdOpts = [use_stdout, abort_on_error, {cd, rebar_state:dir(RState2)}], Command = lists:flatten(lists:join(" ", ["docker" | Args2])), rebar_utils:sh(Command, CmdOpts), {ok, RState2}; Error -> Error end. -spec format_error(any()) -> iolist(). format_error(Reason) -> io_lib:format("~p", [Reason]). %%% PRIVATE FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% template_parameters(RState, Config) -> Config#{ profile => hd(rebar_state:current_profiles(RState)), env => [#{name => N, value => escape_string(V)} || {N, V} <- maps:get(env, Config)], git_url_rewrites => [#{from => F, to => T} || {F, T} <- maps:get(git_url_rewrites, Config)], ports => [#{port => Port, protocol => Proto} || {Port, Proto} <- maps:get(ports, Config)], build_packages => [#{name => N} || N <- maps:get(build_packages, Config)], runtime_packages => [#{name => N} || N <- maps:get(runtime_packages, Config)] }. escape_string(Str) when is_binary(Str) -> iolist_to_binary(io_lib:format("\"~s\"", [rebar_utils:escape_double_quotes(Str)])); escape_string(Str) when is_list(Str) -> iolist_to_binary(io_lib:format("\"~s\"", [rebar_utils:escape_double_quotes(list_to_binary(Str))])); escape_string(Other) -> Other.