defmodule Virtfs do use GenServer alias Virtfs.FS alias Virtfs.Backend ### ### API ### def start_link() do start_link(FS.init()) end def start_link(%FS{} = fs) do GenServer.start_link(__MODULE__, fs) end def ls(pid, path \\ "") do GenServer.call(pid, {:ls, path}) end def ls!(pid, path \\ "") do handle_error(ls(pid, path), {:ls!, path}) end def write(pid, path, content) do GenServer.call(pid, {:write, path, content}) end def write!(pid, path, content) do handle_error(write(pid, path, content), {:write!, path, content}) end def append(pid, path, content) do GenServer.call(pid, {:append, path, content}) end def append!(pid, path, content) do handle_error(append(pid, path, content), {:append!, path, content}) end def append_line(pid, path, content) do GenServer.call(pid, {:append_line, path, content}) end def append_line!(pid, path, content) do handle_error(append_line(pid, path, content), {:append_line!, path, content}) end def read(pid, path) do GenServer.call(pid, {:read, path}) end def read!(pid, path) do handle_error(read(pid, path), {:read!, path}) end def mkdir_p(pid, path) do GenServer.call(pid, {:mkdir_p, path}) end def mkdir_p!(pid, path) do handle_error(mkdir_p(pid, path), {:mkdir_p!, path}) end def rm(pid, path) do GenServer.call(pid, {:rm, path}) end def rm!(pid, path) do handle_error(rm(pid, path), {:rm!, path}) end def rename(pid, src, dest) do GenServer.call(pid, {:rename, src, dest}) end def rename!(pid, src, dest) do handle_error(rename(pid, src, dest), {:rename!, src, dest}) end def rm_rf(pid, path) do GenServer.call(pid, {:rm_rf, path}) end def rm_rf!(pid, path) do handle_error(rm_rf(pid, path), {:rm_rf!, path}) end def cp(pid, src, dest) do GenServer.call(pid, {:cp, src, dest}) end def cp!(pid, src, dest) do handle_error(cp(pid, src, dest), {:cp!, src, dest}) end def cp_r(pid, src, dest) do GenServer.call(pid, {:cp_r, src, dest}) end def cp_r!(pid, src, dest) do handle_error(cp_r(pid, src, dest), {:cp_r!, src, dest}) end def tree(pid, path) do GenServer.call(pid, {:tree, path}) end def tree!(pid, path) do handle_error(tree(pid, path), {:tree!, path}) end def cd(pid, path) do GenServer.call(pid, {:cd, path}) end def cd!(pid, path) do handle_error(cd(pid, path), {:cd!, path}) end def exists?(pid, path) do GenServer.call(pid, {:exists?, path}) end def exists!(pid, path) do handle_error(exists?(pid, path), {:exists!, path}) end def dir?(pid, path) do GenServer.call(pid, {:dir?, path}) end def dir!(pid, path) do handle_error(dir?(pid, path), {:dir!, path}) end def cwd(pid) do GenServer.call(pid, {:cwd}) end ## Path API partially included def expand(pid, path) do GenServer.call(pid, {:expand, path}) end def expand!(pid, path) do handle_error(expand(pid, path), {:expand!, path}) end def relative_to_cwd(pid, path) do GenServer.call(pid, {:relative_to_cwd, path}) end def relative_to_cwd!(pid, path) do handle_error(relative_to_cwd(pid, path), {:relative_to_cwd!, path}) end ## Management API def get_fs(pid) do GenServer.call(pid, {:get_fs}) end def dump(pid, path) do GenServer.call(pid, {:dump, path}) end def load(pid, path, opts \\ []) do GenServer.call(pid, {:load, path, opts}) end ### ### GEN SERVER CALLBACKS ### @impl true def init(%FS{} = fs) do {:ok, fs} end @impl true def handle_call({:ls, path}, _from, %FS{} = fs) do {fs, res} = Backend.ls(fs, path) {:reply, res, fs} end @impl true def handle_call({:write, path, content}, _from, %FS{} = fs) do {fs, res} = Backend.write(fs, path, content) {:reply, res, fs} end @impl true def handle_call({:append, path, content}, _from, %FS{} = fs) do {fs, res} = Backend.append(fs, path, content) {:reply, res, fs} end @impl true def handle_call({:append_line, path, content}, _from, %FS{} = fs) do {fs, res} = Backend.append_line(fs, path, content) {:reply, res, fs} end @impl true def handle_call({:read, path}, _from, %FS{} = fs) do {fs, res} = Backend.read(fs, path) {:reply, res, fs} end @impl true def handle_call({:mkdir_p, path}, _from, %FS{} = fs) do {fs, res} = Backend.mkdir_p(fs, path) {:reply, res, fs} end @impl true def handle_call({:rm, path}, _from, %FS{} = fs) do {fs, res} = Backend.rm(fs, path) {:reply, res, fs} end @impl true def handle_call({:rm_rf, path}, _from, %FS{} = fs) do {fs, res} = Backend.rm_rf(fs, path) {:reply, res, fs} end @impl true def handle_call({:tree, path}, _from, %FS{} = fs) do {fs, res} = Backend.tree(fs, path) {:reply, res, fs} end @impl true def handle_call({:cp, src, dest}, _from, %FS{} = fs) do {fs, res} = Backend.cp(fs, src, dest) {:reply, res, fs} end @impl true def handle_call({:cp_r, src, dest}, _from, %FS{} = fs) do {fs, res} = Backend.cp_r(fs, src, dest) {:reply, res, fs} end @impl true def handle_call({:rename, src, dest}, _from, %FS{} = fs) do {fs, res} = Backend.rename(fs, src, dest) {:reply, res, fs} end @impl true def handle_call({:cd, path}, _from, %FS{} = fs) do {fs, res} = Backend.cd(fs, path) {:reply, res, fs} end @impl true def handle_call({:exists?, path}, _from, %FS{} = fs) do {fs, res} = Backend.exists?(fs, path) {:reply, res, fs} end @impl true def handle_call({:dir?, path}, _from, %FS{} = fs) do {fs, res} = Backend.dir?(fs, path) {:reply, res, fs} end @impl true def handle_call({:cwd}, _from, %FS{} = fs) do {:reply, fs.cwd, fs} end ## Path API callbacks @impl true def handle_call({:expand, path}, _from, %FS{} = fs) do {fs, res} = Backend.expand(fs, path) {:reply, res, fs} end @impl true def handle_call({:relative_to_cwd, path}, _from, %FS{} = fs) do {fs, res} = Backend.relative_to_cwd(fs, path) {:reply, res, fs} end ## Management API callbacks @impl true def handle_call({:get_fs}, _from, %FS{} = fs) do {:reply, fs, fs} end @impl true def handle_call({:dump, path}, _from, %FS{} = fs) do res = Virtfs.Dumper.run(fs, path) {:reply, res, fs} end @impl true def handle_call({:load, path, opts}, _from, %FS{} = fs) do with {:ok, res} <- Virtfs.Loader.run(fs, path, opts) do {:reply, :ok, res} end end defp handle_error(res, args) do case res do {:error, _} -> raise(inspect({res, args})) {:ok, res} -> res :ok -> :ok end end end