# `MishkaInstaller.Installer.LibraryHandler`
[🔗](https://github.com/mishka-group/mishka_installer/blob/v0.1.14/lib/installer/library_handler.ex#L1)

This module provides programmers with a public APIs and helpers that allow them to
load a **pre-built** Elixir/Erlang library (its compiled `ebin`) into a running system.

> It also includes aids and tools that allow them to work with the library while it is running.

`MishkaInstaller.Installer.Installer` is also referred to as action and aggregator functions,
which is something that should be taken into consideration.

If you are unsure about the responsibilities of each function,
it is recommended that you utilise the `MishkaInstaller.Installer.Installer` module and its functions,
which consist of a collection of predefined strategies.

## Why only the `ebin`?

Compiling a library at runtime (`mix deps.get`/`deps.compile`/`compile`) **cannot** work in a
production `release`, because a release ships **no** `Mix`, **no** `Hex`, **no** project source
and **no** `_build` tree. So instead of compiling, this module loads the **already compiled**
artifacts (`ebin/*.beam` + `ebin/<app>.app`):

1. add the `ebin` directory to the code path (`Code.prepend_path/1`),
2. `Application.load/1` + `Application.ensure_all_started/1`.

> #### Restart consideration {: .info}
>
> The code path is held **in memory** by the Erlang code server and is **not** persisted across a
> restart. Only the files on disk and the `MishkaInstaller.Installer.Installer` Mnesia record
> survive. The path + load **must be replayed on every boot** (see
> `MishkaInstaller.Installer.CompileHandler`).

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.
>
> Loading a `.beam` is **running arbitrary code with full node privileges**; the BEAM has no
> sandbox. Only load artifacts from a trusted source, built for the **same** Erlang/OTP and
> Elixir as the host. Native code (`NIF`/port driver `.so`/`.dll`) is **not** portable across
> OS/architecture/ERTS.

# `app`

```elixir
@type app() :: MishkaInstaller.Installer.Installer.t() | map()
```

# `error_return`

```elixir
@type error_return() ::
  {:error, [%{action: atom(), field: atom(), message: String.t()}]}
```

# `okey_return`

```elixir
@type okey_return() :: {:ok, struct() | map() | binary() | [any()]}
```

# `application_ensure`

```elixir
@spec application_ensure(atom()) :: :ok | error_return()
```

Helper function to load an application and all its dependencies.

> It is idempotent: an already loaded application is treated as a success, so this is safe to
> call again on every boot when re-activating a previously installed library.

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.

## Example:

```elixir
application_ensure(:mishka_developer_tools)
```

# `extensions_path`

```elixir
@spec extensions_path() :: Path.t()
```

Helper function to get the path where the pre-built runtime libraries (extensions) are stored.

> It defaults to `deployment/<env>/extensions` under the project path and can be overridden with
> the `:extensions_path` **application env** so a production release can point it at a **writable**
> volume outside the (read-only) release directory.

## Example:

```elixir
extensions_path()
```

# `extract`

```elixir
@spec extract(:tar, binary(), String.t()) :: :ok | error_return()
```

Extracts a downloaded **pre-built** artifact (a `tar.gz` whose content is a compiled `ebin`)
into the extensions directory under the canonical `name` (e.g. `"<app>-<version>"`).

The archive may contain `ebin/...` at its top level or nested one directory deep
(for example `<app>-<version>/ebin/...`). Nothing is compiled here.

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.

## Example:

```elixir
extract(:tar, tar_gz_binary, "elixir_uuid-1.2.1")
```

# `prepend_compiled_apps`

```elixir
@spec prepend_compiled_apps([tuple()]) :: :ok | error_return()
```

By means of this helper function, identify the paths of dependencies to the Erlang VM.

For more information see `Code.prepend_path/1`.

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.

## Example:

```elixir
files_list = [
  decimal: "/_build/dev/lib/decimal/ebin",
  ecto: "/_build/dev/lib/ecto/ebin",
  uniq: "/_build/dev/lib/uniq/ebin"
]

prepend_compiled_apps(files_list)
```

# `read_app`

```elixir
@spec read_app(atom(), Path.t()) :: {:ok, any()} | error_return()
```

Helper function to read Erlang `.app` file in Elixir.

Reads the given app from path in an optimized format and returns its contents.

Based on:
https://github.com/elixir-lang/elixir/blob/f0fcd64f937af8ccdd98e086c107c3902485d404/lib/mix/lib/mix/app_loader.ex#L59-L75

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.

## Example:

```elixir
read_app(:mishka_developer_tools, app_bin_path)
```

# `unload`

```elixir
@spec unload(atom()) :: :ok | error_return()
```

Helper function to unload an application.

> #### Security considerations {: .warning}
>
> It is important to remember that all of the functionalities contained within this
> section must be implemented at the **high access level**, and they should not directly take
> any input from the user. Ensure that you include the required safety measures.

## Example:

```elixir
unload(:mishka_developer_tools)
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
