Packages
appsignal
2.17.4
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.0
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.1
2.14.0
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.12.3
2.12.2
2.12.1
2.12.0
2.11.0
2.10.2
2.10.1
2.10.0
2.9.2
2.9.1
2.9.0
2.8.3
2.8.2
2.8.1
2.8.0
2.7.13
2.7.12
2.7.11
2.7.10
2.7.9
2.7.8
2.7.7
2.7.6
2.7.5
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-beta.1
2.6.1
2.6.0
2.5.3
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.1
2.3.0
2.2.19
2.2.18
2.2.17
2.2.16
2.2.15
2.2.14
2.2.13
2.2.12
retired
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.15
2.1.14
2.1.13
2.1.12
2.1.11
2.1.10
2.1.9
2.1.8
2.1.7
2.1.7-beta.1
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.8
2.0.7
2.0.6
2.0.6-beta.1
2.0.5
retired
2.0.4
retired
2.0.3
retired
2.0.2
retired
2.0.1
retired
2.0.0
retired
2.0.0-beta.11
2.0.0-beta.10
2.0.0-beta.9
2.0.0-beta.8
2.0.0-beta.7
2.0.0-beta.6
2.0.0-beta.5
2.0.0-beta.4
2.0.0-beta.3
2.0.0-beta.2
2.0.0-beta.1
2.0.0-alpha.7
2.0.0-alpha.6
2.0.0-alpha.5
2.0.0-alpha.4
2.0.0-alpha.3
2.0.0-alpha.2
2.0.0-alpha.1
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.13.0-beta.2
1.13.0-beta.1
1.12.1
1.12.0
1.12.0-beta.3
1.12.0-beta.2
1.12.0-beta.1
1.11.8
1.11.7
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
1.11.0
1.11.0-beta.1
1.10.13
1.10.12
1.10.11
1.10.10
1.10.9
1.10.8
1.10.7
1.10.6
1.10.5
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.4
1.9.3
1.9.2
1.9.1
1.9.1-beta.1
1.9.0
1.9.0-beta.1
1.9.0-alpha.1
1.8.2
1.8.1
1.8.1-beta.2
1.8.1-beta.1
1.8.0
1.7.2
1.7.1
1.7.0
1.7.0-beta.2
1.7.0-beta.1
1.7.0-alpha.4
1.7.0-alpha.3
1.7.0-alpha.2
1.7.0-alpha.1
1.6.7
1.6.6
1.6.6-beta.2
1.6.6-beta.1
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-beta.1
1.6.0-alpha.1
1.5.1
1.5.0
1.5.0-beta.2
1.5.0-beta.1
1.4.11-beta.1
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-alpha.1
1.3.6
1.3.6-beta.1
1.3.5
1.3.4
1.3.4-beta.1
1.3.3
1.3.2
1.3.1
1.3.0
1.3.0-beta.3
1.3.0-beta.2
1.3.0-beta.1
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.1
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.2
0.9.1
0.9.0
0.8.0
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Collects error and performance data from your Elixir applications and sends it to AppSignal
Current section
Files
Jump to
Current section
Files
mix_helpers.exs
unless Code.ensure_loaded?(Appsignal.Agent) do
{_, _} = Code.eval_file("agent.exs")
end
defmodule Mix.Appsignal.Helper do
@moduledoc """
Helper functions for downloading and compiling the AppSignal agent library.
"""
@erlang Application.compile_env(:appsignal, :erlang, :erlang)
@os Application.compile_env(:appsignal, :os, :os)
@finch Application.compile_env(:appsignal, :finch, Finch)
@agent Application.compile_env(:appsignal, :agent, Appsignal.Agent)
@extractor Application.compile_env(:appsignal, :extractor, Mix.Appsignal.Helper.Extractor)
@make Application.compile_env(:appsignal, :make, Mix.Appsignal.Helper.Make)
@ldd Application.compile_env(:appsignal, :ldd, Mix.Appsignal.Helper.Ldd)
@root_checker Application.compile_env(:appsignal, :root_checker, Mix.Appsignal.Helper.Root)
@cached_build Application.compile_env(
:appsignal,
:cached_build,
Mix.Appsignal.Helper.CachedBuild
)
@report_writer Application.compile_env(
:appsignal,
:report_writer,
Mix.Appsignal.Helper.ReportWriter
)
@installed_version Application.compile_env(
:appsignal,
:installed_version,
Mix.Appsignal.Helper.InstalledVersion
)
@download_cache Application.compile_env(
:appsignal,
:download_cache,
Mix.Appsignal.Helper.DownloadCache
)
@extension_dir Application.compile_env(
:appsignal,
:extension_dir,
Mix.Appsignal.Helper.ExtensionDir
)
@proxy_env_vars [
"APPSIGNAL_HTTP_PROXY",
"https_proxy",
"HTTPS_PROXY",
"http_proxy",
"HTTP_PROXY"
]
require Logger
def install do
if Mix.env() == :test_no_nif, do: @extension_dir.prepare!(priv_dir())
report = initial_report()
case verify_system_architecture(report) do
{:ok, {arch, report}} ->
case find_package_source(arch, report) do
{:ok, {arch_config, %{build: %{source: "remote"}} = report}} ->
case download_and_compile(arch_config, report) do
:ok ->
:ok
{:error, {reason, report}} ->
abort_installation(reason, report)
end
{:ok, report} ->
# Installation using already downloaded package of the extension
compile(report)
{:error, {reason, report}} ->
abort_installation(reason, report)
end
{:error, {reason, report}} ->
abort_installation(reason, report)
end
end
@doc """
Checks to see if a proxy is defined in any of the accepted OS environment
variables (as per `@proxy_env_vars`).
Returns `nil` if no proxy is defined, or a `{variable_name, proxy_url}` tuple
matching the first found variable.
_NOTE: If the first variable found is defined but empty (""), proxying is
disabled (eg. `nil` is returned)._
"""
def check_proxy(environment \\ System.get_env()) do
Enum.reduce_while(@proxy_env_vars, nil, fn name, acc ->
if value = Map.get(environment, name) do
{:halt, proxy_or_nil(name, value)}
else
{:cont, acc}
end
end)
end
defp proxy_or_nil(_, ""), do: nil
defp proxy_or_nil(name, value), do: {name, value}
defp find_package_source(arch, report) do
architecture_key = arch_key(arch)
arch_config = @agent.triples()[architecture_key]
System.put_env("LIB_DIR", priv_dir())
cond do
has_local_release_files?() ->
Mix.shell().info("AppSignal: Using local agent release.")
@extension_dir.prepare!(priv_dir())
Enum.each(
["appsignal.h", "appsignal-agent", "appsignal.version", "libappsignal.a"],
fn file ->
File.cp(project_ext_path(file), priv_path(file))
end
)
{:ok, merge_report(report, %{build: %{source: "local"}})}
@cached_build.installed?(priv_dir(), @agent.version()) ->
{:ok, merge_report(report, %{build: %{source: "cached_in_priv_dir"}})}
is_nil(arch_config) ->
{:error,
{"No architecture build found for '#{architecture_key}'.",
merge_report(report, %{build: %{source: "remote"}})}}
true ->
{:ok, {arch_config, merge_report(report, %{build: %{source: "remote"}})}}
end
end
defp download_and_compile(arch_config, report) do
report = merge_report(report, %{download: %{checksum: "unverified"}})
case download_package(arch_config, report) do
{:ok, {filename, report}} ->
case verify_download_package(filename, arch_config[:checksum], report) do
{:ok, {filename, report}} ->
case extract_package(filename) do
:ok ->
compile(report)
{:error, reason} ->
{:error, {reason, report}}
end
{:error, {reason, report}} ->
{:error, {reason, report}}
end
{:error, {reason, report}} ->
{:error, {reason, report}}
end
end
defp download_package(arch_config, report) do
version = @agent.version()
filename = arch_config[:filename]
@extension_dir.prepare!(priv_dir())
local_filename = Path.join(tmp_dir(), "appsignal-agent-#{version}.tar.gz")
case @download_cache.exists?(local_filename) do
true ->
{:ok, {local_filename, merge_report(report, %{build: %{source: "cached_in_tmp_dir"}})}}
false ->
Mix.shell().info("Downloading agent release")
{:ok, pid} =
@finch.start_link(
name: AppsignalFinchDownload,
pools: %{default: [conn_opts: download_conn_opts()]}
)
try do
case do_download_file!(filename, local_filename, @agent.mirrors()) do
{:ok, url} ->
{:ok, {local_filename, merge_report(report, %{download: %{download_url: url}})}}
{error, url} ->
{:error, {error, merge_report(report, %{download: %{download_url: url}})}}
end
after
Process.exit(pid, :normal)
end
end
end
defp verify_download_package(filename, expected_checksum, report) do
data = @download_cache.read!(filename)
calculated_checksum = :crypto.hash(:sha256, data) |> Base.encode16(case: :lower)
if calculated_checksum == expected_checksum do
{:ok, {filename, merge_report(report, %{download: %{checksum: "verified"}})}}
else
sub_report = %{download: %{checksum: "invalid"}}
reason = """
Checksum verification of #{filename} failed!
Calculated: #{calculated_checksum}
Expected: #{expected_checksum}
"""
{:error, {reason, merge_report(report, sub_report)}}
end
end
defp do_download_file!(filename, local_filename, mirrors) do
Enum.reduce_while(mirrors, {1, []}, fn mirror, {acc, errors} ->
version = @agent.version()
url = build_download_url(mirror, version, filename)
result = do_download_file!(url, local_filename)
if result == :ok do
# Success on download
{:halt, {:ok, url}}
else
if length(mirrors) == acc do
# All mirrors failed. Write error message detailing all failures
error_messages =
Enum.map(Enum.reverse([result | errors]), fn {:error, message} ->
message
end)
message = """
Could not download archive from any of our mirrors.
Please make sure your network allows access to any of these mirrors.
Attempted to download the archive from the following urls:
#{Enum.join(error_messages, "\n")}
"""
{:halt, {String.trim(message), url}}
else
# Try the next mirror
{:cont, {acc + 1, [result | errors]}}
end
end
end)
end
defp do_download_file!(url, local_filename) do
request =
@finch.build(:get, url, [], "")
|> @finch.request(AppsignalFinchDownload, [])
case request do
{:ok, %{status: 200, body: body}} ->
@download_cache.write(local_filename, body)
response ->
message = """
- URL: #{url}
- Error (Finch response):
#{inspect(response)}
"""
{:error, message}
end
end
defp build_download_url(mirror, version, filename) do
Enum.join([mirror, version, filename], "/")
end
defp download_conn_opts do
default_cacert_file_path = priv_path("cacert.pem")
cacert_file =
case check_cacert_access(default_cacert_file_path) do
:ok ->
default_cacert_file_path
{:error, message} ->
Logger.warning(
"The cacert file path: #{default_cacert_file_path} is not accessible. " <>
"Reason: #{inspect(message)}. " <>
"Using system defaults instead."
)
:certifi.cacertfile()
end
transport_opts =
[
verify: :verify_peer,
cacertfile: cacert_file
] ++ tls_options() ++ customize_hostname_check_or_verify_fun()
conn_opts = [transport_opts: transport_opts]
case check_proxy() do
nil ->
conn_opts
{var, url} ->
Mix.shell().info("- using proxy from #{var} (#{url})")
conn_opts ++ [proxy: parse_proxy(url)]
end
end
defp parse_proxy(url) do
uri = URI.parse(url)
scheme = if uri.scheme == "https", do: :https, else: :http
port = uri.port || if scheme == :https, do: 443, else: 80
{scheme, uri.host, port, []}
end
defp check_cacert_access(cacert_path) do
case File.stat(cacert_path) do
{:ok, %{access: access}} when access in [:read, :read_write] ->
:ok
{:ok, %{access: access}} ->
{:error, "File access is #{inspect(access)}"}
{:error, reason} ->
{:error, reason}
end
end
defp extract_package(filename) do
@extractor.extract(filename, priv_dir())
end
defp compile(report) do
report =
case agent_version() do
{:ok, version} -> merge_report(report, %{build: %{agent_version: version}})
{:error, _} -> report
end
{output, exit_code} = run_make()
if exit_code == 0 do
Mix.shell().info("AppSignal extension installation successful")
write_report(merge_report(report, %{result: %{status: :success}}))
:ok
else
message = """
Build error was encountered while running `make` (exit code: #{exit_code}):
#{output}
"""
{:error, {message, report}}
end
end
defp run_make do
@make.run(to_string(Mix.env()))
end
def verify_system_architecture(report) do
input_arch =
if force_linux_arm_build?() do
~c"aarch64-linux"
else
@erlang.system_info(:system_architecture)
end
case map_arch(input_arch, agent_platform()) do
{:ok, {arch, target} = architecture} ->
sub_report = %{build: %{architecture: arch, target: target}}
{:ok, {architecture, merge_report(report, sub_report)}}
{:error, {:unsupported, {arch, target}}} ->
sub_report = %{build: %{architecture: arch, target: target}}
reason =
"Unsupported target platform #{arch} - #{target}, AppSignal " <>
"integration disabled!\nPlease check " <>
"http://docs.appsignal.com/support/operating-systems.html"
{:error, {reason, merge_report(report, sub_report)}}
{:error, {:unknown, {arch, target}}} ->
sub_report = %{build: %{architecture: arch, target: target}}
reason =
"Unknown target platform #{arch} - #{target}, AppSignal " <>
"integration disabled!\nPlease check " <>
"http://docs.appsignal.com/support/operating-systems.html"
{:error, {reason, merge_report(report, sub_report)}}
end
end
if Mix.env() != :test_no_nif do
defp map_arch(~c"i386-" ++ _, platform), do: build_for("i686", platform)
defp map_arch(~c"i686-" ++ _, platform), do: build_for("i686", platform)
defp map_arch(~c"x86-" ++ _, platform), do: build_for("i686", platform)
defp map_arch(~c"amd64-" ++ _, platform), do: build_for("x86_64", platform)
defp map_arch(~c"x86_64-" ++ _, platform), do: build_for("x86_64", platform)
defp map_arch(~c"aarch64-" ++ _, platform), do: build_for("aarch64", platform)
defp map_arch(~c"arm-" ++ _, platform), do: build_for("aarch64", platform)
end
defp map_arch(arch, platform), do: {:error, {:unknown, {to_string(arch), platform}}}
defp build_for(bit, platform) do
arch = {bit, platform}
case Map.has_key?(@agent.triples(), arch_key(arch)) do
true -> {:ok, arch}
false -> {:error, {:unsupported, arch}}
end
end
defp arch_key({arch, target}) do
"#{arch}-#{target}"
end
defp tmp_dir do
Application.get_env(:appsignal, :tmp_dir) ||
case {File.dir?("/tmp"), File.stat("/tmp")} do
{true, {:ok, %{access: :write}}} -> "/tmp"
{true, {:ok, %{access: :read_write}}} -> "/tmp"
_ -> System.tmp_dir!()
end
end
defp priv_path(filename) do
Path.join(priv_dir(), filename)
end
defp project_ext_path(filename) do
Path.join([__DIR__, "c_src", filename])
end
defp has_local_ext_file(filename) do
filename |> project_ext_path |> File.exists?()
end
defp has_local_release_files? do
has_local_ext_file("appsignal-agent") and has_local_ext_file("appsignal.h") and
has_local_ext_file("libappsignal.a")
end
defp agent_version do
@installed_version.read(priv_dir())
end
defp library_dependencies do
case ldd_version_output() do
{:ok, output} ->
case extract_ldd_version(output) do
nil ->
%{}
ldd_version ->
%{libc: ldd_version}
end
_ ->
%{}
end
end
def agent_platform do
cond do
force_linux_arm_build?() == true ->
"linux"
force_musl_build?() == true ->
"linux-musl"
true ->
case @os.type() do
{:unix, :linux} ->
agent_platform_by_ldd_version()
{_, os} ->
to_string(os)
end
end
end
defp agent_platform_by_ldd_version do
case ldd_version_output() do
{:ok, output} ->
case String.contains?(output, "musl") do
true ->
"linux-musl"
false ->
case extract_ldd_version(output) do
nil ->
"linux"
ldd_version ->
case Version.compare("#{ldd_version}.0", "2.15.0") do
:lt -> "linux-musl"
_ -> "linux"
end
end
end
_ ->
"linux"
end
end
# Fetches the libc version number from the `ldd` command
# If `ldd` is not found it returns `nil`
defp ldd_version_output do
@ldd.version_output()
end
defp extract_ldd_version(ldd_output) when is_binary(ldd_output) do
case Regex.run(~r/\d+\.\d+/, ldd_output) do
[version | _tail] -> version
_ -> nil
end
end
defp extract_ldd_version(_), do: nil
defp initial_report do
{_, os} = @os.type()
%{
result: %{
status: :incomplete
},
language: %{
name: "elixir",
version: System.version(),
otp_version: System.otp_release()
},
build: %{
time: DateTime.to_iso8601(DateTime.utc_now()),
package_path: priv_dir(),
architecture: nil,
target: os,
musl_override: force_musl_build?(),
linux_arm_override: force_linux_arm_build?(),
library_type: "static",
dependencies: %{},
flags: %{}
},
host: %{
root_user: root?(),
dependencies: library_dependencies()
}
}
end
defp write_report(report) do
write_download_report(report)
@report_writer.write_install_report(report)
end
defp write_download_report(%{download: %{}} = report) do
%{
build: %{
time: time,
architecture: architecture,
target: target,
musl_override: musl_override,
linux_arm_override: linux_arm_override,
library_type: library_type,
dependencies: %{},
flags: %{}
}
} = report
%{download: %{checksum: checksum}} = report
download_url = Map.get(report.download, :download_url)
download_report = %{
download: %{
time: time,
architecture: architecture,
target: target,
musl_override: musl_override,
linux_arm_override: linux_arm_override,
library_type: library_type,
download_url: download_url,
checksum: checksum || "unverified"
}
}
@report_writer.write_download_report(download_report)
end
defp write_download_report(_) do
# Write nothing if no download details are recorded in the report
end
defp merge_report(report, %{download: _download_report} = sub_report) do
key = :download
{download_report, sub_report} = Map.pop(sub_report, key)
report = Map.put(report, key, Map.merge(report[key] || %{}, download_report))
merge_report(report, sub_report)
end
defp merge_report(report, %{build: _build_report} = sub_report) do
key = :build
{build_report, sub_report} = Map.pop(sub_report, key)
report = Map.put(report, key, Map.merge(report[key], build_report))
merge_report(report, sub_report)
end
defp merge_report(report, %{result: _installation_report} = sub_report) do
key = :result
{installation_report, sub_report} = Map.pop(sub_report, key)
report = Map.put(report, key, installation_report)
merge_report(report, sub_report)
end
defp merge_report(report, %{}), do: report
defp abort_installation(reason, report) do
report =
merge_report(report, %{result: %{status: :failed, message: serialize_report_value(reason)}})
write_report(report)
Mix.Shell.IO.error("AppSignal installation failed: #{serialize_report_value(reason)}")
end
def priv_dir do
Application.get_env(:appsignal, :priv_dir) ||
case :code.priv_dir(:appsignal) do
{:error, :bad_name} ->
# This happens on initial compilation
Mix.Tasks.Compile.Erlang.manifests()
|> List.first()
|> Path.dirname()
|> String.trim_trailing(".mix")
|> Path.join("priv")
path ->
path
|> List.to_string()
end
end
defp force_musl_build? do
env = System.get_env("APPSIGNAL_BUILD_FOR_MUSL")
env == "1" || env == "true"
end
defp force_linux_arm_build? do
env = System.get_env("APPSIGNAL_BUILD_FOR_LINUX_ARM")
env == "1" || env == "true"
end
if System.otp_release() >= "23" do
defp tls_options, do: [versions: :ssl.versions()[:supported]]
else
defp tls_options do
[
depth: 4,
ciphers: ciphers(),
honor_cipher_order: :undefined
]
end
if System.otp_release() >= "20.3" do
defp ciphers, do: :ssl.cipher_suites(:default, :"tlsv1.2")
else
defp ciphers, do: :ssl.cipher_suites()
end
end
if System.otp_release() >= "21" do
defp customize_hostname_check_or_verify_fun do
[
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
end
else
defp customize_hostname_check_or_verify_fun do
[
verify_fun:
{fn
_, :valid, state -> {:valid, state}
_, :valid_peer, state -> {:valid, state}
_, {:extension, _}, state -> {:unknown, state}
_, reason, _ -> {:fail, reason}
end, self()}
]
end
end
def root? do
@root_checker.root?()
end
defp serialize_report_value(value) when is_binary(value), do: value
defp serialize_report_value(value), do: inspect(value)
end
defmodule Mix.Appsignal.Helper.DownloadCache do
def exists?(path), do: File.exists?(path)
def write(path, body), do: File.write(path, body)
def read!(path), do: File.read!(path)
end
defmodule Mix.Appsignal.Helper.ExtensionDir do
def prepare!(dir) do
File.mkdir_p!(dir)
dir |> Path.join("*appsignal*") |> Path.wildcard() |> Enum.each(&File.rm_rf!/1)
end
end
defmodule Mix.Appsignal.Helper.ReportWriter do
def write_install_report(report), do: write("install", report)
def write_download_report(report), do: write("download", report)
defp write(file, report) do
dir = Mix.Appsignal.Helper.priv_dir()
case Jason.encode(report) do
{:ok, body} ->
File.mkdir_p!(dir)
filename = "#{file}.report"
path = Path.join(dir, filename)
case File.open(path, [:write]) do
{:ok, io} ->
result = IO.binwrite(io, body)
File.close(io)
result
{:error, reason} ->
Mix.Shell.IO.error("""
Error: Could not write AppSignal installation report file (#{filename}).
#{serialize(reason)}
""")
{:error, reason}
end
{:error, reason} ->
Mix.Shell.IO.error("""
Error: Could not encode AppSignal installation report.
#{serialize(reason)}
""")
{:error, reason}
end
end
defp serialize(value) when is_binary(value), do: value
defp serialize(value), do: inspect(value)
end
defmodule Mix.Appsignal.Helper.CachedBuild do
def installed?(priv_dir, expected_version) do
Enum.all?(["appsignal-agent", "appsignal.h", "appsignal_extension.so"], fn file ->
priv_dir |> Path.join(file) |> File.exists?()
end) and version_matches?(priv_dir, expected_version)
end
defp version_matches?(priv_dir, expected_version) do
case File.read(Path.join(priv_dir, "appsignal.version")) do
{:ok, version} -> String.trim(version) == expected_version
{:error, _} -> false
end
end
end
defmodule Mix.Appsignal.Helper.Extractor do
def extract(filename, dir) do
case System.cmd("tar", ["zxf", filename, "--no-same-owner"],
stderr_to_stdout: true,
cd: dir
) do
{_, 0} ->
:ok
{result, _code} ->
IO.binwrite(result)
{:error, "Extracting of #{filename} failed!"}
end
end
end
defmodule Mix.Appsignal.Helper.Make do
def run(env) do
try do
System.cmd(executable(), args(env), stderr_to_stdout: true)
rescue
reason -> {inspect(reason), 1}
end
end
defp executable, do: if(System.find_executable("gmake"), do: "gmake", else: "make")
defp args("test" <> _), do: ["-e", "CFLAGS_ADD=-DTEST"]
defp args(_), do: []
end
defmodule Mix.Appsignal.Helper.InstalledVersion do
def read(priv_dir) do
case File.read(Path.join(priv_dir, "appsignal.version")) do
{:ok, version} -> {:ok, String.trim(version)}
{:error, reason} -> {:error, reason}
end
end
end
defmodule Mix.Appsignal.Helper.Ldd do
def version_output do
case System.cmd("ldd", ["--version"], stderr_to_stdout: true) do
{output, _} -> {:ok, output}
end
rescue
exception -> {:error, exception}
end
end
defmodule Mix.Appsignal.Helper.Root do
def root? do
try do
case System.cmd("id", ["-u"]) do
{id, 0} ->
case Integer.parse(List.first(String.split(id, "\n"))) do
{0, _} -> true
_ -> false
end
_ ->
false
end
catch
:error, _ -> false
end
end
end