Current section

Files

Jump to
gen_dsl lib parser.ex
Raw

lib/parser.ex

defmodule GenDSL.Parser do
@moduledoc "Module to parse_blueprint custom DSL"
@file_path "sample_blueprint.ex"
@sections ~w(dependencies app pretasks generable_elements posttasks)s
@accepted_keys ~w(app dependencies pretasks generable_elements posttasks)a
@accepted_strings ~w(app dependencies pretasks generable_elements posttasks)s
# TODO: remove @file_path default value
def read_blueprint(blueprint_path \\ @file_path) do
case File.read(blueprint_path) do
{:ok, body} -> {:ok, parse_blueprint(body)}
{:error, reason} -> {:error, reason}
end
end
def parse_blueprint(blueprint) do
IO.puts("Parsing blueprint")
parse_blueprint = Jason.decode!(blueprint)
IO.inspect(parse_blueprint, label: "Parsed blueprint")
parse_blueprint
end
def process_blueprint(blueprint) do
IO.puts("Processing blueprint")
blueprint
|> Map.keys()
|> Enum.map(fn section_key ->
{section_key, process_section(blueprint[section_key], section_key)}
end)
|> Enum.into(%{})
end
def execute_blueprint(blueprint, get_deps) do
IO.puts("Executing blueprint")
# TODO: check if this loads all plugins
Mix.Task.load_all()
# blueprint
# |> Map.keys()
# |> Enum.each(fn section_key ->
# execute_section(blueprint[section_key], section_key)
# end)
# IO.inspect(blueprint, label: "Blueprint")
@sections
|> Enum.each(fn section ->
if Map.has_key?(blueprint, section) do
case section do
"dependencies" -> execute_section(blueprint[section], section, get_deps)
_ -> execute_section(blueprint[section], section)
end
end
end)
end
def process_section(section, "dependencies" = _type) do
section
|> Enum.map(fn depenency ->
{depenency["package"] |> String.to_atom(), depenency["version"]}
end)
end
def process_section(section, "app" = _type) do
IO.puts("Processing App")
element_tasks =
to_callbacks(section)
element_tasks
end
def process_section(section, "pretasks" = _type) do
IO.puts("Processing pretasks")
element_tasks =
section
|> Enum.map(fn generable_element ->
to_callbacks(generable_element)
end)
element_tasks
end
def process_section(section, "generable_elements" = _type) do
IO.puts("Processing generable elements")
element_tasks =
section
|> Enum.map(fn generable_element ->
to_callbacks(generable_element)
end)
element_tasks
end
def process_section(section, "posttasks" = _type) do
IO.puts("Processing posttasks")
section
post_tasks =
section
|> Enum.map(fn post_task ->
to_callbacks(post_task)
end)
post_tasks
end
def process_section(_section, _type) do
[]
end
# TODO: Add support for all section types
def execute_section(section, "dependencies" = _type, get_deps) do
IO.puts("Installing dependencies")
if get_deps do
section
|> Mix.install(consolidate_protocols: true)
end
end
def execute_section(section, "app" = _type) do
apply(
section["callback"],
[
section["arguments"]
]
)
end
def execute_section(section, "pretasks" = _type) do
section
# TODO: encapsulate this in a private function
|> Enum.each(fn generable_element ->
apply(
generable_element["callback"],
[
generable_element["arguments"]
]
)
end)
end
def execute_section(section, "generable_elements" = _type) do
section
# TODO: encapsulate this in a private function
|> Enum.each(fn generable_element ->
apply(
generable_element["callback"],
[
generable_element["arguments"]
]
)
end)
end
def execute_section(section, "posttasks" = _type) do
section
|> Enum.each(fn post_task ->
apply(
post_task["callback"],
[
post_task["arguments"]
]
)
end)
end
defp to_callbacks(element) do
apply(
String.to_existing_atom("Elixir.GenDSL.Model." <> element["type"]),
:to_task,
[
element
]
)
end
def sanitize_blueprint(blueprint) do
Map.take(blueprint, @accepted_keys ++ @accepted_strings)
|> Jason.encode!()
|> Jason.decode!(keys: :strings)
end
def add_prerequisites(tasks) do
prerequisites = %{
"pretasks" => [
%{
"type" => "Hex"
}
]
}
tasks
|> Map.merge(prerequisites)
end
def add_postrequisites(tasks, original_dir \\ nil) do
prerequisites = %{
"posttasks" => [
%{
"type" => "ReturnDir",
"dir" => original_dir
}
]
}
tasks
|> Map.merge(prerequisites)
end
end