Skip to content
This repository has been archived by the owner on Nov 23, 2023. It is now read-only.

Commit

Permalink
Merge branch 'rebar3-provider'
Browse files Browse the repository at this point in the history
  • Loading branch information
erszcz committed Jul 19, 2018
2 parents 56f5348 + 5113f54 commit d7fadb8
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 52 deletions.
23 changes: 11 additions & 12 deletions src/docsh_docs_v1.erl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ format_functions(Mod, Items, Kinds, Lang) ->
DocIfRequested <- [ "" ++ [ ["\n", format_maybe_doc(MaybeDoc, Lang)]
|| lists:member(doc, Kinds) ] ] ]).

format_types(Mod, Items, Lang) ->
format_types(_Mod, Items, _Lang) ->
?il2b([ [?il2b([Signature])]
|| {{_, _Name, _Arity}, _, Signature, _, _Metadata} <- Items ]).

Expand Down Expand Up @@ -145,7 +145,7 @@ step(_ModuleInfo, {Name, Arity}, Info0, { #docs_v1{} = DocsV1, DocsMap }) ->
KNA = {Kind, Name, Arity},
Entry = { {Kind, Name, Arity},
erl_anno:new({0, 1}),
signature(Name, Arity, Info),
signature(Kind, Name, Arity, Info),
#{<<"en">> => description(Name, Arity, Info)},
#{} },
{DocsV1, DocsMap#{KNA => Entry}}.
Expand All @@ -165,19 +165,18 @@ infer_item_kind(Info) ->
_ -> type
end.

signature(Name, Arity, Info) ->
case {docsh_lib:get(spec, Info, not_found),
docsh_lib:get(type, Info, not_found)} of
{not_found, not_found} ->
signature(Kind, Name, Arity, Info) ->
InfoKey = case Kind of
function -> spec;
type -> type
end,
case docsh_lib:get(InfoKey, Info, not_found) of
not_found ->
SName = atom_to_list(Name),
SArity = integer_to_list(Arity),
[iolist_to_binary([SName, "/", SArity])];
{Spec, not_found} ->
[Spec];
{not_found, Type} ->
[Type];
{_Spec, _Type} ->
error(spec_and_type_present, [Name, Arity, Info])
InfoItem ->
[InfoItem]
end.

module_doc(ModuleInfo) ->
Expand Down
33 changes: 22 additions & 11 deletions src/docsh_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,9 @@ get_docs(M) ->
case docsh_beam:from_loaded_module(M) of
{error, _} = E -> E;
{ok, B} ->
case do_get_docs(B) of
{ok, Docs} ->
{ok, Docs};
{error, _} ->
{ok, Docs, Warnings} = make_docs(B),
[ print("~s", [docsh_lib:format_error({W, docsh_beam:name(B)})]) || W <- Warnings ],
%% TODO: enable cache at some point
%cache_docs(B, Docs),
{ok, Docs}
end
MakeDocs = application:get_env(docsh, compile_on_demand, compile_if_missing),
AvailableDocs = do_get_docs(B),
dispatch_docs_extraction(B, MakeDocs, AvailableDocs)
end.

do_get_docs(B) ->
Expand All @@ -248,6 +241,24 @@ do_get_docs(B) ->
{error, R}
end.

dispatch_docs_extraction(B, never, AvailableDocs) ->
%% just for troubleshooting
{ok, [B, never, AvailableDocs]};
dispatch_docs_extraction(_, compile_if_missing, {ok, Docs}) ->
{ok, Docs};
dispatch_docs_extraction(B, compile_if_missing, {error, _} = Err) ->
%% TODO: log Reason?
dispatch_docs_extraction(B, always, Err);
dispatch_docs_extraction(B, always, _) ->
dispatch_docs_extraction_(B).

dispatch_docs_extraction_(B) ->
{ok, Docs, Warnings} = make_docs(B),
[ print("~s", [docsh_lib:format_error({W, docsh_beam:name(B)})]) || W <- Warnings ],
%% TODO: enable cache at some point
%cache_docs(B, Docs),
{ok, Docs}.

-spec make_docs(docsh_beam:t()) -> {ok, docsh_format:t(), [Warning]} when
Warning :: no_debug_info | no_src.
make_docs(Beam) ->
Expand All @@ -256,7 +267,7 @@ make_docs(Beam) ->
andalso error(docs_present, [BEAMFile]),
case {docsh_beam:abstract_code(Beam), docsh_beam:source_file(Beam)} of
{false, false} ->
error(no_debug_info_no_src, [BEAMFile]);
error({no_debug_info_no_src, BEAMFile}, [BEAMFile]);
{_, false} ->
{ok, do_make_docs(Beam), [no_src]};
{false, _} ->
Expand Down
3 changes: 1 addition & 2 deletions src/docsh_tracer.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
-module(docsh_tracer).

-compile([export_all]).
-compile([export_all, nowarn_export_all]).

-define(il2b, iolist_to_binary).

Expand Down
85 changes: 85 additions & 0 deletions src/rebar3_prv_docsh.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
-module('rebar3_prv_docsh').

-behaviour(provider).
-export([init/1,
do/1,
format_error/1]).

-define(PROVIDER, compile).
-define(DEPS, [{default, compile}]).
-define(SHORT_DESC, "Store modules' documentation in Docs chunks according to EEP-48").
-define(DESC, "Store modules' documentation in Docs chunks according to EEP-48.\n"
"This exposes Erlang module documentation to Elixir and other BEAM languages.\n"
"Use https://github.com/erszcz/docsh to access your docs in an Erlang shell.\n").

%% ===================================================================
%% Public API
%% ===================================================================

-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
POpts = [
{name, ?PROVIDER}, % The 'user friendly' name of the task
{namespace, docsh},
{module, ?MODULE}, % The module implementation of the task
{bare, true}, % The task can be run by the user, always true
{deps, ?DEPS}, % The list of dependencies
{opts, []}, % list of options understood by the plugin
{short_desc, ?SHORT_DESC},
{desc, ?DESC}
],
Provider = providers:create(POpts),
{ok, rebar_state:add_provider(State, Provider)}.

-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
Apps = case rebar_state:current_app(State) of
undefined ->
rebar_state:project_apps(State);
AppInfo ->
[AppInfo]
end,
[ process_app(State, App) || App <- Apps ],
{ok, State}.

-spec format_error(any()) -> iolist().
format_error(Reason) ->
docsh_lib:format_error(Reason).

%% ===================================================================
%% Helpers
%% ===================================================================

-spec process_app(rebar_state:t(), rebar_app_info:t()) -> ok.
process_app(State, App) ->
BEAMs = app_beam_files(App),
[ process_beam(State, B) || B <- BEAMs ].

-spec app_beam_files(rebar_app_info:t()) -> [file:filename()].
app_beam_files(App) ->
EbinDir = rebar_app_info:ebin_dir(App),
filelib:wildcard(filename:join([EbinDir, "*.beam"])).

-spec process_beam(rebar_state:t(), file:filename()) -> ok.
process_beam(_State, BeamFile) ->
case docsh_lib:has_docs(BeamFile) of
true ->
ok;
false ->
{ok, B} = docsh_beam:from_beam_file(BeamFile),
{ok, Docs, Warnings} = docsh_lib:make_docs(B),
print_warnings(docsh_beam:name(B), Warnings),
DocsChunk = make_docs_chunk(Docs),
{ok, NewBeam} = add_chunks(BeamFile, [DocsChunk]),
ok = file:write_file(BeamFile, NewBeam)
end.

print_warnings(Name, Warnings) ->
[ docsh_lib:print("~s", [docsh_lib:format_error({W, Name})]) || W <- Warnings ].

make_docs_chunk(Docs) ->
{"Docs", term_to_binary(Docs, [compressed])}.

add_chunks(BeamFile, NewChunks) ->
{ok, _, OldChunks} = beam_lib:all_chunks(BeamFile),
{ok, _NewBEAM} = beam_lib:build_module(OldChunks ++ NewChunks).
2 changes: 1 addition & 1 deletion test/completeness_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(completeness_SUITE).
-compile(export_all).
-compile([export_all, nowarn_export_all]).

-import(docsh_helpers, [sh/2]).

Expand Down
3 changes: 1 addition & 2 deletions test/ct_helper.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
-module(ct_helper).

-compile([export_all]).
-compile([export_all, nowarn_export_all]).

%% @doc Like ct:get_config/1, but calls error/1 if Key is not found / undefined.
%% This guarantees to fail fast if required config options are missing from
Expand Down
2 changes: 1 addition & 1 deletion test/docsh_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(docsh_SUITE).
-compile(export_all).
-compile([export_all, nowarn_export_all]).

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
Expand Down
17 changes: 16 additions & 1 deletion test/docsh_helpers.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(docsh_helpers).
-compile([export_all]).
-compile([export_all, nowarn_export_all]).

-define(b2l(B), binary_to_list(B)).
-define(il2b(IL), iolist_to_binary(IL)).
Expand Down Expand Up @@ -28,3 +28,18 @@ sh_log(Command, Code, Result) ->
"code : ~p\n"
"result : ~ts",
[Command, Code, Result]).

check_precondition({Name, P}, Config) ->
try
P(Config),
ok
catch _:Reason ->
ct:fail("~ts failed: ~p", [Name, Reason])
end.

current_git_commit() ->
case os:getenv("TRAVIS_PULL_REQUEST_SHA") of
false -> {_, _, R} = sh("git rev-parse HEAD"),
R;
Commit -> Commit
end.
2 changes: 1 addition & 1 deletion test/edoc_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(edoc_SUITE).
-compile(export_all).
-compile([export_all, nowarn_export_all]).

-include_lib("eunit/include/eunit.hrl").
-include("proplists_eq.hrl").
Expand Down
25 changes: 6 additions & 19 deletions test/install_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
-module(install_SUITE).
-compile(export_all).
-compile([export_all, nowarn_export_all]).

-import(docsh_helpers, [sh/1]).
-import(docsh_helpers, [check_precondition/2,
current_git_commit/0,
sh/1]).

-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
Expand All @@ -15,10 +17,10 @@ all() ->
[docker_linux].

init_per_suite(Config) ->
[ check(P, Config) || P <- prerequisites() ],
[ check_precondition(P, Config) || P <- preconditions() ],
Config.

prerequisites() ->
preconditions() ->
[
{ "docker in $PATH", fun (_Config) -> {_, _, <<"Docker", _/bytes>>} = sh("docker -v") end },
{ "git in $PATH", fun (_) -> {_, _, <<"usage: git", _/bytes>>} = sh("git --help") end }
Expand Down Expand Up @@ -72,14 +74,6 @@ docker_linux(_) ->
%% Helpers
%%

check({Name, P}, Config) ->
try
P(Config),
ok
catch _:Reason ->
ct:fail("~ts failed: ~p", [Name, Reason])
end.

container_name(Prefix) ->
RawRandomBytes = crypto:strong_rand_bytes(9),
Base64 = base64:encode(RawRandomBytes),
Expand Down Expand Up @@ -121,13 +115,6 @@ is_container_running(Name) ->
true
catch _:_ -> false end.

current_git_commit() ->
case os:getenv("TRAVIS_PULL_REQUEST_SHA") of
false -> {_, _, R} = sh("git rev-parse HEAD"),
R;
Commit -> Commit
end.

clone(Repo) ->
["git clone ", Repo].

Expand Down
2 changes: 1 addition & 1 deletion test/proplists_eq_SUITE.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(proplists_eq_SUITE).
-compile(export_all).
-compile([export_all, nowarn_export_all]).

-include_lib("eunit/include/eunit.hrl").

Expand Down
Loading

0 comments on commit d7fadb8

Please sign in to comment.