From 362a27f850a83be15d1d6cac7c061e024967118f Mon Sep 17 00:00:00 2001 From: Alexandre de Souza Date: Wed, 1 Oct 2025 16:29:24 -0300 Subject: [PATCH 1/3] Mount the file system when user set file system --- lib/livebook_web/live/file_select_component.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/livebook_web/live/file_select_component.ex b/lib/livebook_web/live/file_select_component.ex index 04d8339456f..d5c33341daf 100644 --- a/lib/livebook_web/live/file_select_component.ex +++ b/lib/livebook_web/live/file_select_component.ex @@ -499,8 +499,8 @@ defmodule LivebookWeb.FileSelectComponent do def handle_event("set_file_system", %{"id" => file_system_id}, socket) do file_system = Enum.find(socket.assigns.file_systems, &(&1.id == file_system_id)) - file = FileSystem.File.new(file_system) + :ok = FileSystem.mount(file_system) send_event(socket.assigns.target, {:set_file, file, %{exists: true}}) From d89e196bd0ca0adee29497a707e138689385e5b5 Mon Sep 17 00:00:00 2001 From: Alexandre de Souza Date: Wed, 1 Oct 2025 17:19:54 -0300 Subject: [PATCH 2/3] Streams the file content into a collectable --- lib/livebook/file_system/git.ex | 8 +++++++- lib/livebook/file_system/git/client.ex | 19 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/livebook/file_system/git.ex b/lib/livebook/file_system/git.ex index dbd007ce4e4..eeaf1cd32a7 100644 --- a/lib/livebook/file_system/git.ex +++ b/lib/livebook/file_system/git.ex @@ -116,7 +116,13 @@ defimpl Livebook.FileSystem, for: Livebook.FileSystem.Git do def write_stream_halt(_file_system, _state), do: raise("not implemented") - def read_stream_into(_file_system, _path, _collectable), do: raise("not implemented") + def read_stream_into(file_system, path, collectable) do + try do + Git.Client.stream_file(file_system, path, collectable) + rescue + error in File.Error -> FileSystem.Utils.posix_error(error.reason) + end + end def load(file_system, %{"hub_id" => _} = fields) do load(file_system, %{ diff --git a/lib/livebook/file_system/git/client.ex b/lib/livebook/file_system/git/client.ex index 9b7d9aab981..c135490a5f9 100644 --- a/lib/livebook/file_system/git/client.ex +++ b/lib/livebook/file_system/git/client.ex @@ -43,7 +43,20 @@ defmodule Livebook.FileSystem.Git.Client do path = relative_path(path) with {:ok, git_dir} <- fetch_repository(file_system) do - show(git_dir, file_system.branch, path) + git(git_dir, ["show", "#{file_system.branch}:#{path}"]) + end + end + + @doc """ + Streams the content of the given file from given repository. + """ + @spec stream_file(FileSystem.Git.t(), String.t(), Collectable.t()) :: + {:ok, String.t()} | {:error, FileSystem.error()} + def stream_file(%FileSystem.Git{} = file_system, path, collectable) do + path = relative_path(path) + + with {:ok, git_dir} <- fetch_repository(file_system) do + git(git_dir, ["show", "#{file_system.branch}:#{path}"], into: collectable) end end @@ -90,10 +103,6 @@ defmodule Livebook.FileSystem.Git.Client do end end - defp show(git_dir, branch, path) do - git(git_dir, ["show", "#{branch}:#{path}"]) - end - defp rev_parse(git_dir, branch, path) do with {:ok, etag} <- git(git_dir, ["rev-parse", "#{branch}:#{path}"]) do {:ok, String.trim(etag)} From 4e1b20135803ff5925d60ad42b97c0b3bf7b3d37 Mon Sep 17 00:00:00 2001 From: Alexandre de Souza Date: Fri, 3 Oct 2025 14:39:59 -0300 Subject: [PATCH 3/3] Add tests --- test/livebook/file_system/git_test.exs | 28 ++++++++++++++++++++++---- test/support/integration/teams_rpc.ex | 7 ++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/test/livebook/file_system/git_test.exs b/test/livebook/file_system/git_test.exs index 48f5309c329..d2ebc5bf5e4 100644 --- a/test/livebook/file_system/git_test.exs +++ b/test/livebook/file_system/git_test.exs @@ -51,6 +51,7 @@ defmodule Livebook.FileSystem.GitTest do describe "FileSystem.read/2" do @describetag init: true + test "returns an error when a nonexistent key is given", %{file_system: file_system} do assert FileSystem.read(file_system, "/another_file.txt") == {:error, "fatal: path 'another_file.txt' does not exist in 'main'"} @@ -104,6 +105,7 @@ defmodule Livebook.FileSystem.GitTest do describe "FileSystem.etag_for/2" do @describetag init: true + test "returns an error when a nonexistent key is given", %{file_system: file_system} do assert {:error, reason} = FileSystem.etag_for(file_system, "/another_file.txt") assert reason =~ "path 'another_file.txt' does not exist in 'main'" @@ -116,6 +118,7 @@ defmodule Livebook.FileSystem.GitTest do describe "FileSystem.exists?/2" do @describetag init: true + test "returns valid response", %{file_system: file_system} do assert {:ok, true} = FileSystem.exists?(file_system, "/file.txt") assert {:ok, false} = FileSystem.exists?(file_system, "/another_file.txt") @@ -158,10 +161,27 @@ defmodule Livebook.FileSystem.GitTest do end describe "FileSystem.read_stream_into/2" do - test "not implemented", %{file_system: file_system} do - assert_raise RuntimeError, "not implemented", fn -> - FileSystem.read_stream_into(file_system, "/file.txt", <<>>) - end + @describetag init: true + + test "returns an error when a nonexistent key is given", %{file_system: file_system} do + assert FileSystem.read_stream_into(file_system, "/another_file.txt", <<>>) == + {:error, "fatal: path 'another_file.txt' does not exist in 'main'"} + end + + test "returns object contents under the given key", %{file_system: file_system} do + assert {:ok, content} = FileSystem.read_stream_into(file_system, "/file.txt", <<>>) + assert content =~ "git file storage works" + end + + @tag :tmp_dir + test "collects file contents into another file", %{file_system: file_system, tmp_dir: tmp_dir} do + file_path = Path.join(tmp_dir, "myfile.txt") + collectable = FileSystem.File.new(FileSystem.Local.new(), file_path) + + assert {:ok, %FileSystem.File{path: ^file_path}} = + FileSystem.read_stream_into(file_system, "/file.txt", collectable) + + assert File.read!(file_path) =~ "git file storage works" end end diff --git a/test/support/integration/teams_rpc.ex b/test/support/integration/teams_rpc.ex index f53698ce230..9841a48244e 100644 --- a/test/support/integration/teams_rpc.ex +++ b/test/support/integration/teams_rpc.ex @@ -98,12 +98,13 @@ defmodule Livebook.TeamsRPC do hub_id: team.id } - attrs = %{ + attrs = [ name: name, type: String.to_atom(type), value: Livebook.HubHelpers.generate_file_system_json(team, file_system), - org_key: org_key - } + org_key: org_key, + livebook_version: Livebook.Config.app_version() + ] external_id = :erpc.call(node, TeamsRPC, :create_file_system, [attrs]).id Map.replace!(file_system, :external_id, to_string(external_id))