Skip to content
This repository has been archived by the owner. It is now read-only.

modify `priv/rel/files/boot` so it can run elixir in command-line mode. #295

Merged
merged 1 commit into from Feb 19, 2016

Conversation

@vadim-ex
Copy link
Contributor

vadim-ex commented Feb 17, 2016

With this change, assuming that we have hello_cli.ex in the project test_cli with following content:

defmodule HelloCli do
  @spec main() :: no_return
  def main() do
    # print greeting
    IO.puts "HelloCli.main() is running"

    # print command-line args
    :init.get_plain_arguments()
    |> Enum.map(&String.Chars.to_string/1)
    |> Enum.each(&IO.puts/1)

    # set exit code to 4
    System.halt(4)
  end
end

We can release it, and then run

bin/test_cli command Elixir.HelloCli main foo bar baz

The command above prints:

Using /home/vadim/moz/ex/test/rel/test/releases/0.0.1/test.sh
HelloCli.main() is running
foo
bar
baz
@vadim-ex

This comment has been minimized.

Copy link
Contributor Author

vadim-ex commented Feb 17, 2016

I found virtually identical #37. Before closing this one, I will appreciate considering it:

  • it is simpler (affects single boot template);
  • it is more universal -- so, for example, multiple commands can be invoked from the single project. While it looks superficial (one can use command-line switches to the same effect), it simplify things a lot (since deps can provide mix task-like options, which do not need to be hooked-up into common interface).

I also would voice support toward including cli as a standard feature, one way or another. I found it important tool (for example, validation of config during deploy, but before taking system up).

@bitwalker

This comment has been minimized.

Copy link
Owner

bitwalker commented Feb 18, 2016

@vadim-moz #37 was never prod-ready anyway, mostly a discussion to spawn a PR like yours, so I would merge yours.

Could you clarify what you mean by "including cli as a standard feature"? I just want to make sure I understand the specific need that represents before I merge this PR (just in case the real solution is something more complex, but conflicts with the purpose of this change, I don't want to have to document and maintain this if it's a stopgap solution).

@vadim-ex

This comment has been minimized.

Copy link
Contributor Author

vadim-ex commented Feb 18, 2016

Could you clarify what you mean by "including cli as a standard feature"?

I mean, as readily available as console, start, foreground, etc.

My [project] need is to run command-line utilities. I found no way to do that using one of provided options. Escript did not work for us (I have to admit I do not exactly remember what was broken) In addition, escript insisted on carrying a lot of binaries with invocation, which was duplicate to released project.

The command (or cli) was the most straightforward (and natural, I hope) way to create command-line utility. As I hoped to show in the PR comment, it can execute the specified function, pass arguments, and return exit code.

@vadim-ex

This comment has been minimized.

Copy link
Contributor Author

vadim-ex commented Feb 18, 2016

The only disadvantage is that arguments are passed through the :erlang api, not elixir native. But this seems to be elixir runtime problem, not exrm. I might be wrong although.

@bitwalker

This comment has been minimized.

Copy link
Owner

bitwalker commented Feb 18, 2016

@vadim-moz What you've got here sounds like it fulfills those requirements, or at the very least is a good base.

What do you think of something like: bin/myapp command arg --flag1=val1 and configuration via exrm which allows you to set what the entrypoint module is for the cli command (i.e. if something like entrypoint: HelloCli is set, then bin/myapp cli will look for a module named Elixir.HelloCli and call it's main/1 function, and if it was set to something like entrypoint: :some_erl_module then it would look for a module named some_erl_module and call it's main/1 function). If no entrypoint is provided, it just returns an error message stating that one must be provided. The benefit being that you do not have to recall the specific module name in order to use the provided CLI.

@vadim-ex

This comment has been minimized.

Copy link
Contributor Author

vadim-ex commented Feb 18, 2016

I have seen this approach in the #37. I decided against it for my project purpose. Basically, I want to be able to call multiple projects/functions. For example, I want to run my code (MyApp.main), and this is a main entry point. But I also have complicated configuration. To process it, I have MyConfig application, shared by several projects, and compiled into MyApp as a dependency. I want to run MyConfig.validate during deployment process, to ensure that everything is properly configured.

I can, of course, do it by providing flags in the MyApp.main. It is inconvenient, because these flags would pollute interface of every app that uses MyConfig. In addition, some of MyConfig clients are not command line, and for them it would require special coding.

That said, I am not strongly against it. I'd better have your proposed solution (common entry point) than my current production kludge (manually extracted, modified, and unmaintained portion of boot).

I am really grateful that you kindly consider this PR.

@vadim-ex

This comment has been minimized.

Copy link
Contributor Author

vadim-ex commented Feb 18, 2016

As "The Zen of Python" puts it, "special cases are not special enough". I am ready to consider my project approach as a special case, which is not special enough to make it part of common solution. After all, I have experience of only one project, you see many of them. One more item against me: I modeled interface after rpc subcommand -- but nothing says it is a right approach.

On the other hand bin/app cli makes entry point implicit. I am personally prefer explicit interfaces. It is trivial to create a wrapping script like bin/app cli MyApp my_fun "$@" which even better fits the bill.

@bitwalker

This comment has been minimized.

Copy link
Owner

bitwalker commented Feb 19, 2016

@vadim-moz I actually liked that this is modeled after rpc, because the behaviour is the same, just run locally instead of against the release node (which can be remote).

bitwalker pushed a commit that referenced this pull request Feb 19, 2016
modify `priv/rel/files/boot` so it can run elixir in command-line mode.
@bitwalker bitwalker merged commit fec5aba into bitwalker:master Feb 19, 2016
1 check passed
1 check passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@vadim-ex vadim-ex deleted the vadim-ex:vadim/command-line-interface branch Feb 20, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
2 participants
You can’t perform that action at this time.