28

I have an elixir project with a defined version. How can I access this from within the running application.

in mix.exs

  def project do
    [app: :my_app,
     version: "0.0.1"]
  end

I would like to be access this version number in the application so I can add it to the returned message. I looking for something in the env hash like the following

__ENV__.version
# => 0.0.1
Peter Saxton
  • 4,466
  • 5
  • 33
  • 51

6 Answers6

40

Mix.Project itself provides access to all project keywords defined in mix.exs using its config/0 (api doc) function. For concise access it might be wrapped into a function:

@version Mix.Project.config[:version]
def version(), do: @version
0x0me
  • 754
  • 6
  • 16
  • 7
    Make sure this is evaluated at compile time like shown in the example. Otherwise it will not work in production because `module Mix.Project is not available`. – Joe Eifert Apr 21 '17 at 10:45
26

Here's a similar approach to retrieve the version string. It also relies on the :application module, but is maybe a bit more straightforward:

{:ok, vsn} = :application.get_key(:my_app, :vsn)
List.to_string(vsn)
Patrick Oscity
  • 53,604
  • 17
  • 144
  • 168
  • This is a better way. Personally, I'd still use the `charlist |> string |> integer` parsing pipeline, but this is definitely cleaner than using `which_applications`. – Chris Meyer Oct 06 '15 at 23:25
  • Yes good point. Chris' solution is obviously longer because it does an extra step to convert the string into a tuple of integers. Just for printing, the plain string should however be enough. You could combine the two answers to get the tuple if you need it. – Patrick Oscity Oct 07 '15 at 04:20
22

In recent versions of Elixir, the Application module now wraps this for you:

https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/application.ex

Application.spec(:my_app, :vsn) |> to_string()

The Kernel.to_string() method is necessary as Application.spec/2 for the keys :vsn and :description return charlists. to_string() from the Kernel module converts them to a binary.

sebisnow
  • 1,671
  • 17
  • 26
Dr. Ernie
  • 517
  • 4
  • 14
6

I found the version inside of :application.which_applications, but it requires some parsing:

defmodule AppHelper do
  @spec app_version(atom) :: {integer, integer, integer}
  def app_version(target_app) do
    :application.which_applications
    |> Enum.filter(fn({app, _, _}) ->
                    app == target_app
                   end)
    |> get_app_vsn
  end

  # I use a sensible fallback when we can't find the app,
  # you could omit the first signature and just crash when the app DNE.
  defp get_app_vsn([]), do: {0,0,0} 
  defp get_app_vsn([{_app, _desc, vsn}]) do
    [maj, min, rev] = vsn
                      |> List.to_string
                      |> String.split(".")
                      |> Enum.map(&String.to_integer/1)
    {maj, min, rev}
  end
end

And then for usage:

iex(1)> AppHelper.app_version(:logger)
{1, 0, 5}

As always, there's probably a better way.

Chris Meyer
  • 1,601
  • 10
  • 19
  • Good answer cheers. Though kinda a shame if that is the best way to get at it. – Peter Saxton Oct 06 '15 at 12:00
  • 1
    That's the guidance that Jose Valim gave to someone just a few weeks ago. That is, use :application.which_application. https://groups.google.com/d/msg/elixir-lang-talk/qlX4hJKZvC8/pCZBqM1zCQAJ – Onorio Catenacci Oct 06 '15 at 12:16
3

You can simple use:

YourApp.Mixfile.project[:version]
Kernael
  • 3,270
  • 4
  • 22
  • 42
  • Just FYI, that's a canned comment inserted automatically during review - it really doesn't reflect this case, which is unfortunate. My own take on it: An answer is a _statement_, ideally backed up with authoritative references, examples, and/or experiences. Although there is no question mark here, "What about..." is a _question_. If this is indeed an answer, I suggest you edit it to sound like one, and offer a brief explanation that would educate readers by connecting the proffered solution to the problem. – Mogsdad Oct 23 '15 at 18:50
2

Application.spec(:my_app, :vsn) works when the application is started. If you're in a Mix task and you don't need to start the application, in Elixir 1.8 you can use:

MyApp.MixProject.project |> Keyword.fetch!(:version)
Alex
  • 34,776
  • 10
  • 53
  • 68