-
Notifications
You must be signed in to change notification settings - Fork 231
/
rlx_relup.erl
107 lines (94 loc) · 4.95 KB
/
rlx_relup.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
-module(rlx_relup).
-export([do/4,
format_error/1]).
-include("relx.hrl").
-include("rlx_log.hrl").
-spec do(atom(), string(), string() | undefined, rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
do(RelName, ToVsn, undefined, State) ->
OutputDir = rlx_state:base_output_dir(State),
ReleasesDir = filename:join([OutputDir, RelName, "releases"]),
LastRelVsn = get_version_before(RelName, ToVsn, ReleasesDir),
make_upfrom_script(RelName, ToVsn, LastRelVsn, State);
do(RelName, ToVsn, UpFromVsn, State) ->
make_upfrom_script(RelName, ToVsn, UpFromVsn, State).
format_error({relfile_not_found, {Name, Vsn}}) ->
io_lib:format("Release ~p-~s not found", [Name, Vsn]);
format_error({bad_rel_tuple, Release}) ->
io_lib:format("Release format ~p not recognized. Should be of the form {Name, Vsn}.", [Release]);
format_error({relup_generation_error, CurrentName, UpFromName}) ->
io_lib:format("Unknown internal release error generating the relup from ~s to ~s",
[UpFromName, CurrentName]);
format_error({no_upfrom_release_found, undefined}) ->
io_lib:format("No earlier release for relup found", []);
format_error({no_upfrom_release_found, Vsn}) ->
io_lib:format("Upfrom release version (~s) for relup not found", [Vsn]);
format_error({relup_script_generation_error, systools_relup, {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_error, Module, Error}) ->
["Error generating relup: \n", rlx_util:indent(2), Module:format_error(Error)].
%%
make_upfrom_script(Name, ToVsn, UpFromVsn, State) ->
OutputDir = rlx_state:base_output_dir(State),
OutDir = filename:join([OutputDir, atom_to_list(Name), "releases", ToVsn]),
WarningsAsErrors = rlx_state:warnings_as_errors(State),
Options = [{outdir, OutDir},
{path, [filename:join([OutputDir, "*", "lib", "*", "ebin"])]},
{silent, true} | case WarningsAsErrors of
true -> [warnings_as_errors];
false -> []
end],
CurrentRel = strip_dot_rel(find_rel_file(Name, ToVsn, OutputDir)),
UpFromRel = strip_dot_rel(find_rel_file(Name, UpFromVsn, OutputDir)),
?log_debug("systools:make_relup(~p, ~p, ~p, ~p)", [CurrentRel, UpFromRel, UpFromRel, Options]),
case systools:make_relup(CurrentRel, [UpFromRel], [UpFromRel], [no_warn_sasl | Options]) of
ok ->
?log_info("relup from ~s to ~s successfully created!", [UpFromRel, CurrentRel]),
{ok, State};
error ->
erlang:error(?RLX_ERROR({relup_generation_error, CurrentRel, UpFromRel}));
{ok, _RelUp, _, []} ->
?log_info("relup successfully created!"),
{ok, State};
{ok, _RelUp, Module, Warnings} ->
?log_warn("Warnings generating relup:~n~s", [[Module:format_warning(W) || W <- Warnings]]),
{ok, State};
{error, Module, Error} ->
erlang:error(?RLX_ERROR({relup_script_generation_error, Module, Error}))
end.
%% return path to rel file without the .rel extension as a string (not binary)
strip_dot_rel(Name) ->
rlx_util:to_string(filename:join(filename:dirname(Name),
filename:basename(Name, ".rel"))).
find_rel_file(Name, Vsn, Dir) when is_atom(Name) ,
is_list(Vsn) ->
RelFile = filename:join([Dir, atom_to_list(Name), "releases", Vsn, atom_to_list(Name) ++ ".rel"]),
case filelib:is_regular(RelFile) of
true ->
RelFile;
_ ->
erlang:error(?RLX_ERROR({relfile_not_found, {Name, Vsn}}))
end;
find_rel_file(Name, Vsn, _) ->
erlang:error(?RLX_ERROR({bad_rel_tuple, {Name, Vsn}})).
get_version_before(Name, Vsn, ReleasesDir) ->
%% Given directory where all releases for `Name' are find all versions of the release.
%% Since the releases directory will have other files like `RELEASES', use the wildcard
%% `*/Name.rel' to find all version directories and then trim down to just the version
%% string with `filename:dirname/1'
Vsns = [begin
V = filename:dirname(R),
{rlx_util:parse_vsn(V), V}
end || R <- filelib:wildcard(filename:join("*", [Name, ".rel"]), ReleasesDir)],
%% sort all the versions
SortedVsns = lists:sort(fun vsn_lte/2, Vsns),
%% take the last element of a list that has every element up to the `Vsn' we are building
%% the relup for. This will be the most recent version of the same release found.
case lists:reverse(lists:takewhile(fun({_, X}) -> X =/= Vsn end, SortedVsns)) of
[{_, LastVersion} | _] ->
LastVersion;
_ ->
erlang:error(?RLX_ERROR({no_upfrom_release_found, Vsn}))
end.
vsn_lte({VsnA, _}, {VsnB, _}) ->
rlx_util:parsed_vsn_lte(VsnA, VsnB).