Fosi Fossil Service
Small teams. Open source. Built on Fossil.

CaaS / Lamina

Unified Management for Fossil Repositories

Public | Owner: CaaS | Default branch: trunk | Last update: 2026-10-25 00:41

Artifact 7f3e79ed14168f1c5e25394a87466cc38f7c4fbe97625e36801a77d107cfb341:


%%% Author: Niclas Axelsson <niclas@burbas.se>

-module(nova).
-moduledoc "Interface module for nova".

-include_lib("kernel/include/logger.hrl").

-export([
         get_main_app/0,
         get_apps/0,
         get_environment/0,
         get_env/2,
         set_env/2,
         use_stacktrace/1,
         format_stacktrace/1,
         detect_language/0
        ]).

-type state() :: any().
-export_type([state/0]).

%%--------------------------------------------------------------------
-doc "Returns the name of the main bw-application (The one that started everything)".
-spec get_main_app() -> {ok, Application :: atom()} | undefined.
get_main_app() ->
    application:get_env(nova, bootstrap_application).


%%--------------------------------------------------------------------
-doc "Returns a proplist with all nova applications and their prefix. This function is useful when calulating dynamic routes.".
-spec get_apps() -> [{App :: atom(), Prefix :: list()}].
get_apps() ->
    nova_router:compiled_apps().

%%--------------------------------------------------------------------
-doc "Returns which environment nova is started in. This fetches the environment-variable in sys.config for Nova and returns the value found. Defaults to: dev".
-spec get_environment() -> any().
get_environment() ->
    application:get_env(nova, environment, dev).

%%--------------------------------------------------------------------
-doc "Works as the regular application:get_env/3 but instead of giving a specific application we target the application that started nova.".
-spec get_env(Parameter :: atom(), Default :: any()) -> term() | undefined.
get_env(Parameter, Default) ->
    case get_main_app() of
        {ok, App} ->
            application:get_env(App, Parameter, Default);
        _ ->
            Default
    end.


%%--------------------------------------------------------------------
-doc "Sets an environment variable for the main application.".
-spec set_env(Key :: atom(), Value :: any()) -> ok | {error, main_app_not_found}.
set_env(Key, Value) ->
    case get_main_app() of
        {ok, App} ->
            application:set_env(App, Key, Value);
        _ ->
            {error, main_app_not_found}
    end.


%%--------------------------------------------------------------------
-doc "Enables or disables stacktraces. This is a global setting and affects all requests. If stacktraces are enabled, nova will try to print a stacktrace when an exception is thrown.".
-spec use_stacktrace(Enable :: boolean()) -> ok.
use_stacktrace(true) ->
    persistent_term:put(nova_use_stacktrace, true);
use_stacktrace(_) ->
    persistent_term:erase(nova_use_stacktrace).


%%--------------------------------------------------------------------
-doc "Formats a stacktrace into a list of maps. Each map contains the module, function, arity, file, and line number of the function call.".
-spec format_stacktrace(Stacktrace :: [{M :: atom(), F :: atom(), A :: integer(), Info :: list()}])
                       -> [map()].
format_stacktrace(Stacktrace) ->
    SingleFun = fun({M, F, A, Info}) ->
                        #{module => M,
                          function => F,
                          arity => A,
                          file => proplists:get_value(file, Info, <<"unknown">>),
                          line => proplists:get_value(line, Info, -1)}
                end,
    [SingleFun(S) || S <- Stacktrace].


%%--------------------------------------------------------------------
-doc "Detects the language Nova is running in. It checks for the presence of the Elixir and LFE modules, and returns the language.".
-spec detect_language() -> elixir | lfe | erlang.
detect_language() ->
    case {code:which('Elixir.System'), code:which(lfe_eval)} of
        {non_existing, non_existing} -> erlang;
        {_, non_existing}            -> elixir;
        {non_existing, _}            -> lfe;
        {_, _}                       -> elixir  % prefer Elixir if both are present
    end.

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/CaaS/Lamina

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.