Skip to content

Commit 5566e0b

Browse files
committed
Move to template
1 parent 9d026bf commit 5566e0b

File tree

4 files changed

+156
-112
lines changed

4 files changed

+156
-112
lines changed

lib/diff/hex/hex.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ defmodule Diff.Hex do
102102
with {_, true} <- {:file_size_old, file_size_check?(path_old)},
103103
{_, true} <- {:file_size_new, file_size_check?(path_new)},
104104
{_, {:ok, output}} <- {:git_diff, git_diff(path_old, path_new)} do
105-
# Store raw git diff output with base paths for relative conversion
106105
if output do
107106
[{:ok, {output, path_from, path_to}}]
108107
else

lib/diff_web/live/diff_live_view.ex

Lines changed: 1 addition & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,7 @@ defmodule DiffWeb.DiffLiveView do
44
require Logger
55

66
def render(assigns) do
7-
~H"""
8-
<%= if assigns[:error] do %>
9-
<div class="message-container">
10-
<h2 class="message">Error</h2>
11-
<p><%= @error %></p>
12-
</div>
13-
<% else %>
14-
<%= if assigns[:view_mode] == :diffs_list do %>
15-
<div class="search-area">
16-
<h1 class="package-header">Package Diffs</h1>
17-
<div>
18-
<%= for {package, from, to, url} <- @diffs do %>
19-
<div>
20-
<a href={url} class="package-name">
21-
<%= package %> (<%= from %><%= to %>)
22-
</a>
23-
</div>
24-
<% end %>
25-
</div>
26-
</div>
27-
<% else %>
28-
<div class="search-area">
29-
<div class="diff-stats-header">
30-
<span class="files-changed"><%= @metadata.files_changed %> files changed</span>
31-
<span class="additions">+<%= @metadata.total_additions %></span>
32-
<span class="deletions">-<%= @metadata.total_deletions %></span>
33-
</div>
34-
</div>
35-
36-
<%= if @generating do %>
37-
<div class="message-container">
38-
<div class="message">Generating diff patches...</div>
39-
</div>
40-
<% end %>
41-
42-
<%= if @loading do %>
43-
<div class="message-container">
44-
<div class="message">Loading patches...</div>
45-
</div>
46-
<% end %>
47-
48-
49-
50-
<div class="ghd-container" id="patch-list">
51-
<%= for patch_id <- @loaded_patches do %>
52-
<div id={"patch-#{patch_id}"}>
53-
<%= raw(load_patch_content(@package, @from, @to, patch_id)) %>
54-
</div>
55-
<% end %>
56-
57-
<%= if @has_more_patches do %>
58-
<div id="loading-trigger" phx-hook="InfiniteScroll" data-loaded={length(@loaded_patches)}>
59-
Loading more patches...
60-
</div>
61-
<% end %>
62-
</div>
63-
<% end %>
64-
<% end %>
65-
"""
7+
Phoenix.View.render(DiffWeb.LiveView, "diff.html", assigns)
668
end
679

6810
# Mount for single diff view
@@ -430,58 +372,6 @@ defmodule DiffWeb.DiffLiveView do
430372
_ -> nil
431373
end
432374

433-
defp load_patch_content(package, from, to, patch_id) do
434-
case Diff.Storage.get_patch(package, from, to, patch_id) do
435-
{:ok, raw_content} ->
436-
# Parse the stored content based on format
437-
case Jason.decode(raw_content) do
438-
{:ok, %{"type" => "too_large", "file" => file_path}} ->
439-
# Handle legacy too_large patches
440-
Phoenix.View.render_to_string(DiffWeb.RenderView, "too_large.html", file: file_path)
441-
|> sanitize_utf8()
442-
443-
{:ok, %{"diff" => raw_diff, "path_from" => path_from, "path_to" => path_to}} ->
444-
# Handle new format with raw diff and base paths for relative conversion
445-
case GitDiff.parse_patch(raw_diff, relative_from: path_from, relative_to: path_to) do
446-
{:ok, []} ->
447-
"<div class='patch-info'>No changes in patch</div>"
448-
449-
{:ok, patches} ->
450-
# Take the first patch (should only be one per file)
451-
patch = List.first(patches)
452-
453-
Phoenix.View.render_to_string(DiffWeb.RenderView, "patch.html", patch: patch)
454-
|> sanitize_utf8()
455-
456-
{:error, reason} ->
457-
Logger.error("Failed to parse patch #{patch_id}: #{inspect(reason)}")
458-
"<div class='patch-error'>Failed to parse patch</div>"
459-
end
460-
461-
_ ->
462-
# Fallback: try parsing as raw diff without relative paths (legacy raw format)
463-
case GitDiff.parse_patch(raw_content) do
464-
{:ok, []} ->
465-
"<div class='patch-info'>No changes in patch</div>"
466-
467-
{:ok, patches} ->
468-
# Take the first patch (should only be one per file)
469-
patch = List.first(patches)
470-
471-
Phoenix.View.render_to_string(DiffWeb.RenderView, "patch.html", patch: patch)
472-
|> sanitize_utf8()
473-
474-
{:error, reason} ->
475-
Logger.error("Failed to parse patch #{patch_id}: #{inspect(reason)}")
476-
"<div class='patch-error'>Failed to parse patch</div>"
477-
end
478-
end
479-
480-
{:error, _reason} ->
481-
"<div class='patch-error'>Failed to load patch</div>"
482-
end
483-
end
484-
485375
defp parse_diff(diff) do
486376
case String.split(diff, ":", trim: true) do
487377
[app, from, to] -> {app, from, to, build_url(app, from, to)}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<%= if assigns[:error] do %>
2+
<div class="message-container">
3+
<h2 class="message">Error</h2>
4+
<p><%= @error %></p>
5+
</div>
6+
<% else %>
7+
<%= if assigns[:view_mode] == :diffs_list do %>
8+
<div class="search-area">
9+
<h1 class="package-header">Package Diffs</h1>
10+
<div>
11+
<%= for {package, from, to, url} <- @diffs do %>
12+
<div>
13+
<a href="<%= url %>" class="package-name">
14+
<%= package %> (<%= from %><%= to %>)
15+
</a>
16+
</div>
17+
<% end %>
18+
</div>
19+
</div>
20+
<% else %>
21+
<div class="search-area">
22+
<div class="diff-stats-header">
23+
<span class="files-changed"><%= @metadata.files_changed %> files changed</span>
24+
<span class="additions">+<%= @metadata.total_additions %></span>
25+
<span class="deletions">-<%= @metadata.total_deletions %></span>
26+
</div>
27+
</div>
28+
29+
<%= if @generating do %>
30+
<div class="message-container">
31+
<div class="message">Generating diff patches...</div>
32+
</div>
33+
<% end %>
34+
35+
<%= if @loading do %>
36+
<div class="message-container">
37+
<div class="message">Loading patches...</div>
38+
</div>
39+
<% end %>
40+
41+
<div class="ghd-container" id="patch-list">
42+
<%= for patch_id <- @loaded_patches do %>
43+
<div id="patch-<%= patch_id %>">
44+
<%= raw(load_patch_content(@package, @from, @to, patch_id)) %>
45+
</div>
46+
<% end %>
47+
48+
<%= if @has_more_patches do %>
49+
<div id="loading-trigger" phx-hook="InfiniteScroll" data-loaded="<%= length(@loaded_patches) %>">
50+
Loading more patches...
51+
</div>
52+
<% end %>
53+
</div>
54+
<% end %>
55+
<% end %>

