~mika/www.m1kadev.nl

bce19303cd873fea1ee082f7c87b407300d38e23 — m1kadev 6 months ago 1c5e50a
kethel: add support for pages/
8 files changed, 62 insertions(+), 31 deletions(-)

M kethel/lib/bricks.ex
A kethel/lib/common.ex
D kethel/lib/compilers.ex
D kethel/lib/kernelx.ex
M kethel/lib/pages.ex
M kethel/main.exs
M kethel/mix.exs
M kethel/mix.lock
M kethel/lib/bricks.ex => kethel/lib/bricks.ex +2 -3
@@ 8,10 8,9 @@ defmodule Bricks do
  @typedoc "A valid mustache template"
  @type mustache() :: binary()

  @spec collect(relative_path()) :: [ { brick_name(), mustache() } ]
  @spec collect(relative_path()) :: %{ brick_name() => mustache() }
  def collect(folder) do
    Path.wildcard(folder <> "/bricks/*.thtml")
      |> Enum.map(fn brick -> { brick, File.read!(brick) } end) 
      |> Enum.map(fn { brick, contents } -> { FileX.trimmed_filename(brick), contents } end) # "../bricks/base_header.html" would beccome just "base_header"
      |> Map.new(fn x -> { FileX.trimmed_filename(x), File.read!(x) } end)
  end
 end 

A kethel/lib/common.ex => kethel/lib/common.ex +3 -0
@@ 0,0 1,3 @@
defmodule Context do
  defstruct project_root: "/", bricks: %{}, fxg: "fxg"
end

D kethel/lib/compilers.ex => kethel/lib/compilers.ex +0 -12
@@ 1,12 0,0 @@
defmodule Compilers do
  # TODO
  @doc "Creates a random file in /tmp/kethel-TIME/, which functions as a pipe writing the given `data`"
  @spec tempdata(binary()) :: binary()
  defp tempdata(data) do
  end


  @doc "Invokes the fxg compiler on `data`. provides the output as a binary"
  def fxg(path) do
  end
end

D kethel/lib/kernelx.ex => kethel/lib/kernelx.ex +0 -8
@@ 1,8 0,0 @@
defmodule KernelX do

  @doc "Returns all bytes from `binary`, excluding those before `from`"
  @spec binary_slice_from(binary(), pos_integer()) :: binary()
  def binary_slice_from(binary, from) do
    binary_part(binary, from, byte_size(binary) - from)
  end
end

M kethel/lib/pages.ex => kethel/lib/pages.ex +44 -3
@@ 1,8 1,49 @@
require Rambo

defmodule Pages do
  defstruct [ :source_files, :main_template, :project_root, :bricks ]

  def trim_abs_path(path, context) do
    begin = byte_size(context.project_root) + byte_size("pages/") # ROOT + pages/ 
    binary_part(path, begin, byte_size(path) - begin - byte_size(".fxg")) # remove extension
  end

  @spec collect(%Context{}) :: %Pages{}
  def collect(context) do
    pages_root = context.project_root <> "/pages"
    pages = Path.wildcard(pages_root <> "/**/*.fxg")
      |> Enum.map(fn path -> { path, File.read!(path) } end)
      |> Enum.map(fn { path, data } -> { KernelX.binary_slice_from(path, byte_size(pages_root)), data } end)
    %Pages{
      project_root: context.project_root,
      source_files: Path.wildcard(pages_root <> "/**/*.fxg")
        |> Enum.map(fn path -> { path, File.read!(path) } end)
        |> Enum.map(fn { path, data } -> { trim_abs_path(path, context), data } end),
      main_template: File.read!(context.project_root <> "/templates/base.thtml"),
      bricks: context.bricks,
    }
  end

  @spec compile(%Pages{}) :: none()
  def compile(pages) do
    Task.async_stream(pages.source_files, fn page -> compile_file(pages, page) end) |> Enum.to_list()
  end

  defp compile_file(pages, { page_path, page_data }) do
    output_path = "#{pages.project_root}/build#{page_path}.html"
    IO.puts("#{pages.project_root}/pages#{page_path}.fxg -> #{output_path}")
    # check for a custom template
    custom_template_path = "#{pages.project_root}/templates/pages#{page_path}.thtml"
    template = case File.read(custom_template_path) do
      {:ok, custom_template} -> custom_template
      {:error, :enoent} -> pages.main_template
      {:error, err } -> raise err
    end
    mustache_context = Map.merge(%{fxg_content: invoke_fxg(page_data), location: page_path}, pages.bricks)
    page_rendered = Mustache.render(template, mustache_context)
    File.write!(output_path, page_rendered)
  end

  # TODO: switch this to Rambo
  defp invoke_fxg(data) do
    {:ok, res} = Rambo.run("fxg", ["-"], in: data)
    res.out
  end
end

M kethel/main.exs => kethel/main.exs +10 -3
@@ 4,11 4,18 @@ folder = Enum.at(args, 1)

if folder != nil do
  project_root = Path.expand(folder) 
  context = %{
   project_root: project_root,
   bricks: Bricks.collect(project_root)
  context = %Context{
    project_root: project_root,
    bricks: Bricks.collect(project_root),
    fxg: System.find_executable("fxg")
  }
  
  File.rm_rf!("#{project_root}/build")
  File.mkdir_p("#{project_root}/build")

  pages = Pages.collect(context)

  Pages.compile(pages)
else
  IO.puts(:stderr, "The root project folder should be provided on the command line")
end

M kethel/mix.exs => kethel/mix.exs +2 -2
@@ 13,8 13,8 @@ defmodule Kethel.MixProject do

  defp deps do
    [
      { :tzdata, "~> 1.1" },
      { :mustache, "~> 0.5.0" }
      { :mustache, "~> 0.5.0" },
      {:rambo, "~> 0.3.4" },
    ]
  end
end

M kethel/mix.lock => kethel/mix.lock +1 -0
@@ 6,6 6,7 @@
  "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"},
  "mustache": {:hex, :mustache, "0.5.1", "1bfee8a68a8e72d47616541a93a632ae1684c1abc17c9eb5f7bfecb78d7496e5", [:mix], [], "hexpm", "524c9bbb6080a52d7b6806436b4e269e0224c785a228faf3293ef30a75016bfa"},
  "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
  "rambo": {:hex, :rambo, "0.3.4", "8962ac3bd1a633ee9d0e8b44373c7913e3ce3d875b4151dcd060886092d2dce7", [:mix], [], "hexpm", "0cc54ed089fbbc84b65f4b8a774224ebfe60e5c80186fafc7910b3e379ad58f1"},
  "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
  "tzdata": {:hex, :tzdata, "1.1.3", "b1cef7bb6de1de90d4ddc25d33892b32830f907e7fc2fccd1e7e22778ab7dfbc", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d4ca85575a064d29d4e94253ee95912edfb165938743dbf002acdf0dcecb0c28"},
  "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},