~mika/www.m1kadev.nl

ref: 3020fb369cb40b7ea2971099dbce6ac6b9eca69a www.m1kadev.nl/kethel/lib/thoughts.ex -rw-r--r-- 3.4 KiB
3020fb36 — m1kadev kethel: final touches 5 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
defmodule Thoughts do
  defstruct [:thoughts, :template, :bricks, :project_root, :index_template, :inline_template ]

  @spec urlify(binary()) :: binary()
  defp urlify(name) do
    name
    |> String.replace(" ", "_")
  end

  @spec trim_abs_path(binary(), binary()) :: binary()
  defp trim_abs_path(path, project_root) do
    # ROOT + thoughts/
    begin = byte_size(project_root) + byte_size("/thoughts/")
    binary_part(path, begin, byte_size(path) - begin)
  end

  @spec collect(binary(), %{binary() => binary()}) :: %Thoughts{}
  def collect(project_root, bricks) do
    %Thoughts{
      thoughts:
        Path.wildcard("#{project_root}/thoughts/*")
        |> Enum.map(fn path -> {path, get_file_commit_date(path), File.read!(path)} end)
        |> Enum.sort_by(fn {_, date, _ } -> date end, :desc),
      inline_template: File.read!("#{project_root}/templates/inline_thought.thtml"),
      template: File.read!("#{project_root}/templates/thought.thtml"),
      index_template: File.read!("#{project_root}/templates/thoughts.thtml"),
      bricks: bricks,
      project_root: project_root
    }
  end

  @spec ensure_folders(binary()) :: :ok
  def ensure_folders(project_root) do
    File.mkdir_p!("#{project_root}/build/thoughts/")
  end

  @spec compile(%Thoughts{}) :: pos_integer()
  def compile(thoughts) do
    t_begin = System.monotonic_time(:millisecond)
    ensure_folders(thoughts.project_root)

    thoughts.thoughts
    |> Task.async_stream(fn thought ->
      compile_file(thought, thoughts.template, thoughts.bricks, thoughts.project_root) end)
    |> Enum.to_list()

    # generate index
    index_content = thoughts.thoughts
      |> Enum.map(fn thought -> inline_thought(thought, thoughts) end)
      |> Enum.join()
    index = Mustache.render(thoughts.index_template, Map.merge(thoughts.bricks, %{fxg_content: index_content}))
    File.write!("#{thoughts.project_root}/build/thoughts/index.html", index)
    IO.puts("[COMPILED] #{thoughts.project_root}/build/thoughts/index.html")

    t_end = System.monotonic_time(:millisecond)
    t_end - t_begin
  end

  defp inline_thought({path, date, thought}, context) do
    stripped_name = String.replace_prefix(path, "#{context.project_root}/thoughts/", "")
    location = "https://m1kadev.nl/thoughts/#{urlify(stripped_name)}.html"
    title = "<a href=\"#{location}\">#{stripped_name}</a>"
    Mustache.render(context.inline_template, %{name: title, date: date, thought: thought})
  end

  defp compile_file({path, date, thought}, template, bricks, project_root) do
    name = trim_abs_path(path, project_root)
    output_path = "#{project_root}/build/thoughts/#{urlify(name)}.html"
    mustache_context = Map.merge(bricks, %{thought: thought, name: name, date: date})

    File.write!(output_path, Mustache.render(template, mustache_context))
    IO.puts("[COMPILED] #{path} -> #{output_path}")
  end

  def get_file_commit_date(path) do
    {ts_string, 0} = System.cmd("git", ["log", "--format=%ct", path])
    String.trim_trailing(ts_string)
      |> String.to_integer()
  end

  def to_rss({path, date, thought}, template, project_root) do
    location = String.replace_prefix(path, project_root <> "/thoughts/", "")
    link = "https://m1kadev.nl/thoughts/" <> urlify(location) <> ".html"
    rfc_date = date
      |> DateTime.from_unix!()
      |> Calendar.strftime("%a, %d %b %Y %H:%M:%S %Z")
    Mustache.render(template, %{title: location, date: rfc_date, description: thought, category: "thoughts", link: link } ) 
  end
end