lib/diff_web/views/live_view.ex

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
defmodule DiffWeb.LiveView do
2+
use DiffWeb, :view
3+
require Logger
4+
5+
def load_patch_content(package, from, to, patch_id) do
6+
case Diff.Storage.get_patch(package, from, to, patch_id) do
7+
{:ok, raw_content} ->
8+
# Parse the stored content based on format
9+
case Jason.decode(raw_content) do
10+
{:ok, %{"type" => "too_large", "file" => file_path}} ->
11+
# Handle legacy too_large patches
12+
Phoenix.View.render_to_string(DiffWeb.RenderView, "too_large.html", file: file_path)
13+
|> sanitize_utf8()
14+
15+
{:ok, %{"diff" => raw_diff, "path_from" => path_from, "path_to" => path_to}} ->
16+
# Handle new format with raw diff and base paths for relative conversion
17+
case GitDiff.parse_patch(raw_diff, relative_from: path_from, relative_to: path_to) do
18+
{:ok, []} ->
19+
"<div class='patch-info'>No changes in patch</div>"
20+
21+
{:ok, patches} ->
22+
# Take the first patch (should only be one per file)
23+
patch = List.first(patches)
24+
25+
Phoenix.View.render_to_string(DiffWeb.RenderView, "patch.html", patch: patch)
26+
|> sanitize_utf8()
27+
28+
{:error, reason} ->
29+
Logger.error("Failed to parse patch #{patch_id}: #{inspect(reason)}")
30+
"<div class='patch-error'>Failed to parse patch</div>"
31+
end
32+
33+
_ ->
34+
# Fallback: try parsing as raw diff without relative paths (legacy raw format)
35+
case GitDiff.parse_patch(raw_content) do
36+
{:ok, []} ->
37+
"<div class='patch-info'>No changes in patch</div>"
38+
39+
{:ok, patches} ->
40+
# Take the first patch (should only be one per file)
41+
patch = List.first(patches)
42+
43+
Phoenix.View.render_to_string(DiffWeb.RenderView, "patch.html", patch: patch)
44+
|> sanitize_utf8()
45+
46+
{:error, reason} ->
47+
Logger.error("Failed to parse patch #{patch_id}: #{inspect(reason)}")
48+
"<div class='patch-error'>Failed to parse patch</div>"
49+
end
50+
end
51+
52+
{:error, _reason} ->
53+
"<div class='patch-error'>Failed to load patch</div>"
54+
end
55+
end
56+
57+
defp sanitize_utf8(content) when is_binary(content) do
58+
case String.valid?(content) do
59+
true ->
60+
content
61+
62+
false ->
63+
# Multiple fallback strategies for invalid UTF-8
64+
content
65+
|> sanitize_invalid_bytes()
66+
end
67+
end
68+
69+
defp sanitize_utf8(content), do: content
70+
71+
defp sanitize_invalid_bytes(content) do
72+
# Try different encoding conversions and fallbacks
73+
cond do
74+
# Try converting from common encodings
75+
latin1_result = safe_unicode_convert(content, :latin1, :utf8) ->
76+
latin1_result
77+
78+
# Try converting from ISO-8859-1
79+
iso_result = safe_unicode_convert(content, {:encoding, :latin1}, :utf8) ->
80+
iso_result
81+
82+
# Last resort: replace invalid bytes with replacement character
83+
true ->
84+
content
85+
|> :binary.bin_to_list()
86+
# Replace high bytes with '?'
87+
|> Enum.map(fn byte -> if byte > 127, do: 63, else: byte end)
88+
|> :binary.list_to_bin()
89+
end
90+
end
91+
92+
defp safe_unicode_convert(content, from, to) do
93+
case :unicode.characters_to_binary(content, from, to) do
94+
result when is_binary(result) -> result
95+
_ -> nil
96+
end
97+
rescue
98+
_ -> nil
99+
end
100+
end

0 commit comments

Comments
 (0)