AdRoll / rebar3_format

Erlang Formatter for Rebar3
https://tech.nextroll.com/blog/dev/2020/02/25/erlang-rebar3-format.html
MIT License
109 stars 21 forks source link

undefined function rebar3_format:main/1 #331

Closed Olivier-Boudeville closed 1 year ago

Olivier-Boudeville commented 1 year ago

Hi again,

(using rebar 3.20.0 on Erlang/OTP 25 Erts 13.1)

Trying to run rebar3_format as an escript rather than as a plugin; I imagine it is still supported?

Its build is now ok, yet when executing it, it does not seem to find its main module, whereas that module was built:

  $ git clone https://github.com/AdRoll/rebar3_format.git
  $ cd rebar3_format
  $ ERL_FLAGS="-enable-feature all" rebar3 as release escriptize
  $./_build/release/bin/rebar3_format
escript: exception error: undefined function rebar3_format:main/1
  in function  escript:run/2 (escript.erl, line 750)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1 
  in call from init:do_boot/3 

Nevertheless ./_build/release/lib/rebar3_format/ebin/rebar3_format.beam exists. I suppose we should not fiddle with the code path or alter the environment so that the escript can be run?

(tried also a prior ERL_FLAGS="-enable-feature all" rebar3 format yet the escript is still failing)

Thanks for any hint!

Olivier-Boudeville commented 1 year ago

(tried also a ERL_FLAGS="-enable-feature all" ./_build/release/bin/rebar3_format)

elbrujohalcon commented 1 year ago

I don't think we ever supported this. We do have a script, but it was primarily a test artifact, IIRC.

elbrujohalcon commented 1 year ago

In any case, rebar3_format:main/1, in fact, doesn't exist… https://github.com/AdRoll/rebar3_format/blob/main/src/rebar3_format.erl

Olivier-Boudeville commented 1 year ago

OK, thanks again Brujo; I was mistaken by the existence of the ./_build/release/bin/rebar3_format escript and may have mixed up with another similar tool (erlfmt - which does provide also an escript, in addition to a plugin).

Maybe simply adding in the rebar3_format module a function along the following lines could help?

main(_) ->
  io:format("rebar3_format shall be run as a plugin, not as an escript."),              
  throw(escript_not_supported).

Thanks anyway, I close the issue.

elbrujohalcon commented 1 year ago

Yeah, pull requests are welcomed with open arms :)

Olivier-Boudeville commented 1 year ago

Well, you are right, this is fair!

So I gave it a go, starting from my previous example code, with this commit https://github.com/AdRoll/rebar3_format/compare/main...Olivier-Boudeville:rebar3_format:notify-escript-not-supported

Using ERL_FLAGS="-enable-feature all" rebar3 test, I could overcome the facts that the word "rebar3_format" was not among the known ones in dictionary, that neither io:format/1 nor throw/1 were wanted, so I ended with:


-export([init/1, main/1]).

[...]

%% @private
-spec main(any()) -> no_return().
main(_) ->
    rebar_api:abort("rebar3_format shall be run as a plugin, not as an escript.",[]).

However the dead link checker does not seem to be aware that this code could be called as an escript, and I am a bit stuck about how to override this misbelief (maybe a behaviour-like declaration could prevent that):

===> The following pieces of code are dead and should be removed:
src/rebar3_format.erl:13: main/1 doesn't need its #1 argument

Worse, actually running that code will not work either:

$ ERL_FLAGS="-enable-feature all" rebar3 as release escriptize
$ ERL_FLAGS="-enable-feature all" ./_build/release/bin/rebar3_format
escript: exception error: undefined function rebar_api:abort/2
  in function  escript:run/2 (escript.erl, line 750)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1
  in call from init:do_boot/3

So I guess some direct calls to io:format/2 and halt/exit/throw would be needed in this case - but the various checkers involved will not allow that. I see no satisfactory solution here!

elbrujohalcon commented 1 year ago

You just have to ignore the checkers with something like this (you might need to adjust it because I'm writing it directly on the web from memory)…

-elvis({elvis_style, no_call, disable}).
-hank({unnecessary_function_argument, [{main, 1, 1}]}).

The rules are there to prevent us from doing bad stuff… but if we know we are doing good stuff we can just ignore them ;)