Commit cbfd3cf441f6c03e55e80b211e675083e4927fe6

Thomas de Grivel 2022-01-09T11:17:50

git log, git show

diff --git a/lib/kmxgit/git_manager.ex b/lib/kmxgit/git_manager.ex
index 4a15702..c25c47d 100644
--- a/lib/kmxgit/git_manager.ex
+++ b/lib/kmxgit/git_manager.ex
@@ -179,9 +179,37 @@ defmodule Kmxgit.GitManager do
   end
 
   def log(repo, tree \\ nil) do
+    if tree do
+      log_(repo, [tree])
+    else
+      log_(repo, [])
+    end
+  end
+
+  defp ok_hd({:ok, list}), do: {:ok, hd(list)}
+  defp ok_hd(x), do: x
+
+  def log1(repo, tree \\ nil) do
+    if tree do
+      log_(repo, ["-1", tree])
+    else
+      log_(repo, ["-1"])
+    end
+    |> ok_hd()
+  end
+
+  def log1_file(repo, file, tree \\ nil) do
+    if tree do
+      log_(repo, ["-1", tree, "--", file])
+    else
+      log_(repo, ["-1", "--", file])
+    end
+    |> ok_hd()
+  end
+
+  defp log_(repo, args) do
     dir = git_dir(repo)
-    args = ["-C", dir, "log", "--format=%H %aI \"%an <%ae>\" %s"]
-    args = if tree, do: args ++ [tree], else: args
+    args = ["-C", dir, "log", "--format=%H %aI \"%an\" %s"] ++ args
     {out, status} = System.cmd("git", args, stderr_to_stdout: true)
     case status do
       0 ->
diff --git a/lib/kmxgit_web/controllers/repository_controller.ex b/lib/kmxgit_web/controllers/repository_controller.ex
index fe44706..f050732 100644
--- a/lib/kmxgit_web/controllers/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/repository_controller.ex
@@ -103,40 +103,14 @@ defmodule KmxgitWeb.RepositoryController do
     if repo && repo.public_access || Repository.member?(repo, current_user) do
       org = repo.organisation
       user = repo.user
-      git = setup_git(repo, branch || "master", path, conn)
+      git = setup_git(repo, branch || "master", path, conn, op)
       first_branch = case Enum.at(git.branches, 0) do
                        {first_branch, _} -> first_branch
                        nil -> nil
                      end
       branch1 = branch || first_branch
       if git.valid do
-        op = op || :tree
-        case op do
-          :blob ->
-            if (git.content) do
-              conn
-              |> put_resp_content_type("application/octet-stream")
-              |> put_resp_header("Content-Disposition", "attachment; filename=#{git.filename |> URI.encode()}")
-              |> resp(200, git.content)
-            else
-              not_found(conn)
-            end
-          :tree ->
-            conn
-            |> assign(:branch, branch1)
-            |> assign(:branch_url, Routes.repository_path(conn, :show, Repository.owner_slug(repo), Repository.splat(repo, if branch1 do ["_tree", branch1] else [] end)))
-            |> assign_current_organisation(org)
-            |> assign(:current_repository, repo)
-            |> assign(:git, git)
-            |> assign(:repo, repo)
-            |> assign(:members, Repository.members(repo))
-            |> assign(:owner, org || user)
-            |> assign(:path, path)
-            |> render("show.html")
-          x ->
-            IO.inspect({:unknown_op, x})
-            not_found(conn)
-        end
+        show_op(conn, op || :tree, branch1, git, org, path, repo, user)
       else
         IO.inspect(:invalid_git)
         not_found(conn)
@@ -166,9 +140,11 @@ defmodule KmxgitWeb.RepositoryController do
   defp get_op_branch_and_path(chunks) do
     if path = chunks |> Enum.at(1) do
       op = case path |> Enum.at(0) do
-             "_tree" -> :tree
              "_blob" -> :blob
-             _ -> nil
+             "_commit" -> :commit
+             "_log" -> :log
+             "_tree" -> :tree
+             x -> :unknown
            end
       if op do
         {_, rest} = chunks |> Enum.split(2)
@@ -188,28 +164,30 @@ defmodule KmxgitWeb.RepositoryController do
     end
   end
 
-  defp setup_git(repo, branch, path, conn) do
+  defp setup_git(repo, branch, path, conn, op) do
     %{branches: [],
       content: nil,
       content_html: nil,
       content_type: nil,
       filename: nil,
       files: [],
+      log1: nil,
       readme: [],
       status: "",
       valid: true}
-    |> git_put_branches(repo, conn)
+    |> git_put_branches(repo, conn, op)
     |> git_put_files(repo, branch, path, conn)
     |> git_put_content(repo, path)
     |> git_put_readme(repo)
+    |> git_put_log1(repo, branch, path)
   end
 
-  defp git_put_branches(git = %{valid: true}, repo, conn) do
+  defp git_put_branches(git = %{valid: true}, repo, conn, op) do
     case GitManager.branches(Repository.full_slug(repo)) do
       {:ok, branches} ->
         branches = branches
         |> Enum.map(fn b ->
-          url = Routes.repository_path(conn, :show, Repository.owner_slug(repo), Repository.splat(repo) ++ ["_tree", b])
+          url = Routes.repository_path(conn, :show, Repository.owner_slug(repo), Repository.splat(repo) ++ ["_#{op}", b])
           {b, url}
         end)
         %{git | branches: branches}
@@ -295,6 +273,73 @@ defmodule KmxgitWeb.RepositoryController do
     git
   end
 
+  defp git_put_log1(git, repo, branch, path) do
+    slug = Repository.full_slug(repo)
+    {:ok, log1} = if path && path != "" do
+      GitManager.log1_file(slug, path, branch)
+    else
+      GitManager.log1(slug, branch)
+    end
+    %{git | log1: log1}
+  end
+
+  defp git_log(git, repo, branch, path) do
+    slug = Repository.full_slug(repo)
+    {:ok, log} = if path && path != "" do
+      GitManager.log_file(slug, path, branch)
+    else
+      GitManager.log(slug, branch)
+    end
+    log
+  end
+
+  defp show_op(conn, :blob, branch, git, org, path, _repo, user) do
+    if (git.content) do
+      conn
+      |> put_resp_content_type("application/octet-stream")
+      |> put_resp_header("Content-Disposition", "attachment; filename=#{git.filename |> URI.encode()}")
+      |> resp(200, git.content)
+    else
+      not_found(conn)
+    end
+  end
+  defp show_op(conn, :commit, branch, git, org, path, repo, user) do
+    conn
+    |> assign(:commit, git.log1)
+    |> assign_current_organisation(org)
+    |> assign(:current_repository, repo)
+    |> assign(:repo, repo)
+    |> render("commit.html")
+  end
+  defp show_op(conn, :log, branch, git, org, path, repo, user) do
+    log = git_log(git, repo, branch, path)
+    conn
+    |> assign(:branch, branch)
+    |> assign(:branch_url, Routes.repository_path(conn, :show, Repository.owner_slug(repo), Repository.splat(repo, if branch do ["_log", branch] else [] end)))
+    |> assign_current_organisation(org)
+    |> assign(:current_repository, repo)
+    |> assign(:git, git)
+    |> assign(:log, log)
+    |> assign(:repo, repo)
+    |> render("log.html")
+  end
+  defp show_op(conn, :tree, branch, git, org, path, repo, user) do
+    conn
+    |> assign(:branch, branch)
+    |> assign(:branch_url, Routes.repository_path(conn, :show, Repository.owner_slug(repo), Repository.splat(repo, if branch do ["_tree", branch] else [] end)))
+    |> assign_current_organisation(org)
+    |> assign(:current_repository, repo)
+    |> assign(:git, git)
+    |> assign(:repo, repo)
+    |> assign(:members, Repository.members(repo))
+    |> assign(:owner, org || user)
+    |> assign(:path, path)
+    |> render("show.html")
+  end
+  defp show_op(conn, x, _branch, _git, _org, _path, _repo, _user) do
+    not_found(conn)
+  end
+
   def edit(conn, params) do
     current_user = conn.assigns.current_user
     slug = Enum.join(params["slug"], "/")
diff --git a/lib/kmxgit_web/templates/repository/commit.html.heex b/lib/kmxgit_web/templates/repository/commit.html.heex
new file mode 100644
index 0000000..fcec2ac
--- /dev/null
+++ b/lib/kmxgit_web/templates/repository/commit.html.heex
@@ -0,0 +1,26 @@
+<div class="container-fluid">
+
+  <div class="row">
+    <%= render("show_title.html", assigns) %>
+  </div>
+
+  <div class="row">
+    <hr/>
+    <h2>
+      <%= gettext("Commit") %>
+      <%= @commit.hash %>
+    </h2>
+
+    <div class="commit">
+      <div class="date">
+        <%= @commit.date |> String.replace("T", " ") |> String.replace("+", " +") %>
+      </div>
+      <div class="author">
+        <%= @commit.author %>
+      </div>
+      <div class="message" %>
+        <%= @commit.message %>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/lib/kmxgit_web/templates/repository/log.html.heex b/lib/kmxgit_web/templates/repository/log.html.heex
new file mode 100644
index 0000000..fb394ce
--- /dev/null
+++ b/lib/kmxgit_web/templates/repository/log.html.heex
@@ -0,0 +1,49 @@
+<div class="container-fluid">
+
+  <div class="row">
+    <div class="col">
+      <%= render("show_title.html", assigns) %>
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col">
+      <hr/>
+      <%= render("show_branch.html", assigns) %>
+
+      <hr/>
+      <h2>
+        <%= gettext("Log") %>
+      </h2>
+
+      <table class="table">
+        <thead>
+          <tr>
+            <th><%= gettext "Commit" %></th>
+            <th><%= gettext "Author" %></th>
+            <th><%= gettext "Date" %></th>
+            <th><%= gettext "Message" %></th>
+          </tr>
+        </thead>
+        <tbody>
+          <%= for commit <- @log do %>
+            <tr class="commit">
+              <td class="hash">
+                <%= link commit.hash, id: commit.hash, to: Routes.repository_path(@conn, :show, Repository.owner_slug(@repo), Repository.splat(@repo, ["_commit", @git.log1.hash])) %>
+              </td>
+              <td class="author">
+                <%= commit.author %>
+              </td>
+              <td class="date">
+                <%= commit.date |> String.replace("T", " ") |> String.replace("+", " +") %>
+              </td>
+              <td class="message" %>
+                <%= commit.message %>
+              </td>
+            </tr>
+          <% end %>
+        </tbody>
+      </table>
+    </div>
+  </div>
+</div>
diff --git a/lib/kmxgit_web/templates/repository/show.html.heex b/lib/kmxgit_web/templates/repository/show.html.heex
index 2c92d3c..28fd03c 100644
--- a/lib/kmxgit_web/templates/repository/show.html.heex
+++ b/lib/kmxgit_web/templates/repository/show.html.heex
@@ -14,7 +14,13 @@
       <hr/>
       <%= render("show_branch.html", assigns) %>
 
