mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-26 21:36:02 +08:00
Fix file comparison (#2709)
This commit is contained in:
parent
e934b1763e
commit
0b69625987
9 changed files with 52 additions and 15 deletions
|
|
@ -77,6 +77,18 @@ defmodule Livebook.FileSystem.File do
|
||||||
{file.file_system_id, node, file.path}
|
{file.file_system_id, node, file.path}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Checks if two files are equal.
|
||||||
|
|
||||||
|
Comparing files with `Kernel.==/2` may result in false-negatives,
|
||||||
|
because the structs hold additional information.
|
||||||
|
"""
|
||||||
|
@spec equal?(t(), t()) :: boolean()
|
||||||
|
def equal?(file1, file2) do
|
||||||
|
file1.path == file2.path and file1.file_system_id == file2.file_system_id and
|
||||||
|
file1.file_system_module == file2.file_system_module
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Checks if the given file is within a file system local to its node.
|
Checks if the given file is within a file system local to its node.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ defmodule Livebook.NotebookManager do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_cast({:add_recent_notebook, file, name}, state = prev_state) do
|
def handle_cast({:add_recent_notebook, file, name}, state = prev_state) do
|
||||||
recent_notebooks = Enum.reject(state.recent_notebooks, &(&1.file == file))
|
recent_notebooks = Enum.reject(state.recent_notebooks, &FileSystem.File.equal?(&1.file, file))
|
||||||
|
|
||||||
recent_notebooks = [
|
recent_notebooks = [
|
||||||
%{file: file, name: name, added_at: DateTime.utc_now()} | recent_notebooks
|
%{file: file, name: name, added_at: DateTime.utc_now()} | recent_notebooks
|
||||||
|
|
@ -158,7 +158,7 @@ defmodule Livebook.NotebookManager do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast({:add_starred_notebook, file, name}, state = prev_state) do
|
def handle_cast({:add_starred_notebook, file, name}, state = prev_state) do
|
||||||
if Enum.any?(state.starred_notebooks, &(&1.file == file)) do
|
if Enum.any?(state.starred_notebooks, &FileSystem.File.equal?(&1.file, file)) do
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
else
|
else
|
||||||
starred_notebooks = [
|
starred_notebooks = [
|
||||||
|
|
@ -172,14 +172,16 @@ defmodule Livebook.NotebookManager do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast({:remove_recent_notebook, file}, state = prev_state) do
|
def handle_cast({:remove_recent_notebook, file}, state = prev_state) do
|
||||||
recent_notebooks = Enum.reject(state.recent_notebooks, &(&1.file == file))
|
recent_notebooks = Enum.reject(state.recent_notebooks, &FileSystem.File.equal?(&1.file, file))
|
||||||
state = %{state | recent_notebooks: recent_notebooks}
|
state = %{state | recent_notebooks: recent_notebooks}
|
||||||
broadcast_changes(state, prev_state)
|
broadcast_changes(state, prev_state)
|
||||||
{:noreply, state, {:continue, :dump_state}}
|
{:noreply, state, {:continue, :dump_state}}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_cast({:remove_starred_notebook, file}, state = prev_state) do
|
def handle_cast({:remove_starred_notebook, file}, state = prev_state) do
|
||||||
starred_notebooks = Enum.reject(state.starred_notebooks, &(&1.file == file))
|
starred_notebooks =
|
||||||
|
Enum.reject(state.starred_notebooks, &FileSystem.File.equal?(&1.file, file))
|
||||||
|
|
||||||
state = %{state | starred_notebooks: starred_notebooks}
|
state = %{state | starred_notebooks: starred_notebooks}
|
||||||
broadcast_changes(state, prev_state)
|
broadcast_changes(state, prev_state)
|
||||||
{:noreply, state, {:continue, :dump_state}}
|
{:noreply, state, {:continue, :dump_state}}
|
||||||
|
|
|
||||||
|
|
@ -689,11 +689,15 @@ defmodule LivebookWeb.FileSelectComponent do
|
||||||
unhighlighted: name,
|
unhighlighted: name,
|
||||||
file: file,
|
file: file,
|
||||||
is_dir: FileSystem.File.dir?(file),
|
is_dir: FileSystem.File.dir?(file),
|
||||||
is_running: file in running_files,
|
is_running: running?(file, running_files),
|
||||||
editable: Keyword.get(opts, :editable, true)
|
editable: Keyword.get(opts, :editable, true)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp running?(file, running_files) do
|
||||||
|
Enum.any?(running_files, &FileSystem.File.equal?(&1, file))
|
||||||
|
end
|
||||||
|
|
||||||
defp hidden?(filename) do
|
defp hidden?(filename) do
|
||||||
String.starts_with?(filename, ".")
|
String.starts_with?(filename, ".")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
defmodule LivebookWeb.NotebookCardsComponent do
|
defmodule LivebookWeb.NotebookCardsComponent do
|
||||||
use LivebookWeb, :live_component
|
use LivebookWeb, :live_component
|
||||||
|
|
||||||
|
alias Livebook.FileSystem
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
assigns = assign_new(assigns, :card_icon, fn -> nil end)
|
assigns = assign_new(assigns, :card_icon, fn -> nil end)
|
||||||
|
|
@ -72,10 +74,10 @@ defmodule LivebookWeb.NotebookCardsComponent do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp file_running?(file, sessions) do
|
defp file_running?(file, sessions) do
|
||||||
Enum.any?(sessions, &(&1.file == file))
|
Enum.any?(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp session_by_file(file, sessions) do
|
defp session_by_file(file, sessions) do
|
||||||
Enum.find(sessions, &(&1.file == file))
|
Enum.find(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -276,11 +276,11 @@ defmodule LivebookWeb.OpenLive do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp file_running?(file, sessions) do
|
defp file_running?(file, sessions) do
|
||||||
Enum.any?(sessions, &(&1.file == file))
|
Enum.any?(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp session_id_by_file(file, sessions) do
|
defp session_id_by_file(file, sessions) do
|
||||||
session = Enum.find(sessions, &(&1.file == file))
|
session = Enum.find(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
session.id
|
session.id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -112,14 +112,14 @@ defmodule LivebookWeb.OpenLive.FileComponent do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp file_running?(file, sessions) do
|
defp file_running?(file, sessions) do
|
||||||
Enum.any?(sessions, &(&1.file == file))
|
Enum.any?(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp files(sessions) do
|
defp files(sessions) do
|
||||||
Enum.map(sessions, & &1.file)
|
for session <- sessions, session.file, do: session.file
|
||||||
end
|
end
|
||||||
|
|
||||||
defp session_by_file(file, sessions) do
|
defp session_by_file(file, sessions) do
|
||||||
Enum.find(sessions, &(&1.file == file))
|
Enum.find(sessions, &(&1.file && FileSystem.File.equal?(&1.file, file)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ defmodule LivebookWeb.SessionLive.PersistenceComponent do
|
||||||
@impl true
|
@impl true
|
||||||
def mount(socket) do
|
def mount(socket) do
|
||||||
sessions = Sessions.list_sessions()
|
sessions = Sessions.list_sessions()
|
||||||
running_files = Enum.map(sessions, & &1.file)
|
running_files = for session <- sessions, session.file, do: session.file
|
||||||
{:ok, assign(socket, running_files: running_files)}
|
{:ok, assign(socket, running_files: running_files)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -212,7 +212,9 @@ defmodule LivebookWeb.SessionLive.PersistenceComponent do
|
||||||
|
|
||||||
defp savable?(draft_file, saved_file, running_files) do
|
defp savable?(draft_file, saved_file, running_files) do
|
||||||
file = normalize_file(draft_file)
|
file = normalize_file(draft_file)
|
||||||
not FileSystem.File.dir?(draft_file) and (file not in running_files or file == saved_file)
|
running? = Enum.any?(running_files, &FileSystem.File.equal?(&1, file))
|
||||||
|
changed? = saved_file == nil or not FileSystem.File.equal?(file, saved_file)
|
||||||
|
not FileSystem.File.dir?(draft_file) and (running? or changed?)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp map_diff(left, right) do
|
defp map_diff(left, right) do
|
||||||
|
|
|
||||||
|
|
@ -1377,7 +1377,7 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
|
|
||||||
defp star_button(assigns) do
|
defp star_button(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<%= if @file in @starred_files do %>
|
<%= if starred?(@file, @starred_files) do %>
|
||||||
<span class="tooltip left" data-tooltip="Unstar notebook">
|
<span class="tooltip left" data-tooltip="Unstar notebook">
|
||||||
<.icon_button phx-click="unstar_notebook">
|
<.icon_button phx-click="unstar_notebook">
|
||||||
<.remix_icon icon="star-fill" class="text-yellow-600" />
|
<.remix_icon icon="star-fill" class="text-yellow-600" />
|
||||||
|
|
@ -1392,4 +1392,8 @@ defmodule LivebookWeb.SessionLive.Render do
|
||||||
<% end %>
|
<% end %>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp starred?(file, starred_files) do
|
||||||
|
Enum.any?(starred_files, &Livebook.FileSystem.File.equal?(&1, file))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,17 @@ defmodule Livebook.FileSystem.FileTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "equal?/2" do
|
||||||
|
test "returns true for matching files built in different processes" do
|
||||||
|
file_system = FileSystem.Local.new()
|
||||||
|
|
||||||
|
file1 = Livebook.FileSystem.File.new(file_system, "/tmp/")
|
||||||
|
file2 = Task.await(Task.async(fn -> Livebook.FileSystem.File.local("/tmp/") end))
|
||||||
|
|
||||||
|
assert FileSystem.File.equal?(file1, file2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "local/1" do
|
describe "local/1" do
|
||||||
test "uses the globally configured local file system instance" do
|
test "uses the globally configured local file system instance" do
|
||||||
assert FileSystem.File.local(p("/path")).file_system_id ==
|
assert FileSystem.File.local(p("/path")).file_system_id ==
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue