File 0001-Rebar3-and-Thumbs-on-R16-OTP20.patch of Package cluster_info
From d12dec63294479e70823711fe61ed0dbf9db38c2 Mon Sep 17 00:00:00 2001
From: Ted Burghart <ted@tedb.net>
Date: Fri, 3 Feb 2017 18:30:03 -0500
Subject: [PATCH] Rebar3 and Thumbs on R16 - OTP20.
- Rebar2 is no longer supported.
- Made some code more efficient, and made some code lots more efficient.
- Removed ancient code.
- Even added a test!
---
.gitignore | 42 ++++++-
.thumbs.yml | 25 +++++
Makefile | 20 ----
rebar | Bin 119212 -> 0 bytes
rebar.config | 112 +++++++++++++++++--
src/cluster_info.app.src | 4 +-
src/cluster_info.erl | 222 +++++++++++++++++--------------------
src/cluster_info_basic.erl | 131 +++++++++++++++-------
tools.mk | 149 -------------------------
9 files changed, 363 insertions(+), 342 deletions(-)
create mode 100644 .thumbs.yml
delete mode 100644 Makefile
delete mode 100755 rebar
delete mode 100644 tools.mk
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 23b2645..0000000
--- a/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-.PHONY: all compile deps clean distclean
-
-all: deps compile
-
-compile:
- ./rebar compile
-
-deps:
- ./rebar get-deps
-
-clean:
- ./rebar clean
-
-distclean: clean
- ./rebar delete-deps
-
-DIALYZER_APPS = kernel stdlib sasl erts ssl tools os_mon runtime_tools crypto inets \
- xmerl webtool snmp public_key mnesia eunit syntax_tools compiler
-
-include tools.mk
diff --git a/src/cluster_info.app.src b/src/cluster_info.app.src
index 4000a3e..d4aeffe 100644
--- a/src/cluster_info.app.src
+++ b/src/cluster_info.app.src
@@ -26,8 +26,6 @@
{registered, []},
{applications, [kernel, stdlib, sasl]},
{mod, {cluster_info, []}},
- {modules, [cluster_info
- , cluster_info_ex
- ]}
+ {modules, []}
]
}.
diff --git a/src/cluster_info.erl b/src/cluster_info.erl
index c70e3a2..c488f9a 100644
--- a/src/cluster_info.erl
+++ b/src/cluster_info.erl
@@ -1,29 +1,28 @@
-%%%----------------------------------------------------------------------
-%%% Copyright: (c) 2009-2010 Gemini Mobile Technologies, Inc. All rights reserved.
-%%% Copyright: (c) 2010-2012 Basho Technologies, Inc. All rights reserved.
-%%%
-%%% Licensed 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.
-%%%
-%%% File : cluster_info.erl
-%%% Purpose : Cluster info/postmortem data gathering app
-%%%----------------------------------------------------------------------
+%% -------------------------------------------------------------------
+%%
+%% Copyright (c) 2010-2017 Basho Technologies, Inc.
+%% Copyright (c) 2009-2010 Gemini Mobile Technologies, Inc. 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.
+%%
+%% -------------------------------------------------------------------
-module(cluster_info).
-behaviour(application).
--define(DICT_KEY, '^_^--cluster_info').
-
%% application callbacks
%% Note: It is *not* necessary to start this application as a real/true OTP
%% application before you can use it. The application behavior here
@@ -47,7 +46,15 @@
-type dump_option() :: {'modules', [atom()]}.
-type dump_return() :: 'ok' | 'error'.
--type filename() :: string().
+-type filename() :: string().
+
+-type lnlimit() :: undefined | pos_integer().
+-type lnlimits() :: {lnlimit(), lnlimit()}.
+-type limitfmtfun() :: fun((iolist(), list()) -> iolist()).
+-type limitrec() :: {lnlimits(), limitfmtfun()}.
+
+%% Internal use only, maps to limitrec().
+-define(DICT_KEY, '^_^--cluster_info').
%%%----------------------------------------------------------------------
%%% Callback functions from application
@@ -112,21 +119,20 @@ dump_node(Node, Path, Opts) when is_atom(Node), is_list(Path) ->
{ok, FH} = file:open(Path, [append]),
Collector = self(),
Remote = spawn(Node, fun() ->
- dump_local_info(Collector, Opts),
- collector_done(Collector)
- end),
- {ok, MRef} = gmt_util_make_monitor(Remote),
- Res = try
- ok = collect_remote_info(Remote, FH)
- catch X:Y ->
- io:format("Error: ~P ~P at ~p\n",
- [X, 20, Y, 20, erlang:get_stacktrace()]),
- error
- after
- catch file:close(FH),
- gmt_util_unmake_monitor(MRef)
- end,
- Res.
+ dump_local_info(Collector, Opts),
+ collector_done(Collector)
+ end),
+ MRef = monitor(process, Remote),
+ try
+ ok = collect_remote_info(Remote, FH)
+ catch X:Y ->
+ io:format("Error: ~P ~P at ~p\n",
+ [X, 20, Y, 20, erlang:get_stacktrace()]),
+ error
+ after
+ demonitor(MRef, [flush]),
+ catch file:close(FH)
+ end.
%% @doc Dump the cluster_info on local node to the specified File.
-spec dump_local_node(filename()) -> [dump_return()].
@@ -156,18 +162,22 @@ dump_nodes(Nodes0, Path, Opts) ->
Nodes = lists:sort(Nodes0),
io:format("HTML report is at: ~p:~p\n", [node(), Path]),
{ok, FH} = file:open(Path, [append]),
- io:format(FH, "<!DOCTYPE html>~n<html>~n<head><meta charset=\"UTF-8\"><title>Cluster Info</title></head>~n<body>", []),
+ io:format(FH,
+ "<!DOCTYPE html>~n<html>~n<head><meta charset=\"UTF-8\">"
+ "<title>Cluster Info</title></head>~n<body>", []),
io:format(FH, "<h1>Node Reports</h1>\n", []),
io:format(FH, "<ul>\n", []),
- _ = [io:format(FH,"<li> <a href=\"#~p\">~p</a>\n", [Node, Node]) ||
- Node <- Nodes],
+ lists:foreach(fun(Node) ->
+ io:format(FH,"<li> <a href=\"#~p\">~p</a>\n", [Node, Node])
+ end, Nodes),
io:format(FH, "</ul>\n\n", []),
_ = file:close(FH),
Res = [dump_node(Node, Path, Opts) || Node <- Nodes],
{ok, FH2} = file:open(Path, [append]),
io:format(FH2, "~n</body>~n</html>~n", []),
- _ = file:close(FH), Res.
+ _ = file:close(FH),
+ Res.
list_reports() ->
list_reports("all modules, please").
@@ -320,28 +330,34 @@ harvest_reqs(Timeout) ->
[]
end.
+-spec safe_format(iolist(), list()) -> iolist().
safe_format(Fmt, Args) ->
- case get_limits() of
- {undefined, _} ->
- io_lib:format(Fmt, Args);
- {TermMaxSize, FmtMaxBytes} ->
- limited_fmt(Fmt, Args, TermMaxSize, FmtMaxBytes)
- end.
+ {_, LimitedFmt} = get_limit_record(),
+ LimitedFmt(Fmt, Args).
+%% Not sure why this is exported, but it is ...
+-spec get_limits() -> lnlimits().
get_limits() ->
+ {Limits, _} = get_limit_record(),
+ Limits.
+
+-spec get_limit_record() -> limitrec().
+get_limit_record() ->
case erlang:get(?DICT_KEY) of
undefined ->
- case code:which(lager_trunc_io) of
+ TruncIO = lager_trunc_io,
+ Rec = case code:which(TruncIO) of
non_existing ->
- {undefined, undefined};
+ {{undefined, undefined}, fun io_lib:format/2};
_ ->
- Res = {get_env(cluster_info, term_max_size, default_size()),
- get_env(cluster_info, fmt_max_bytes, default_size())},
- erlang:put(?DICT_KEY, Res),
- Res
- end;
- T when is_tuple(T) ->
- T
+ TMax = get_env(cluster_info, term_max_size, default_size()),
+ FMax = get_env(cluster_info, fmt_max_bytes, default_size()),
+ {{TMax, FMax}, limited_fmt_fun(TruncIO, TMax, FMax)}
+ end,
+ _ = erlang:put(?DICT_KEY, Rec),
+ Rec;
+ {{_, _}, _} = Val ->
+ Val
end.
get_env(App, Key, Default) ->
@@ -350,25 +366,31 @@ get_env(App, Key, Default) ->
{ok, Val} -> Val
end.
-%% @doc Format Fmt and Args similar to what io_lib:format/2 does but with
-%% limits on how large the formatted string may be.
+%% Return a function that formats Fmt and Args similar to what io_lib:format/2
+%% does but with limits on how large the formatted string may be.
%%
-%% If the Args list's size is larger than TermMaxSize, then the
-%% formatting is done by trunc_io:print/2, where FmtMaxBytes is used
-%% to limit the formatted string's size.
--spec limited_fmt(string(), list(), integer(), integer()) -> iolist().
-limited_fmt(Fmt, Args, TermMaxSize, FmtMaxBytes) ->
- TermSize = erts_debug:flat_size(Args),
- if TermSize > TermMaxSize ->
- ["Oversize args for format \"", Fmt, "\": \n",
- [
- begin
- {Str, _} = lager_trunc_io:print(lists:nth(N, Args), FmtMaxBytes),
- [" arg", integer_to_list(N), ": ", Str, "\n"]
- end || N <- lists:seq(1, length(Args))
- ]];
- true ->
- io_lib:format(Fmt, Args)
+%% If the Args list's size is larger than TermMaxSize, then the formatting is
+%% done by TruncIO:print/2, where FmtMaxBytes is used to limit the formatted
+%% string's size.
+%%
+%% TruncIO is assumed to be a module that exports print/2 that works like
+%% lager_trunc_io's.
+-spec limited_fmt_fun(module(), pos_integer(), pos_integer()) -> limitfmtfun().
+limited_fmt_fun(TruncIO, TermMaxSize, FmtMaxBytes) ->
+ fun(Fmt, Args) ->
+ % When you go looking for it, this is an undocumented API in the
+ % kernel that's been marked experimental for years.
+ case erts_debug:flat_size(Args) of
+ TermSize when TermSize > TermMaxSize ->
+ ["Oversize args for format \"", Fmt, "\": \n" | [
+ begin
+ {Str, _} = TruncIO:print(lists:nth(N, Args), FmtMaxBytes),
+ [" arg", integer_to_list(N), ": ", Str, "\n"]
+ end || N <- lists:seq(1, erlang:length(Args))
+ ]];
+ _ ->
+ io_lib:format(Fmt, Args)
+ end
end.
reset_limits() -> erlang:erase(?DICT_KEY).
@@ -376,56 +398,16 @@ reset_limits() -> erlang:erase(?DICT_KEY).
default_size() -> 256*1024.
make_anchor(Node0, Mod, Name) ->
- NameNoSp = re:replace(Name, " ", "",
- [{return, list}, global]),
+ NameNoSp = re:replace(Name, " ", "", [{return, list}, global]),
Node = re:replace(atom_to_list(Node0), "'", "", [{return, list}, global]),
- lists:flatten(io_lib:format("~s~w~s",
- [Node, Mod, NameNoSp])).
-
-%% From gmt_util.erl, also Apache Public License'd.
-
-%% @spec (server_spec()) -> {ok, monitor_ref()} | error
-%% @doc Simplify the arcane art of <tt>erlang:monitor/1</tt>:
-%% create a monitor.
-%%
-%% The arg may be a PID or a {registered_name, node} tuple.
-%% In the case of the tuple, we will use rpc:call/4 to find the
-%% server's actual PID before calling erlang:monitor();
-%% therefore there is a risk of blocking by the RPC call.
-%% To avoid the risk of blocking in this case, use make_monitor/2.
-
-gmt_util_make_monitor(Pid) when is_pid(Pid) ->
- case catch erlang:monitor(process, Pid) of
- MRef when is_reference(MRef) ->
- receive
- {'DOWN', MRef, _, _, _} ->
- error
- after 0 ->
- {ok, MRef}
- end;
- _ ->
- error
- end.
-
-%% @spec (pid()) -> {ok, monitor_ref()} | error
-%% @doc Simplify the arcane art of <tt>erlang:demonitor/1</tt>:
-%% destroy a monitor.
-
-gmt_util_unmake_monitor(MRef) ->
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- ok
- after 0 ->
- ok
- end.
+ lists:flatten(io_lib:format("~s~w~s", [Node, Mod, NameNoSp])).
send(Pid, IoData) ->
ReList = [{"&", "\\&"}, {"<", "\\<"}],
- Str = lists:foldl(fun({RE, Replace}, Str) ->
- re:replace(Str, RE, Replace, [{return,binary},
- global])
- end, IoData, ReList),
+ Str = lists:foldl(
+ fun({RE, Replace}, Data) ->
+ re:replace(Data, RE, Replace, [{return, binary}, global])
+ end, IoData, ReList),
send2(Pid, Str).
send2(Pid, IoData) ->
diff --git a/src/cluster_info_basic.erl b/src/cluster_info_basic.erl
index 26fa94a..424b27f 100644
--- a/src/cluster_info_basic.erl
+++ b/src/cluster_info_basic.erl
@@ -1,19 +1,23 @@
-%%%----------------------------------------------------------------------
-%%% Copyright: (c) 2009-2010 Gemini Mobile Technologies, Inc. All rights reserved.
-%%% Copyright: (c) 2010-2012 Basho Technologies, Inc. All rights reserved.
-%%%
-%%% Licensed 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.
-%%%----------------------------------------------------------------------
+%% -------------------------------------------------------------------
+%%
+%% Copyright (c) 2010-2017 Basho Technologies, Inc.
+%% Copyright (c) 2009-2010 Gemini Mobile Technologies, Inc. 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.
+%%
+%% -------------------------------------------------------------------
-module(cluster_info_basic).
@@ -31,6 +35,10 @@
loaded_modules/1, memory_hogs/2, non_zero_mailboxes/1, port_info/1,
registered_names/1, time_and_date/1, timer_status/1]).
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+
register() ->
cluster_info:register_app(?MODULE).
@@ -40,7 +48,7 @@ cluster_info_init() ->
cluster_info_generator_funs() ->
[
%% Short(er) output items at the top
- {"Current time and date", fun time_and_date/1},
+ {"Current time and date", time_and_date_fun()},
{"VM statistics", fun erlang_statistics/1},
{"erlang:memory() summary", fun erlang_memory/1},
{"Top 50 process memory hogs", fun(C) -> memory_hogs(C, 50) end},
@@ -212,33 +220,38 @@ registered_names(C) ->
cluster_info:format(C, " ~p\n", [L]).
time_and_date(C) ->
- case exists_new_time_api() of
+ case erlang:is_builtin(erlang, monotonic_time, 0) of
true ->
- cluster_info:format(C, " Current date : ~p\n", [date()]),
- cluster_info:format(C, " Current time : ~p\n", [time()]),
- cluster_info:format(C, " Current timestamp: ~p\n\n", [apply_without_warnings(erlang, timestamp, [])]),
- cluster_info:format(C, " erlang:system_info(os_system_time_source):\n ~p\n\n",
- [erlang:system_info(os_system_time_source)]),
- cluster_info:format(C, " erlang:system_info(os_monotonic_time_source):\n ~p\n",
- [erlang:system_info(os_monotonic_time_source)]);
- false ->
- cluster_info:format(C, " Current date: ~p\n", [date()]),
- cluster_info:format(C, " Current time: ~p\n", [time()]),
- cluster_info:format(C, " Current now : ~p\n", [apply_without_warnings(erlang, now, [])])
+ time_and_date_new(C);
+ _ ->
+ time_and_date_old(C)
end.
-exists_new_time_api() ->
- try erlang:system_info(os_monotonic_time_source) of
+time_and_date_fun() ->
+ case erlang:is_builtin(erlang, monotonic_time, 0) of
+ true ->
+ fun time_and_date_new/1;
_ ->
- true
- catch
- error:badarg ->
- false
+ fun time_and_date_old/1
end.
-% to ignore xref warnings
-apply_without_warnings(M, F, A) ->
- apply(M, F, A).
+time_and_date_old(C) ->
+ cluster_info:format(C, " Current date: ~p\n", [erlang:date()]),
+ cluster_info:format(C, " Current time: ~p\n", [erlang:time()]),
+ cluster_info:format(C, " Current now : ~p\n", [os:timestamp()]).
+
+time_and_date_new(C) ->
+ cluster_info:format(C, " Current date : ~p\n", [erlang:date()]),
+ cluster_info:format(C, " Current time : ~p\n", [erlang:time()]),
+ cluster_info:format(C, " Current timestamp: ~p\n\n", [apply0(erlang, timestamp)]),
+ cluster_info:format(C, " erlang:system_info(os_system_time_source):\n ~p\n\n",
+ [erlang:system_info(os_system_time_source)]),
+ cluster_info:format(C, " erlang:system_info(os_monotonic_time_source):\n ~p\n",
+ [erlang:system_info(os_monotonic_time_source)]).
+
+-compile({inline, apply0/2}).
+apply0(Mod, Func) ->
+ Mod:Func().
timer_status(C) ->
case catch timer:get_status() of
@@ -251,3 +264,45 @@ timer_status(C) ->
gmt_util_get_alarms() ->
alarm_handler:get_alarms().
+-ifdef(TEST).
+
+time_and_date_test_() ->
+ {timeout, 30, fun() ->
+ This = erlang:self(),
+ {Pid, Mon} = erlang:spawn_monitor(fun() -> time_and_date(This) end),
+ Res = receive_time_and_date(Pid, Mon, []),
+ ?assertMatch([_|_], Res),
+ Len = case otp_version() of
+ Vsn when Vsn >= 18 ->
+ 5;
+ _ ->
+ 3
+ end,
+ ?assertEqual(Len, erlang:length(Res))
+ end}.
+
+receive_time_and_date(Pid, Mon, Acc) ->
+ receive
+ {collect_data, Pid, IoData} ->
+ receive_time_and_date(Pid, Mon, [IoData | Acc]);
+ {collect_data_ack, Pid} ->
+ Pid ! collect_data_goahead,
+ receive_time_and_date(Pid, Mon, Acc);
+ {'DOWN', Mon, _, Pid, _} ->
+ Acc
+ after
+ 2000 ->
+ {error, {timeout, Acc}}
+ end.
+
+otp_version() ->
+ {Vsn, _} = string:to_integer(
+ case erlang:system_info(otp_release) of
+ [$R | Rel] ->
+ Rel;
+ Rel ->
+ Rel
+ end),
+ Vsn.
+
+-endif. % TEST
diff --git a/tools.mk b/tools.mk
deleted file mode 100644
index 445dd0c..0000000
--- a/tools.mk
+++ /dev/null
@@ -1,149 +0,0 @@
-# -------------------------------------------------------------------
-#
-# Copyright (c) 2014 Basho Technologies, Inc.
-#
-# 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.
-#
-# -------------------------------------------------------------------
-
-# -------------------------------------------------------------------
-# NOTE: This file is is from https://github.com/basho/tools.mk.
-# It should not be edited in a project. It should simply be updated
-# wholesale when a new version of tools.mk is released.
-# -------------------------------------------------------------------
-
-REBAR ?= ./rebar
-REVISION ?= $(shell git rev-parse --short HEAD)
-PROJECT ?= $(shell basename `find src -name "*.app.src"` .app.src)
-
-.PHONY: compile-no-deps test docs xref dialyzer-run dialyzer-quick dialyzer \
- cleanplt upload-docs
-
-compile-no-deps:
- ${REBAR} compile skip_deps=true
-
-test: compile
- ${REBAR} eunit skip_deps=true
-
-upload-docs: docs
- @if [ -z "${BUCKET}" -o -z "${PROJECT}" -o -z "${REVISION}" ]; then \
- echo "Set BUCKET, PROJECT, and REVISION env vars to upload docs"; \
- exit 1; fi
- @cd doc; s3cmd put -P * "s3://${BUCKET}/${PROJECT}/${REVISION}/" > /dev/null
- @echo "Docs built at: http://${BUCKET}.s3-website-us-east-1.amazonaws.com/${PROJECT}/${REVISION}"
-
-docs:
- ${REBAR} doc skip_deps=true
-
-xref: compile
- ${REBAR} xref skip_deps=true
-
-PLT ?= $(HOME)/.combo_dialyzer_plt
-LOCAL_PLT = .local_dialyzer_plt
-DIALYZER_FLAGS ?= -Wunmatched_returns
-
-${PLT}: compile
- @if [ -f $(PLT) ]; then \
- dialyzer --check_plt --plt $(PLT) --apps $(DIALYZER_APPS) && \
- dialyzer --add_to_plt --plt $(PLT) --output_plt $(PLT) --apps $(DIALYZER_APPS) ; test $$? -ne 1; \
- else \
- dialyzer --build_plt --output_plt $(PLT) --apps $(DIALYZER_APPS); test $$? -ne 1; \
- fi
-
-${LOCAL_PLT}: compile
- @if [ -d deps ]; then \
- if [ -f $(LOCAL_PLT) ]; then \
- dialyzer --check_plt --plt $(LOCAL_PLT) deps/*/ebin && \
- dialyzer --add_to_plt --plt $(LOCAL_PLT) --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1; \
- else \
- dialyzer --build_plt --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1; \
- fi \
- fi
-
-dialyzer-run:
- @echo "==> $(shell basename $(shell pwd)) (dialyzer)"
-# The bulk of the code below deals with the dialyzer.ignore-warnings file
-# which contains strings to ignore if output by dialyzer.
-# Typically the strings include line numbers. Using them exactly is hard
-# to maintain as the code changes. This approach instead ignores the line
-# numbers, but takes into account the number of times a string is listed
-# for a given file. So if one string is listed once, for example, and it
-# appears twice in the warnings, the user is alerted. It is possible but
-# unlikely that this approach could mask a warning if one ignored warning
-# is removed and two warnings of the same kind appear in the file, for
-# example. But it is a trade-off that seems worth it.
-# Details of the cryptic commands:
-# - Remove line numbers from dialyzer.ignore-warnings
-# - Pre-pend duplicate count to each warning with sort | uniq -c
-# - Remove annoying white space around duplicate count
-# - Save in dialyer.ignore-warnings.tmp
-# - Do the same to dialyzer_warnings
-# - Remove matches from dialyzer.ignore-warnings.tmp from output
-# - Remove duplicate count
-# - Escape regex special chars to use lines as regex patterns
-# - Add pattern to match any line number (file.erl:\d+:)
-# - Anchor to match the entire line (^entire line$)
-# - Save in dialyzer_unhandled_warnings
-# - Output matches for those patterns found in the original warnings
- @if [ -f $(LOCAL_PLT) ]; then \
- PLTS="$(PLT) $(LOCAL_PLT)"; \
- else \
- PLTS=$(PLT); \
- fi; \
- if [ -f dialyzer.ignore-warnings ]; then \
- if [ $$(grep -cvE '[^[:space:]]' dialyzer.ignore-warnings) -ne 0 ]; then \
- echo "ERROR: dialyzer.ignore-warnings contains a blank/empty line, this will match all messages!"; \
- exit 1; \
- fi; \
- dialyzer $(DIALYZER_FLAGS) --plts $${PLTS} -c ebin > dialyzer_warnings ; \
- cat dialyzer.ignore-warnings \
- | sed -E 's/^([^:]+:)[^:]+:/\1/' \
- | sort \
- | uniq -c \
- | sed -E '/.*\.erl: /!s/^[[:space:]]*[0-9]+[[:space:]]*//' \
- > dialyzer.ignore-warnings.tmp ; \
- egrep -v "^[[:space:]]*(done|Checking|Proceeding|Compiling)" dialyzer_warnings \
- | sed -E 's/^([^:]+:)[^:]+:/\1/' \
- | sort \
- | uniq -c \
- | sed -E '/.*\.erl: /!s/^[[:space:]]*[0-9]+[[:space:]]*//' \
- | grep -F -f dialyzer.ignore-warnings.tmp -v \
- | sed -E 's/^[[:space:]]*[0-9]+[[:space:]]*//' \
- | sed -E 's/([]\^:+?|()*.$${}\[])/\\\1/g' \
- | sed -E 's/(\\\.erl\\\:)/\1\\d+:/g' \
- | sed -E 's/^(.*)$$/^[[:space:]]*\1$$/g' \
- > dialyzer_unhandled_warnings ; \
- rm dialyzer.ignore-warnings.tmp; \
- if [ $$(cat dialyzer_unhandled_warnings | wc -l) -gt 0 ]; then \
- egrep -f dialyzer_unhandled_warnings dialyzer_warnings ; \
- found_warnings=1; \
- fi; \
- [ "$$found_warnings" != 1 ] ; \
- else \
- dialyzer $(DIALYZER_FLAGS) --plts $${PLTS} -c ebin; \
- fi
-
-dialyzer-quick: compile-no-deps dialyzer-run
-
-dialyzer: ${PLT} ${LOCAL_PLT} dialyzer-run
-
-cleanplt:
- @echo
- @echo "Are you sure? It takes several minutes to re-build."
- @echo Deleting $(PLT) and $(LOCAL_PLT) in 5 seconds.
- @echo
- sleep 5
- rm $(PLT)
- rm $(LOCAL_PLT)
--
2.31.1