Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Or use `-h` or `--help` option:

### Audit a single target

spectrometer audit --github https://github.com/ninenines/cowboy
spectrometer audit --github https://github.com/atomvm/atomvm_packbeam
spectrometer audit --hex jsx
spectrometer audit --hex cowboy --version 3.1.0
spectrometer audit --dir /path/to/project
Expand All @@ -150,14 +150,29 @@ Or use `-h` or `--help` option:

### Query function support

Functions can be queried by specific arity, or arity may be omitted.

spectrometer query lists:map
spectrometer query lists:map/2

#### Elixir function support

Elixir functions can be queried using several formats:

spectrometer query Elixir.List.keyfind
spectrometer query List.keyfind
spectrometer query Elixir.List.keyfind/4
spectrometer query List.keyfind/4

### List supported functions

spectrometer supported
spectrometer supported --module gen_server
spectrometer supported -m lists
spectrometer supported -m Elixir.List
spectrometer supported -m List
spectrometer supported --ex # Show only Elixir functions
spectrometer supported --erl # Show only Erlang functions

### Regenerate supported functions database

Expand Down
792 changes: 790 additions & 2 deletions priv/supported_functions.data

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions rebar.config.script
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ Version =
{api_reference, true}
]}
]},
{check, [{erl_opts, [debug_info, {i, "include"}]}, {plugins, [erlfmt]}]},
{check, [
{erl_opts, [debug_info, {i, "include"}]},
{plugins, [erlfmt, rebar3_uncovered]}
]},
{prod, [
{erl_opts, [debug_info, {i, "include"}, nowarn_sasl, {sasl, false}]}
]}
Expand Down Expand Up @@ -137,7 +140,7 @@ Version =
]}
]},
{provider_hooks, [
{pre, [{release, escriptize}]}
{pre, [{release, escriptize}, {tar, escriptize}]}
]},
{post_hooks, [
{release,
Expand Down
11 changes: 8 additions & 3 deletions release/install.in
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,14 @@ readonly tmp_dir
readonly dest_dir="${prefix}/lib/atomvm_spectrometer"
if [ -x "${prefix}/bin/spectrometer" ]; then
installed_version="$("${prefix}"/bin/spectrometer version)"
if [ "${installed_version}" = "${version}" ] && [ "${force_install}" != "true" ]; then
echo "ERROR! It looks like ${version} is already installed! Use --force to override"
exit 1
if [ "${installed_version}" = "${version}" ]; then
if [ "${force_install}" != "true" ]; then
echo "ERROR! It looks like ${version} is already installed! Use --force to override"
exit 1
else
sh "${prefix}/lib/atomvm_spectrometer/uninstall.sh" || true
rm -rf "${prefix}/lib/atomvm_spectrometer"
fi
fi
fi

Expand Down
96 changes: 18 additions & 78 deletions src/atomvm_spectrometer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -61,49 +61,49 @@ main(Args) ->
spectrometer_help:usage(Cmd),
maybe_halt(0);
{command, audit, Opts} ->
case run_analyzer_dispatch(Opts, fun run_audit/1) of
case spectrometer_analyzer:audit(Opts) of
ok ->
maybe_halt(0);
{error, Reason} ->
io:format("Audit failed, ~p.\n", [Reason]),
maybe_halt(1)
end;
{command, ecosystem, Opts} ->
case run_ecosystem(Opts) of
case spectrometer_ecosystem:run(Opts) of
ok ->
maybe_halt(0);
{error, Reason} ->
io:format("Ecosystem scanning failed, ~p.\n", [Reason]),
maybe_halt(1)
end;
{command, examine, Opts} ->
case run_analyzer_dispatch(Opts, fun run_examine/1) of
case spectrometer_analyzer:examine(Opts) of
ok ->
maybe_halt(0);
{error, Reason} ->
io:format("Examine failed, ~p.\n", [Reason]),
maybe_halt(1)
end;
{command, supported, Opts} ->
case run_supported(Opts) of
case spectrometer_atomvm:report_supported(Opts) of
ok -> maybe_halt(0);
{error, _} -> maybe_halt(1)
end;
{command, filter, Opts} ->
case run_filter(Opts) of
case spectrometer_analyzer:filter(Opts) of
ok ->
maybe_halt(0);
{error, Reason} ->
io:format("Filter failed: ~p\n", [Reason]),
maybe_halt(1)
end;
{command, update, Opts} ->
case run_update(Opts) of
case spectrometer_updater:update(Opts) of
ok -> maybe_halt(0);
{error, _} -> maybe_halt(1)
end;
{command, query, Opts} ->
case run_query(Opts) of
case spectrometer_atomvm:query(Opts) of
ok -> maybe_halt(0);
{error, _} -> maybe_halt(1)
end
Expand Down Expand Up @@ -159,7 +159,7 @@ parse_args(["audit" | Rest]) ->
parse_args(["ecosystem" | Rest]) ->
case lists:any(fun(E) -> lists:member(E, ["-h", "--help"]) end, Rest) of
false ->
case parse_ecosystem_args(Rest, default_eccopts()) of
case parse_ecosystem_args(Rest, default_eco_opts()) of
{error, Msg} -> {error, Msg};
Opts when is_map(Opts) -> {command, ecosystem, Opts}
end;
Expand Down Expand Up @@ -307,8 +307,8 @@ parse_audit_args(["--min-count", N | Rest], Opts) ->
parse_audit_args([Unknown | _], _Opts) ->
{error, "Unknown option: " ++ Unknown}.

-spec default_eccopts() -> opts_map().
default_eccopts() ->
-spec default_eco_opts() -> opts_map().
default_eco_opts() ->
#{
workers => 4,
github => true,
Expand Down Expand Up @@ -359,16 +359,20 @@ parse_supported_args([], Opts) ->
Opts;
parse_supported_args(["--module", Mod | Rest], Opts) ->
parse_supported_args(Rest, Opts#{
module => spectrometer_utils:atom_from_string(Mod)
module => spectrometer_utils:normalize_module_name(Mod)
});
parse_supported_args(["-m", Mod | Rest], Opts) ->
parse_supported_args(Rest, Opts#{
module => spectrometer_utils:atom_from_string(Mod)
module => spectrometer_utils:normalize_module_name(Mod)
});
parse_supported_args(["--cache", Dir | Rest], Opts) ->
parse_supported_args(Rest, Opts#{cache_dir => Dir});
parse_supported_args(["-c", Dir | Rest], Opts) ->
parse_supported_args(Rest, Opts#{cache_dir => Dir});
parse_supported_args(["--erl" | Rest], Opts) ->
parse_supported_args(Rest, Opts#{filter => erlang_only});
parse_supported_args(["--ex" | Rest], Opts) ->
parse_supported_args(Rest, Opts#{filter => elixir_only});
parse_supported_args([Unknown | _], _) ->
Reason = io_lib:format("unknown option ~s", [Unknown]),
{error, Reason}.
Expand Down Expand Up @@ -410,7 +414,8 @@ parse_filter_args([MaybeFile | Rest], Opts) ->
parse_query_args([], #{query := _Q} = Opts) ->
Opts;
parse_query_args([], _) ->
{error, "No function specified. Usage: query Module:Function[/Arity]"};
{error,
"No function specified. Usage: query Module:Function or Module.Function[/Arity]"};
parse_query_args(["--cache", Dir | Rest], Opts) ->
parse_query_args(Rest, Opts#{cache_dir => Dir});
parse_query_args(["-c", Dir | Rest], Opts) ->
Expand Down Expand Up @@ -451,10 +456,6 @@ parse_update_args(["--force" | Rest], Opts) ->
parse_update_args([Unknown | _], _Opts) ->
{error, "Unknown option: " ++ Unknown}.

-doc false.
run_audit(Opts) ->
spectrometer_analyzer:audit(Opts).

-doc false.
run_analyzer_dispatch(Opts, Runner) ->
case spectrometer_utils:start_applications() of
Expand All @@ -464,64 +465,3 @@ run_analyzer_dispatch(Opts, Runner) ->
io:format("Failed to start required applications... "),
{error, Reason}
end.

-doc false.
-spec run_ecosystem(opts_map()) -> ok | {error, term()}.
run_ecosystem(Opts) ->
spectrometer_ecosystem:run(Opts).

-doc false.
run_examine(Opts) ->
spectrometer_analyzer:examine(Opts).

-doc false.
-spec run_supported(opts_map()) -> ok | {error, unsupported}.
run_supported(Opts) ->
spectrometer_atomvm:report_supported(Opts).

-doc false.
-spec run_filter(opts_map()) -> ok | {error, term()}.
run_filter(Opts) ->
spectrometer_analyzer:filter(Opts).

-doc false.
-spec run_query(opts_map()) -> ok | {error, term()}.
run_query(Opts) ->
spectrometer_atomvm:query(Opts).

-doc false.
-spec run_update(opts_map()) -> ok | {error, term()}.
run_update(Opts) ->
case Opts of
#{cache_dir := CacheDir} ->
application:set_env(spectrometer, cache_dir, CacheDir);
#{} ->
ok
end,
OutputFile =
case Opts of
#{output := File} ->
File;
#{} ->
spectrometer_utils:user_db_file()
end,
Force = maps:get(force, Opts, false),

case filelib:is_file(OutputFile) andalso not Force of
true ->
io:format("Output file already exists: ~s\n", [OutputFile]),
io:format("Use --force to overwrite.\n"),
{error, {file_exists, OutputFile}};
_ ->
case spectrometer_updater:update_datafile(Opts, OutputFile) of
ok ->
ok;
{error, Reason} ->
io:format(
standard_error, "Error: unable to update data, ~p\n", [
Reason
]
),
{error, Reason}
end
end.
Loading
Loading