From 086b785cb087e5ef20679d83b0a3082004b579f1 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sun, 25 Jul 2021 17:37:59 +0200 Subject: [PATCH] chore: delete relup_deps injection in v5, we will not rely on relup_deps to resolve app start order after upgrade --- rebar.config.erl | 8 -- scripts/inject-deps.escript | 156 ------------------------------------ 2 files changed, 164 deletions(-) delete mode 100755 scripts/inject-deps.escript diff --git a/rebar.config.erl b/rebar.config.erl index 1de92bbf2..8c5ff1019 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -146,31 +146,23 @@ prod_compile_opts() -> prod_overrides() -> [{add, [ {erl_opts, [deterministic]}]}]. -relup_deps(_Profile) -> - % {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", compile, "scripts/inject-deps.escript " ++ atom_to_list(Profile)}]}. - {post_hooks, []}. - profiles() -> Vsn = get_vsn(), [ {'emqx', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, cloud, bin)} , {overrides, prod_overrides()} - , relup_deps('emqx') ]} , {'emqx-pkg', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, cloud, pkg)} , {overrides, prod_overrides()} - , relup_deps('emqx-pkg') ]} , {'emqx-edge', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, edge, bin)} , {overrides, prod_overrides()} - , relup_deps('emqx-edge') ]} , {'emqx-edge-pkg', [ {erl_opts, prod_compile_opts()} , {relx, relx(Vsn, edge, pkg)} , {overrides, prod_overrides()} - , relup_deps('emqx-edge-pkg') ]} , {check, [ {erl_opts, common_compile_opts()} ]} diff --git a/scripts/inject-deps.escript b/scripts/inject-deps.escript deleted file mode 100755 index 8100c3959..000000000 --- a/scripts/inject-deps.escript +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env escript - -%% This script injects implicit relup dependencies for emqx applications. -%% -%% By 'implicit', it means that it is not feasible to define application -%% dependencies in .app.src files. -%% -%% For instance, during upgrade/downgrade, emqx_dashboard usually requires -%% a restart after (but not before) all plugins are upgraded (and maybe -%% restarted), however, the dependencies are not resolvable at build time -%% when relup is generated. -%% -%% This script is to be executed after compile, with the profile given as the -%% first argument. For each dependency, it modifies the .app file to -%% have the `relup_deps` list extended to application attributes. -%% -%% The `relup_deps` application attribute is then picked up by (EMQ's fork of) -%% `relx` when top-sorting apps to generate relup instructions - --mode(compile). - -usage() -> - "Usage: " ++ escript:script_name() ++ " emqx|emqx-edge". - --type app() :: atom(). --type deps_overlay() :: {re, string()} | app(). - -%% deps/0 returns the dependency overlays. -%% {re, Pattern} to match application names using regexp pattern --spec deps(string()) -> [{app(), [deps_overlay()]}]. -deps("emqx-edge" ++ _) -> - %% special case for edge - base_deps() ++ [{{re, ".+"}, [{exclude, App} || App <- edge_excludes()]}]; -deps(_Profile) -> - base_deps(). - -edge_excludes() -> - [ emqx_lwm2m - , emqx_auth_ldap - , emqx_auth_pgsql - , emqx_auth_redis - , emqx_auth_mongo - , emqx_lua_hook - , emqx_exhook - , emqx_exproto - , emqx_prometheus - ]. - -base_deps() -> - %% make sure emqx_dashboard depends on all other emqx_xxx apps - %% so the appup instructions for emqx_dashboard is always the last - %% to be executed - [ {emqx_dashboard, [{re, "emqx_.*"}]} - , {emqx_management, [{re, "emqx_.*"}, {exclude, emqx_dashboard}]} - , {{re, "emqx_.*"}, [emqx]} - ]. - -main([Profile | _]) -> - ok = inject(Profile); -main(_Args) -> - io:format(standard_error, "~s", [usage()]), - erlang:halt(1). - -expand_names({Name, Deps}, AppNames) -> - Names = match_pattern(Name, AppNames), - [{N, Deps} || N <- Names]. - -%% merge k-v pairs with v1 ++ v2 -merge([], Acc) -> Acc; -merge([{K, V0} | Rest], Acc) -> - V = case lists:keyfind(K, 1, Acc) of - {K, V1} -> V1 ++ V0; - false -> V0 - end, - NewAcc = lists:keystore(K, 1, Acc, {K, V}), - merge(Rest, NewAcc). - -expand_deps([], _AppNames, Acc) -> Acc; -expand_deps([{exclude, Dep} | Deps], AppNames, Acc) -> - Matches = expand_deps([Dep], AppNames, []), - expand_deps(Deps, AppNames, Acc -- Matches); -expand_deps([Dep | Deps], AppNames, Acc) -> - NewAcc = add_to_list(Acc, match_pattern(Dep, AppNames)), - expand_deps(Deps, AppNames, NewAcc). - -inject(Profile) -> - LibDir = lib_dir(Profile), - AppNames = list_apps(LibDir), - Deps0 = lists:flatmap(fun(Dep) -> expand_names(Dep, AppNames) end, deps(Profile)), - Deps1 = merge(Deps0, []), - Deps2 = lists:map(fun({Name, DepsX}) -> - NewDeps = expand_deps(DepsX, AppNames, []), - {Name, NewDeps} - end, Deps1), - lists:foreach(fun({App, Deps}) -> inject(App, Deps, LibDir) end, Deps2). - -%% list the profile/lib dir to get all apps -list_apps(LibDir) -> - Apps = filelib:wildcard("*", LibDir), - lists:foldl(fun(App, Acc) -> [App || is_app(LibDir, App)] ++ Acc end, [], Apps). - -is_app(_LibDir, "." ++ _) -> false; %% ignore hidden dir -is_app(LibDir, AppName) -> - Path = filename:join([ebin_dir(LibDir, AppName), AppName ++ ".app"]), - filelib:is_regular(Path) orelse error({unknown_app, AppName, Path}). %% wtf - -lib_dir(Profile) -> - filename:join(["_build", Profile, lib]). - -ebin_dir(LibDir, AppName) -> filename:join([LibDir, AppName, "ebin"]). - -inject(App0, DepsToAdd, LibDir) -> - App = str(App0), - AppEbinDir = ebin_dir(LibDir, App), - [AppFile0] = filelib:wildcard("*.app", AppEbinDir), - AppFile = filename:join(AppEbinDir, AppFile0), - {ok, [{application, AppName, Props}]} = file:consult(AppFile), - Deps0 = case lists:keyfind(relup_deps, 1, Props) of - {_, X} -> X; - false -> [] - end, - %% merge extra deps, but do not self-include - Deps = add_to_list(Deps0, DepsToAdd) -- [App0], - case Deps =:= [] of - true -> ok; - _ -> - NewProps = lists:keystore(relup_deps, 1, Props, {relup_deps, Deps}), - AppSpec = {application, AppName, NewProps}, - AppSpecIoData = io_lib:format("~p.", [AppSpec]), - io:format(user, "updated_relup_deps for ~p~n", [App]), - file:write_file(AppFile, AppSpecIoData) - end. - -str(A) when is_atom(A) -> atom_to_list(A). - -match_pattern({re, Re}, AppNames) -> - Match = fun(AppName) -> re:run(AppName, Re) =/= nomatch end, - AppNamesToAdd = lists:filter(Match, AppNames), - AppsToAdd = lists:map(fun(N) -> list_to_atom(N) end, AppNamesToAdd), - case AppsToAdd =:= [] of - true -> error({nomatch, Re}); - false -> AppsToAdd - end; -match_pattern(NameAtom, AppNames) -> - case lists:member(str(NameAtom), AppNames) of - true -> [NameAtom]; - false -> error({notfound, NameAtom}) - end. - -%% Append elements to list without duplication. No reordering. -add_to_list(List, []) -> List; -add_to_list(List, [H | T]) -> - case lists:member(H, List) of - true -> add_to_list(List, T); - false -> add_to_list(List ++ [H], T) - end.