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):
- add the
ebindirectory to the code path (Code.prepend_path/1), Application.load/1+Application.ensure_all_started/1.
Restart consideration
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
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.
Summary
Functions
Helper function to load an application and all its dependencies.
Helper function to get the path where the pre-built runtime libraries (extensions) are stored.
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>").
By means of this helper function, identify the paths of dependencies to the Erlang VM.
Helper function to read Erlang .app file in Elixir.
Helper function to unload an application.
Types
Functions
@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
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:
application_ensure(:mishka_developer_tools)
@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>/extensionsunder the project path and can be overridden with the:extensions_pathapplication env so a production release can point it at a writable volume outside the (read-only) release directory.
Example:
extensions_path()
@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
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:
extract(:tar, tar_gz_binary, "elixir_uuid-1.2.1")
@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
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:
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)
@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.
Security considerations
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:
read_app(:mishka_developer_tools, app_bin_path)
@spec unload(atom()) :: :ok | error_return()
Helper function to unload an application.
Security considerations
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:
unload(:mishka_developer_tools)