aboutsummaryrefslogtreecommitdiffstats
path: root/src/rcl_prv_overlay.erl
diff options
context:
space:
mode:
authorEric <[email protected]>2013-05-09 17:04:18 -0700
committerEric <[email protected]>2013-05-09 17:04:18 -0700
commitefbdfbe117939cd50d0252a210b9b7634de42bb4 (patch)
tree74b0bad39d3a5b25bd4199728c16c0b1a4ade703 /src/rcl_prv_overlay.erl
parent0d5a803a28010cc956948b614408b9d38997e9a1 (diff)
downloadrelx-efbdfbe117939cd50d0252a210b9b7634de42bb4.tar.gz
relx-efbdfbe117939cd50d0252a210b9b7634de42bb4.tar.bz2
relx-efbdfbe117939cd50d0252a210b9b7634de42bb4.zip
Basic file rename from rcl to rlx
Diffstat (limited to 'src/rcl_prv_overlay.erl')
-rw-r--r--src/rcl_prv_overlay.erl418
1 files changed, 0 insertions, 418 deletions
diff --git a/src/rcl_prv_overlay.erl b/src/rcl_prv_overlay.erl
deleted file mode 100644
index 35e37bf..0000000
--- a/src/rcl_prv_overlay.erl
+++ /dev/null
@@ -1,418 +0,0 @@
-%% -*- 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 Eric Merritt <[email protected]>
-%%% @copyright (C) 2012 Erlware, LLC.
-%%%
-%%% @doc Given a complete built release this provider assembles that release
-%%% into a release directory.
--module(rcl_prv_overlay).
-
--behaviour(rcl_provider).
-
--export([init/1,
- do/1,
- format_error/1]).
-
--define(DIRECTORY_RE, ".*(\/|\\\\)$").
-
--include_lib("relcool/include/relcool.hrl").
-
-%%============================================================================
-%% API
-%%============================================================================
--spec init(rcl_state:t()) -> {ok, rcl_state:t()}.
-init(State) ->
- {ok, State}.
-
-%% @doc recursively dig down into the library directories specified in the state
-%% looking for OTP Applications
--spec do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error().
-do(State) ->
- {RelName, RelVsn} = rcl_state:default_configured_release(State),
- Release = rcl_state:get_realized_release(State, RelName, RelVsn),
- case rcl_release:realized(Release) of
- true ->
- generate_overlay_vars(State, Release);
- false ->
- ?RCL_ERROR({unresolved_release, RelName, RelVsn})
- end.
-
--spec format_error(ErrorDetail::term()) -> iolist().
-format_error({unresolved_release, RelName, RelVsn}) ->
- io_lib:format("The release has not been resolved ~p-~s", [RelName, RelVsn]);
-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({unable_to_read_varsfile, FileName, Reason}) ->
- io_lib:format("Unable to read vars file (~s) for overlay due to: ~p",
- [FileName, Reason]);
-format_error({overlay_failed, Errors}) ->
- [[format_error(rcl_util:error_reason(Error)), "\n"] || Error <- Errors];
-format_error({dir_render_failed, Dir, Error}) ->
- io_lib:format("rendering mkdir path failed ~s with ~p",
- [Dir, Error]);
-format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}) ->
- io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s",
- [AppDir, TargetDir, rcl_util:indent(1),
- file:format_error(Reason)]);
-format_error({copy_failed, FromFile, ToFile, Err}) ->
- io_lib:format("Unable to copy from ~s to ~s because of ~p",
- [FromFile, ToFile, Err]);
-format_error({unable_to_write, ToFile, Reason}) ->
- io_lib:format("Unable to write to ~s because ~p",
- [ToFile, Reason]);
-format_error({unable_to_enclosing_dir, ToFile, Reason}) ->
- io_lib:format("Unable to create enclosing directory for ~s because ~p",
- [ToFile, Reason]);
-format_error({unable_to_render_template, FromFile, Reason}) ->
- io_lib:format("Unable to render template ~s because ~p",
- [FromFile, Reason]);
-format_error({unable_to_compile_template, FromFile, Reason}) ->
- io_lib:format("Unable to compile template ~s because ~p",
- [FromFile, Reason]);
-format_error({unable_to_make_dir, Absolute, Error}) ->
- io_lib:format("Unable to make directory ~s because ~p",
- [Absolute, Error]).
-
-%%%===================================================================
-%%% Internal Functions
-%%%===================================================================
--spec generate_overlay_vars(rcl_state:t(), rcl_release:t()) ->
- {ok, rcl_state:t()} | relcool:error().
-generate_overlay_vars(State, Release) ->
- StateVars = generate_state_vars(State),
- ReleaseVars = generate_release_vars(Release),
- get_overlay_vars_from_file(State, StateVars ++ ReleaseVars).
-
--spec get_overlay_vars_from_file(rcl_state:t(), proplists:proplist()) ->
- {ok, rcl_state:t()} | relcool:error().
-get_overlay_vars_from_file(State, OverlayVars) ->
- case rcl_state:get(State, overlay_vars, undefined) of
- undefined ->
- do_overlay(State, OverlayVars);
- FileName ->
- read_overlay_vars(State, OverlayVars, FileName)
- end.
-
--spec read_overlay_vars(rcl_state:t(), proplists:proplist(), file:name()) ->
- {ok, rcl_state:t()} | relcool:error().
-read_overlay_vars(State, OverlayVars, FileName) ->
- RelativeRoot = get_relative_root(State),
- RelativePath = filename:join(RelativeRoot, erlang:iolist_to_binary(FileName)),
- case file:consult(RelativePath) of
- {ok, Terms} ->
- case render_overlay_vars(OverlayVars, Terms, []) of
- {ok, NewTerms} ->
- do_overlay(State, NewTerms ++ OverlayVars);
- Error ->
- Error
- end;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_read_varsfile, FileName, Reason})
- end.
-
--spec render_overlay_vars(proplists:proplist(), proplists:proplist(),
- proplists:proplist()) ->
- {ok, proplists:proplist()} | relcool:error().
-render_overlay_vars(OverlayVars, [{Key, Value} | Rest], Acc)
- when erlang:is_list(Value) ->
- case io_lib:printable_list(Value) of
- true ->
- case render_template(Acc ++ OverlayVars, erlang:iolist_to_binary(Value)) of
- {ok, Data} ->
- %% Adding to the end sucks, but ordering needs to be retained
- render_overlay_vars(OverlayVars, Rest, Acc ++ [{Key, Data}]);
- Error ->
- Error
- end;
- false ->
- case render_overlay_vars(Acc ++ OverlayVars, Value, []) of
- {ok, NewValue} ->
- render_overlay_vars(OverlayVars, Rest, Acc ++ [{Key, NewValue}]);
- Error ->
- Error
- end
- end;
-render_overlay_vars(OverlayVars, [{Key, Value} | Rest], Acc)
- when erlang:is_binary(Value) ->
- case render_template(Acc ++ OverlayVars, erlang:iolist_to_binary(Value)) of
- {ok, Data} ->
- render_overlay_vars(OverlayVars, Rest, Acc ++ [{Key, erlang:iolist_to_binary(Data)}]);
- Error ->
- Error
- end;
-render_overlay_vars(OverlayVars, [KeyValue | Rest], Acc) ->
- render_overlay_vars(OverlayVars, Rest, Acc ++ [KeyValue]);
-render_overlay_vars(_OverlayVars, [], Acc) ->
- {ok, Acc}.
-
--spec generate_release_vars(rcl_release:t()) -> proplists:proplist().
-generate_release_vars(Release) ->
- [{erts_vsn, rcl_release:erts(Release)},
- {release_erts_version, rcl_release:erts(Release)},
- {release_name, rcl_release:name(Release)},
- {rel_vsn, rcl_release:vsn(Release)},
- {release_version, rcl_release:vsn(Release)},
- {release_applications, lists:map(fun(App) ->
- rcl_app_info:name(App)
- end, rcl_release:application_details(Release))},
- {release, [generate_app_vars(App)|| App <- rcl_release:application_details(Release)]},
- {release_goals, [if
- erlang:is_list(Constraint) ->
- Constraint;
- true ->
- rcl_depsolver:format_constraint(Constraint)
- end || Constraint <- rcl_release:goals(Release)]}].
-
--spec generate_app_vars(rcl_app_info:t()) -> AppInfo::tuple().
-generate_app_vars(App) ->
- {rcl_app_info:name(App),
- [{version, rcl_app_info:vsn_as_string(App)},
- {dir, rcl_app_info:dir(App)},
- {active_dependencies, rcl_app_info:active_deps(App)},
- {library_dependencies, rcl_app_info:library_deps(App)},
- {link, rcl_app_info:link(App)}]}.
-
--spec generate_state_vars(rcl_state:t()) -> proplists:proplist().
-generate_state_vars(State) ->
- [{log, rcl_log:format(rcl_state:log(State))},
- {output_dir, rcl_state:output_dir(State)},
- {target_dir, rcl_state:output_dir(State)},
- {overridden, [AppName || {AppName, _} <- rcl_state:overrides(State)]},
- {overrides, rcl_state:overrides(State)},
- {goals, [rcl_depsolver:format_constraint(Constraint) ||
- Constraint <- rcl_state:goals(State)]},
- {lib_dirs, rcl_state:lib_dirs(State)},
- {config_file, rcl_state:config_file(State)},
- {providers, rcl_state:providers(State)},
- {sys_config, rcl_state:sys_config(State)},
- {root_dir, rcl_state:root_dir(State)},
- {default_release_name, case rcl_state:default_configured_release(State) of
- {Name0, _} ->
- Name0
- end},
- {default_release_version, case rcl_state:default_configured_release(State) of
- {_, Vsn0} ->
- Vsn0
- end},
- {default_release, case rcl_state:default_configured_release(State) of
- {Name1, undefined} ->
- erlang:atom_to_list(Name1);
- {Name1, Vsn1} ->
- erlang:atom_to_list(Name1) ++ "-" ++ Vsn1
- end}].
-
--spec do_overlay(rcl_state:t(), proplists:proplist()) ->
- {ok, rcl_state:t()} | relcool:error().
-do_overlay(State, OverlayVars) ->
- case rcl_state:get(State, overlay, undefined) of
- undefined ->
- {ok, State};
- Overlays ->
- handle_errors(State,
- lists:map(fun(Overlay) ->
- do_individual_overlay(State, OverlayVars,
- Overlay)
- end, Overlays))
- end.
-
--spec handle_errors(rcl_state:t(), [ok | relcool:error()]) ->
- {ok, rcl_state:t()} | relcool:error().
-handle_errors(State, Result) ->
- case [Error || Error <- Result,
- rcl_util:is_error(Error)] of
- Errors = [_|_] ->
- ?RCL_ERROR({overlay_failed, Errors});
- [] ->
- {ok, State}
- end.
-
--spec do_individual_overlay(rcl_state:t(), proplists:proplist(),
- OverlayDirective::term()) ->
- {ok, rcl_state:t()} | relcool:error().
-do_individual_overlay(State, OverlayVars, {mkdir, Dir}) ->
- ModuleName = make_template_name("rcl_mkdir_template", Dir),
- case erlydtl:compile(erlang:iolist_to_binary(Dir), ModuleName) of
- {ok, ModuleName} ->
- case render(ModuleName, OverlayVars) of
- {ok, IoList} ->
- Absolute = absolutize(State,
- filename:join(rcl_state:output_dir(State),
- erlang:iolist_to_binary(IoList))),
- case rcl_util:mkdir_p(Absolute) of
- {error, Error} ->
- ?RCL_ERROR({unable_to_make_dir, Absolute, Error});
- ok ->
- ok
- end;
- {error, Error} ->
- ?RCL_ERROR({dir_render_failed, Dir, Error})
- end;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_compile_template, Dir, Reason})
- end;
-do_individual_overlay(State, OverlayVars, {copy, From, To}) ->
- FromTemplateName = make_template_name("rcl_copy_from_template", From),
- ToTemplateName = make_template_name("rcl_copy_to_template", To),
- file_render_do(OverlayVars, From, FromTemplateName,
- fun(FromFile) ->
- file_render_do(OverlayVars, To, ToTemplateName,
- fun(ToFile) ->
- copy_to(State, FromFile, ToFile)
- end)
- end);
-do_individual_overlay(State, OverlayVars, {template, From, To}) ->
- FromTemplateName = make_template_name("rcl_template_from_template", From),
- ToTemplateName = make_template_name("rcl_template_to_template", To),
- file_render_do(OverlayVars, From, FromTemplateName,
- fun(FromFile) ->
- file_render_do(OverlayVars, To, ToTemplateName,
- fun(ToFile) ->
- RelativeRoot = get_relative_root(State),
- FromFile0 = absolutize(State,
- filename:join(RelativeRoot,
- erlang:iolist_to_binary(FromFile))),
- FromFile1 = erlang:binary_to_list(FromFile0),
- write_template(OverlayVars,
- FromFile1,
- absolutize(State,
- filename:join(rcl_state:output_dir(State),
- erlang:iolist_to_binary(ToFile))))
- end)
- end).
-
--spec copy_to(rcl_state:t(), file:name(), file:name()) -> ok | relcool:error().
-copy_to(State, FromFile0, ToFile0) ->
- RelativeRoot = get_relative_root(State),
- ToFile1 = absolutize(State, filename:join(rcl_state:output_dir(State),
- erlang:iolist_to_binary(ToFile0))),
-
- FromFile1 = absolutize(State, filename:join(RelativeRoot,
- erlang:iolist_to_binary(FromFile0))),
- ToFile2 = case is_directory(ToFile0, ToFile1) of
- false ->
- filelib:ensure_dir(ToFile1),
- ToFile1;
- true ->
- rcl_util:mkdir_p(ToFile1),
- erlang:iolist_to_binary(filename:join(ToFile1,
- filename:basename(FromFile1)))
- end,
- case ec_file:copy(FromFile1, ToFile2) of
- ok ->
- {ok, FileInfo} = file:read_file_info(FromFile1),
- ok = file:write_file_info(ToFile2, FileInfo),
- ok;
- {error, Err} ->
- ?RCL_ERROR({copy_failed,
- FromFile1,
- ToFile1, Err})
- end.
-
-get_relative_root(State) ->
- case rcl_state:config_file(State) of
- [] ->
- rcl_state:root_dir(State);
- Config ->
- filename:dirname(Config)
- end.
-
--spec is_directory(file:name(), file:name()) -> boolean().
-is_directory(ToFile0, ToFile1) ->
- case re:run(ToFile0, ?DIRECTORY_RE) of
- nomatch ->
- filelib:is_dir(ToFile1);
- _ ->
- true
- end.
-
-
--spec render_template(proplists:proplist(), iolist()) ->
- ok | relcool:error().
-render_template(OverlayVars, Data) ->
- TemplateName = make_template_name("rcl_template_renderer", Data),
- case erlydtl:compile(Data, TemplateName) of
- Good when Good =:= ok; Good =:= {ok, TemplateName} ->
- case render(TemplateName, OverlayVars) of
- {ok, IoData} ->
- {ok, IoData};
- {error, Reason} ->
- ?RCL_ERROR({unable_to_render_template, Data, Reason})
- end;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_compile_template, Data, Reason})
- end.
-
-write_template(OverlayVars, FromFile, ToFile) ->
- case render_template(OverlayVars, FromFile) of
- {ok, IoData} ->
- case filelib:ensure_dir(ToFile) of
- ok ->
- case file:write_file(ToFile, IoData) of
- ok ->
- {ok, FileInfo} = file:read_file_info(FromFile),
- ok = file:write_file_info(ToFile, FileInfo),
- ok;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_write, ToFile, Reason})
- end;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_enclosing_dir, ToFile, Reason})
- end;
- Error ->
- Error
- end.
-
--spec file_render_do(proplists:proplist(), iolist(), module(),
- fun((term()) -> {ok, rcl_state:t()} | relcool:error())) ->
- {ok, rcl_state:t()} | relcool:error().
-file_render_do(OverlayVars, Data, TemplateName, NextAction) ->
- case erlydtl:compile(erlang:iolist_to_binary(Data), TemplateName) of
- {ok, TemplateName} ->
- case render(TemplateName, OverlayVars) of
- {ok, IoList} ->
- NextAction(IoList);
- {error, Error} ->
- ?RCL_ERROR({render_failed, Data, Error})
- end;
- {error, Reason} ->
- ?RCL_ERROR({unable_to_compile_template, Data, Reason})
- end.
-
--spec make_template_name(string(), term()) -> module().
-make_template_name(Base, Value) ->
- %% Seed so we get different values each time
- random:seed(erlang:now()),
- Hash = erlang:phash2(Value),
- Ran = random:uniform(10000000),
- erlang:list_to_atom(Base ++ "_" ++
- erlang:integer_to_list(Hash) ++
- "_" ++ erlang:integer_to_list(Ran)).
-
--spec render(module(), proplists:proplist()) -> {ok, iolist()} | {error, Reason::term()}.
-render(ModuleName, OverlayVars) ->
- try
- ModuleName:render(OverlayVars)
- catch
- _:Reason ->
- {error, Reason}
- end.
-
-absolutize(State, FileName) ->
- filename:absname(filename:join(rcl_state:root_dir(State),
- erlang:iolist_to_binary(FileName))).