Current section
Files
Jump to
Current section
Files
lib/serum/project/loader.ex
defmodule Serum.Project.Loader do
@moduledoc false
_moduledocp = "A module for loading Serum project definition files."
alias Serum.GlobalBindings
alias Serum.Project
alias Serum.Project.ElixirValidator
alias Serum.Result
alias Serum.Theme
@doc """
Detects and loads Serum project definition file from the source directory.
"""
@spec load(binary(), binary()) :: Result.t(Project.t())
def load(src, dest) do
case do_load(src) do
{:ok, %Project{} = proj} ->
GlobalBindings.put(:site, %{
name: proj.site_name,
description: proj.site_description,
author: proj.author,
author_email: proj.author_email,
server_root: proj.server_root,
base_url: proj.base_url
})
GlobalBindings.put(:project, proj)
{:ok, %Project{proj | src: src, dest: dest}}
{:error, _} = error ->
error
end
end
@spec do_load(binary()) :: Result.t(Project.t())
defp do_load(src) do
exs_path = Path.join(src, "serum.exs")
if File.exists?(exs_path) do
load_exs(exs_path)
else
{:error, {:enoent, exs_path, 0}}
end
end
@spec load_exs(binary()) :: Result.t(Project.t())
defp load_exs(exs_path) do
with {:ok, data} <- File.read(exs_path),
{map, _} <- Code.eval_string(data, [], file: exs_path),
:ok <- ElixirValidator.validate(map) do
{:ok, Project.new(Map.put(map, :theme, %Theme{module: map[:theme]}))}
else
# From File.read/1:
{:error, reason} when is_atom(reason) ->
{:error, {reason, exs_path, 0}}
# From ElixirValidator.validate/2:
{:invalid, message} when is_binary(message) ->
{:error, {message, exs_path, 0}}
{:invalid, messages} when is_list(messages) ->
sub_errors =
Enum.map(messages, fn message ->
{:error, {message, exs_path, 0}}
end)
{:error, {:project_validator, sub_errors}}
end
rescue
e in [CompileError, SyntaxError, TokenMissingError] ->
{:error, {e.description, e.file, e.line}}
e ->
err_name =
e.__struct__
|> to_string()
|> String.replace_prefix("Elixir.", "")
err_msg = "#{err_name} while evaluating: #{Exception.message(e)}"
{:error, {err_msg, exs_path, 0}}
end
end