+      <hr/>
       <h2><%= @path %></h2>
+
+      <%= if @git.log1 do %>
+        <%= render("show_commit_message.html", assigns) %>
+      <% end %>
+
       <%= if @git.content do %>
         <hr/>
         <%= render("show_git_content.html", assigns) %>
diff --git a/lib/kmxgit_web/templates/repository/show_commit_message.html.heex b/lib/kmxgit_web/templates/repository/show_commit_message.html.heex
new file mode 100644
index 0000000..fe24b94
--- /dev/null
+++ b/lib/kmxgit_web/templates/repository/show_commit_message.html.heex
@@ -0,0 +1,13 @@
+<%= link to: Routes.repository_path(@conn, :show, Repository.owner_slug(@repo), Repository.splat(@repo, ["_log", @branch])) <> "##{@git.log1.hash}" do %>
+  <div class="log1">
+    <div class="date">
+      <%= @git.log1.date |> String.replace("T", " ") |> String.replace("+", " +") %>
+    </div>
+    <div class="author">
+      <%= @git.log1.author %>
+    </div>
+    <div class="message" %>
+      <%= @git.log1.message %>
+    </div>
+  </div>
+<% end %>
diff --git a/lib/kmxgit_web/templates/repository/show_git_content.html.heex b/lib/kmxgit_web/templates/repository/show_git_content.html.heex
index d9cb262..8ead8a8 100644
--- a/lib/kmxgit_web/templates/repository/show_git_content.html.heex
+++ b/lib/kmxgit_web/templates/repository/show_git_content.html.heex
@@ -1,4 +1,4 @@
-<h2><%= gettext("Content") %></h2>
+<h3><%= gettext("Content") %></h3>
 <%= if @git.content_html do %>
   <div class="content_html">
     <%= raw @git.content_html %>
diff --git a/lib/kmxgit_web/templates/repository/show_readmes.html.heex b/lib/kmxgit_web/templates/repository/show_readmes.html.heex
index a4f7e0b..4efc9fa 100644
--- a/lib/kmxgit_web/templates/repository/show_readmes.html.heex
+++ b/lib/kmxgit_web/templates/repository/show_readmes.html.heex
@@ -1,6 +1,6 @@
 <%= Enum.map @git.readme, fn readme -> %>
   <hr/>
-  <h2><%= readme.name %></h2>
+  <h3><%= readme.name %></h3>
   <div class="container-fluid file-content">
     <%= if readme.html do %>
       <%= raw readme.html %>
diff --git a/lib/pygmentize.ex b/lib/pygmentize.ex
index b233f8f..85e506d 100644
--- a/lib/pygmentize.ex
+++ b/lib/pygmentize.ex
@@ -6,7 +6,7 @@ defmodule Pygmentize do
   end
 
   def html(content, filename) do
-    dir = "#{System.tmp_dir}/#{random_string}"
+    dir = "#{System.tmp_dir()}/#{random_string()}"
     File.mkdir_p(dir)
     path = "#{dir}/#{filename}"
     File.write(path, content)
@@ -23,7 +23,7 @@ defmodule Pygmentize do
     ref = state.ref
     receive do
       {^port, {:data, msg}} ->
-        state = Map.put(state, content: [msg | state.content])
+        state = Map.put(state, :content, [msg | state.content])
         get_reply(port, state)
       {:DOWN, ^ref, :port, _port, :normal} ->
         Enum.reverse(state.output)