Current section
Files
Jump to
Current section
Files
ockam_vault_software
mix.exs
mix.exs
defmodule Ockam.Vault.Software.MixProject do
use Mix.Project
@version "0.62.0"
@elixir_requirement "~> 1.12"
@ockam_release_url "https://github.com/build-trust/ockam/releases"
@download_libs [
{"ockam.linux_elixir_ffi.so", ["linux_x86_64_gnu", "native", "libockam_elixir_ffi.so"]},
{"ockam.darwin_universal_elixir_ffi.so",
["darwin_universal", "native", "libockam_elixir_ffi.so"]}
]
@ockam_github_repo "https://github.com/build-trust/ockam"
@ockam_github_repo_path "implementations/elixir/ockam/ockam_vault_software"
def project do
[
app: :ockam_vault_software,
version: package_version(),
elixir: @elixir_requirement,
consolidate_protocols: Mix.env() != :test,
elixirc_options: [warnings_as_errors: true],
deps: deps(),
aliases: aliases(),
# lint
dialyzer: [flags: ["-Wunmatched_returns", :underspecs]],
# test
test_coverage: [output: "_build/cover"],
preferred_cli_env: ["test.cover": :test],
# hex
description: "A software implementation of the ockam vault behaviour.",
package: package(),
# docs
name: "Ockam Vault Software",
docs: docs()
]
end
# mix help compile.app for more
def application do
[
mod: {Ockam.Vault.Software, []},
extra_applications: []
]
end
defp deps do
[
{:ex_doc, "~> 0.25", only: :dev, runtime: false},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.1", only: [:dev], runtime: false}
]
end
# used by hex
defp package do
[
links: %{"GitHub" => @ockam_github_repo},
licenses: ["Apache-2.0"],
source_url: @ockam_github_repo
]
end
# used by ex_doc
defp docs do
[
main: "Ockam.Vault.Software",
source_url_pattern:
"#{@ockam_github_repo}/blob/v#{package_version()}/#{@ockam_github_repo_path}/%{path}#L%{line}"
]
end
defp aliases do
[
"check.native": &check_native/1,
"download.native": &download_native/1,
"recompile.native": &recompile_native/1,
"clean.native": &clean_native/1,
"hex.build": ["download.native --version=#{package_version()}", "hex.build"],
"hex.publish": ["download.native --version=#{package_version()}", "hex.publish"],
compile: ["check.native", "compile"],
clean: ["clean", "clean.native"],
docs: "docs --output _build/docs --formatter html",
"test.cover": "test --no-start --cover",
"lint.format": "format --check-formatted",
"lint.credo": "credo --strict",
"lint.dialyzer": "dialyzer --format dialyxir",
lint: ["lint.format", "lint.credo"]
]
end
defp native_build_path(), do: Path.join([Mix.Project.build_path(), "native"])
defp native_priv_path() do
Path.join([Mix.Project.app_path(), "priv", "native"])
end
defp check_native(args) do
case test_recompile?() do
true ->
recompile_native(args)
_ ->
case prebuilt_lib_exists?() do
true -> :ok
false -> download_native(args)
end
end
end
defp download_native(args) do
version_path =
case ockam_version(args) do
"latest" -> "/latest/download"
other -> "/download/ockam_" <> other
end
base_url = @ockam_release_url <> version_path
## To donwload files we need inets and ssl
:inets.start()
:ssl.start()
Enum.each(@download_libs, fn {from, to} ->
download_url = base_url <> "/" <> from
dest_path = ["priv" | to]
dest_file = Path.join(dest_path)
dest_dir = Path.join(Enum.take(dest_path, length(dest_path) - 1))
File.mkdir_p!(dest_dir)
IO.puts("Downloading lib from #{download_url} to #{dest_file}")
File.rm_rf(dest_file)
{:ok, :saved_to_file} =
:httpc.request(
:get,
{to_charlist(download_url), []},
[],
stream: to_charlist(dest_file)
)
end)
end
defp package_version() do
case System.get_env("VERSION") do
nil -> @version
version -> version
end
end
defp ockam_version(args) do
case OptionParser.parse(args, switches: [version: :string]) do
{[version: version], _, _} ->
"v" <> version
_ ->
case Mix.env() do
:dev -> "latest"
:prod -> "v" <> package_version()
end
end
end
defp test_recompile?() do
Mix.env() == :test and System.get_env("NO_RECOMPILE_NATIVE") != "true"
end
defp prebuilt_lib_exists?() do
case prebuilt_lib_path() do
{:ok, _path} -> true
_ -> false
end
end
defp prebuilt_lib_path() do
with {:ok, subdir} <- os_subdir() do
case Path.wildcard(Path.join(["priv", subdir, "native", "libockam_elixir_ffi.*"])) do
[] -> :error
[_file] -> {:ok, Path.join("priv", subdir)}
end
end
end
## NOTE: duplicate in vault_software.ex
## we need to run this both in compile-time and in runtime
defp os_subdir() do
case {:os.type(), to_string(:erlang.system_info(:system_architecture))} do
## Linux libs only built for GNU
{{:unix, :linux}, "x86_64" <> type} ->
if String.ends_with?(type, "gnu") do
{:ok, "linux_x86_64_gnu"}
else
:error
end
{{:unix, :linux}, "aarch64" <> type} ->
if String.ends_with?(type, "gnu") do
{:ok, "linux_aarch64_gnu"}
else
:error
end
## MacOS libs are multi-arch
{{:unix, :darwin}, "x86_64" <> _} ->
{:ok, "darwin_universal"}
{{:unix, :darwin}, "aarch64" <> _} ->
{:ok, "darwin_universal"}
_ ->
:error
end
end
defp recompile_native(args) do
clean_native(args)
:ok = cmake_generate()
:ok = cmake_build()
:ok = copy_to_priv()
:ok
end
defp clean_native(_) do
File.rm_rf!(native_build_path())
File.rm_rf!(native_priv_path())
end
defp cmake_generate() do
{_, 0} =
System.cmd(
"cmake",
[
"-S",
"native",
"-B",
native_build_path(),
"-DBUILD_SHARED_LIBS=ON",
"-DCMAKE_BUILD_TYPE=Release"
],
into: IO.stream(:stdio, :line),
env: [{"ERL_INCLUDE_DIR", erl_include_dir()}]
)
:ok
end
defp cmake_build() do
{_, 0} =
System.cmd(
"cmake",
["--build", native_build_path()],
into: IO.stream(:stdio, :line),
env: [{"ERL_INCLUDE_DIR", erl_include_dir()}]
)
:ok
end
defp erl_include_dir() do
[:code.root_dir(), Enum.concat('erts-', :erlang.system_info(:version)), 'include']
|> Path.join()
|> to_string
end
defp copy_to_priv() do
priv_path = native_priv_path()
File.mkdir_p!(priv_path)
Enum.each(["dylib", "so"], fn extension ->
Path.join([native_build_path(), "**", "*.#{extension}"])
|> Path.wildcard()
|> Enum.each(fn lib ->
filename = Path.basename(lib, ".#{extension}")
destination = Path.join(priv_path, "#{filename}.so")
File.cp!(lib, destination)
end)
end)
:ok
end
end