diff --git a/plugins/override_deps_versions.erl b/plugins/override_deps_versions.erl new file mode 100644 index 000000000..d9820f711 --- /dev/null +++ b/plugins/override_deps_versions.erl @@ -0,0 +1,126 @@ +-module(override_deps_versions). +-export([preprocess/2, 'pre_update-deps'/2, new_replace/1, new_replace/0]). + +preprocess(Config, _Dirs) -> + update_deps(Config). + +update_deps(Config) -> + LocalDeps = rebar_config:get_local(Config, deps, []), + TopDeps = case rebar_config:get_xconf(Config, top_deps, []) of + [] -> LocalDeps; + Val -> Val + end, + Config2 = rebar_config:set_xconf(Config, top_deps, TopDeps), + NewDeps = lists:map(fun({Name, _, _} = Dep) -> + case lists:keyfind(Name, 1, TopDeps) of + false -> Dep; + TopDep -> TopDep + end + end, LocalDeps), + %io:format("LD ~p~n", [LocalDeps]), + %io:format("TD ~p~n", [TopDeps]), + + Config3 = rebar_config:set(Config2, deps, NewDeps), + {ok, Config3, []}. + + +'pre_update-deps'(Config, _Dirs) -> + {ok, Config2, _} = update_deps(Config), + + case code:is_loaded(old_rebar_config) of + false -> + {_, Beam, _} = code:get_object_code(rebar_config), + NBeam = rename(Beam, old_rebar_config), + code:load_binary(old_rebar_config, "blank", NBeam), + replace_mod(Beam); + _ -> + ok + end, + {ok, Config2}. + +new_replace() -> + old_rebar_config:new(). +new_replace(Config) -> + NC = old_rebar_config:new(Config), + {ok, Conf, _} = update_deps(NC), + Conf. + +replace_mod(Beam) -> + {ok, {_, [{exports, Exports}]}} = beam_lib:chunks(Beam, [exports]), + Funcs = lists:filtermap( + fun({module_info, _}) -> + false; + ({Name, Arity}) -> + Args = args(Arity), + Call = case Name of + new -> + [erl_syntax:application( + erl_syntax:abstract(override_deps_versions), + erl_syntax:abstract(new_replace), + Args)]; + _ -> + [erl_syntax:application( + erl_syntax:abstract(old_rebar_config), + erl_syntax:abstract(Name), + Args)] + end, + {true, erl_syntax:function(erl_syntax:abstract(Name), + [erl_syntax:clause(Args, none, + Call)])} + end, Exports), + Forms0 = ([erl_syntax:attribute(erl_syntax:abstract(module), + [erl_syntax:abstract(rebar_config)])] + ++ Funcs), + Forms = [erl_syntax:revert(Form) || Form <- Forms0], + %io:format("--------------------------------------------------~n" + % "~s~n", + % [[erl_pp:form(Form) || Form <- Forms]]), + {ok, Mod, Bin} = compile:forms(Forms, [report, export_all]), + code:purge(rebar_config), + {module, Mod} = code:load_binary(rebar_config, "mock", Bin). + + +args(0) -> + []; +args(N) -> + [arg(N) | args(N-1)]. + +arg(N) -> + erl_syntax:variable(list_to_atom("A"++integer_to_list(N))). + +rename(BeamBin0, Name) -> + BeamBin = replace_in_atab(BeamBin0, Name), + update_form_size(BeamBin). + +%% Replace the first atom of the atom table with the new name +replace_in_atab(<<"Atom", CnkSz0:32, Cnk:CnkSz0/binary, Rest/binary>>, Name) -> + replace_first_atom(<<"Atom">>, Cnk, CnkSz0, Rest, latin1, Name); +replace_in_atab(<<"AtU8", CnkSz0:32, Cnk:CnkSz0/binary, Rest/binary>>, Name) -> + replace_first_atom(<<"AtU8">>, Cnk, CnkSz0, Rest, unicode, Name); +replace_in_atab(<>, Name) -> + <>. + +replace_first_atom(CnkName, Cnk, CnkSz0, Rest, Encoding, Name) -> + <> = Cnk, + NumPad0 = num_pad_bytes(CnkSz0), + <<_:NumPad0/unit:8, NextCnks/binary>> = Rest, + NameBin = atom_to_binary(Name, Encoding), + NameSz = byte_size(NameBin), + CnkSz = CnkSz0 + NameSz - NameSz0, + NumPad = num_pad_bytes(CnkSz), + <>. + + +%% Calculate the number of padding bytes that have to be added for the +%% BinSize to be an even multiple of ?beam_num_bytes_alignment. +num_pad_bytes(BinSize) -> + case 4 - (BinSize rem 4) of + 4 -> 0; + N -> N + end. + +%% Update the size within the top-level form +update_form_size(<<"FOR1", _OldSz:32, Rest/binary>> = Bin) -> + Sz = size(Bin) - 8, +<<"FOR1", Sz:32, Rest/binary>>. diff --git a/rebar.config b/rebar.config index c67a86f67..e790310ac 100644 --- a/rebar.config +++ b/rebar.config @@ -102,7 +102,7 @@ {if_rebar3, {plugins, [rebar3_hex, {provider_asn1, "0.2.0"}]}}. {if_not_rebar3, {plugins, [ - deps_erl_opts, + deps_erl_opts, override_deps_versions, {if_var_true, elixir, rebar_elixir_compiler}, {if_var_true, elixir, rebar_exunit} ]}}. diff --git a/rebar.config.script b/rebar.config.script index 8cef5791a..f31ceaae2 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -342,7 +342,8 @@ Rules = [ GlobalDepsFilter, []} ], -Config = FilterConfig(FilterConfig, ProcessVars(ProcessVars, CONFIG, []), Rules), +Config = [{plugin_dir, filename:join([filename:dirname(SCRIPT),"plugins"])}]++ +FilterConfig(FilterConfig, ProcessVars(ProcessVars, CONFIG, []), Rules), %io:format("ejabberd configuration:~n ~p~n", [Config]),