170 lines
4.3 KiB
Elixir
170 lines
4.3 KiB
Elixir
# Since Elixir does not (yet) support local macros,
|
|
# we need to wrap the step that extracts git information
|
|
# in this module.
|
|
defmodule System.GitCompiler do
|
|
@moduledoc false
|
|
|
|
defmacro generate do
|
|
quote do
|
|
@doc """
|
|
Returns a tuple { Elixir version, commit sha-1, build date }.
|
|
|
|
The format of the return value may change in a future release. Please
|
|
make sure your code doesn't depend on it.
|
|
"""
|
|
def build_info do
|
|
{ System.version,
|
|
unquote(get_head_sha),
|
|
unquote(get_date) }
|
|
end
|
|
end
|
|
end
|
|
|
|
# Tries to run `git rev-parse HEAD`. In case of success returns the
|
|
# commit sha, otherwise returns an empty string.
|
|
defp get_head_sha do
|
|
# The following failures are possible:
|
|
#
|
|
# 1) there is no `git` command
|
|
# 2) pwd is not a git repository
|
|
#
|
|
command = 'git rev-parse HEAD'
|
|
opts = [:stream, :exit_status, :use_stdio,
|
|
:stderr_to_stdout, :in, :eof]
|
|
port = :erlang.open_port {:spawn, command}, opts
|
|
|
|
output = read_port port
|
|
case output do
|
|
{ 0, data } ->
|
|
Regex.replace_all %r/\n/, to_binary(data), ""
|
|
_ ->
|
|
""
|
|
end
|
|
end
|
|
|
|
defp read_port(port, data // []) do
|
|
receive do
|
|
{^port, {:data, new_data}} ->
|
|
read_port port, [new_data|data]
|
|
{^port, :eof} ->
|
|
:erlang.port_close port
|
|
receive do
|
|
{^port, {:exit_status, exit_status}} ->
|
|
{exit_status, List.reverse data}
|
|
end
|
|
end
|
|
end
|
|
|
|
defp get_date do
|
|
list_to_binary :httpd_util.rfc1123_date
|
|
end
|
|
end
|
|
|
|
defmodule System do
|
|
@moduledoc """
|
|
The System module provides access to some variables used or
|
|
maintained by the VM and to functions that interact strongly
|
|
with the VM or the host system.
|
|
"""
|
|
|
|
require System.GitCompiler
|
|
System.GitCompiler.generate
|
|
|
|
@doc """
|
|
Returns Elixir's version as binary.
|
|
"""
|
|
def version, do: "0.5.0.dev"
|
|
|
|
@doc """
|
|
Returns the list of command-line arguments passed to the program.
|
|
"""
|
|
def argv do
|
|
Erlang.gen_server.call(:elixir_code_server, :argv)
|
|
end
|
|
|
|
@doc """
|
|
Registers a function that will be invoked
|
|
at the end of program execution. Useful for
|
|
invoking a hook on scripted mode.
|
|
|
|
The function must expect the exit status code
|
|
as argument.
|
|
"""
|
|
def at_exit(fun) when is_function(fun, 1) do
|
|
server_call { :at_exit, fun }
|
|
end
|
|
|
|
@doc """
|
|
Executes `command` in a command shell of the target OS,
|
|
captures the standard output of the command and returns
|
|
the result as a binary.
|
|
"""
|
|
def cmd(command) do
|
|
list_to_binary :os.cmd(to_char_list(command))
|
|
end
|
|
|
|
@doc """
|
|
Returns a list of all environment variables. Each environment variable is
|
|
given as a single string of the format "VarName=Value", where VarName is the
|
|
name of the variable and Value its value.
|
|
"""
|
|
def get_env do
|
|
Enum.map :os.getenv, list_to_binary &1
|
|
end
|
|
|
|
@doc """
|
|
Returns the value of the environment variable
|
|
`varname` as a binary, or nil if the environment
|
|
variable is undefined.
|
|
"""
|
|
def get_env(varname) do
|
|
case :os.getenv(to_char_list(varname)) do
|
|
false -> nil
|
|
other -> list_to_binary(other)
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Returns the process identifier of the current Erlang emulator
|
|
in the format most commonly used by the operating system environment.
|
|
|
|
See http://www.erlang.org/doc/man/os.html#getpid-0 for more info.
|
|
"""
|
|
def get_pid, do: list_to_binary(:os.getpid)
|
|
|
|
@doc """
|
|
Sets a new `value` for the environment variable `varname`.
|
|
"""
|
|
def put_env(varname, value) do
|
|
:os.putenv to_char_list(varname), to_char_list(value)
|
|
end
|
|
|
|
@doc """
|
|
Sets a new value for each environment variable corresponding
|
|
to each key in `dict`.
|
|
"""
|
|
def put_env(dict) do
|
|
Enum.each dict, fn {key, val} -> put_env key, val end
|
|
end
|
|
|
|
@doc """
|
|
Get the stacktrace.
|
|
"""
|
|
def stacktrace do
|
|
filter_stacktrace Erlang.erlang.get_stacktrace
|
|
end
|
|
|
|
## Helpers
|
|
|
|
# Filter stacktrace by removing internal BOOTSTRAP calls.
|
|
defp filter_stacktrace([{ Elixir.Builtin, :raise, _, _ }|t]), do: filter_stacktrace(t)
|
|
defp filter_stacktrace([{ _mod, :BOOTSTRAP, _, info }|t]),
|
|
do: filter_stacktrace([{ Elixir.Builtin, :defmodule, 2, info }|t])
|
|
defp filter_stacktrace([h|t]), do: [h|filter_stacktrace(t)]
|
|
defp filter_stacktrace([]), do: []
|
|
|
|
defp server_call(args) do
|
|
Erlang.gen_server.call(:elixir_code_server, args)
|
|
end
|
|
end
|