Jido.VFS (Jido.VFS v1.0.0)

View Source

Jido.VFS is a filesystem abstraction for Elixir providing a unified interface over many storage backends. It allows you to swap out filesystems on the fly without needing to rewrite your application code. Eliminate vendor lock-in, reduce technical debt, and improve testability.

Features

  • Unified API - Same operations work across all adapters
  • Multiple Backends - Local, S3, Sprite, Git, GitHub, ETS, and InMemory storage
  • Version Control - Git, Sprite, ETS, and InMemory adapters support versioning
  • Streaming - Efficient handling of large files
  • Cross-Filesystem Operations - Copy files between different storage backends
  • Visibility Controls - Public/private file permissions

Contract Guarantees (V1)

  • Public API return shape is deterministic: :ok, {:ok, value}, or {:error, %Jido.VFS.Errors.*{}}
  • Unsupported operations always return %Jido.VFS.Errors.UnsupportedOperation{operation, adapter}
  • Paths are normalized before adapter calls and traversal/absolute paths are rejected with typed errors
  • Cross-filesystem copy is memory-bounded: native copy if available, then streaming, then tempfile spooling fallback
  • Versioned adapters (Git, ETS, InMemory) return %Jido.VFS.Revision{} values from revisions/3

Adapters

AdapterUse CaseStreamingVersioningNotes
Jido.VFS.Adapter.LocalLocal filesystemYesNoFull local filesystem operations
Jido.VFS.Adapter.S3AWS S3 / MinioYesNoPrefix-scoped clear/listing, multipart stream uploads
Jido.VFS.Adapter.SpriteFly.io SpritesYesYesShell-command filesystem + checkpoint-backed versioning
Jido.VFS.Adapter.GitGit repositoriesYesYesDeterministic bootstrap commit, rollback support
Jido.VFS.Adapter.GitHubGitHub APINoNoRemote read/write via API, typed unsupported ops
Jido.VFS.Adapter.ETSETS tablesYesYesVersion storage hardened without dynamic atoms
Jido.VFS.Adapter.InMemoryTestingYesYesEphemeral storage with version snapshots

Capability Checks

Use supports?/2 before optional operations:

if Jido.VFS.supports?(filesystem, :write_stream) do
  {:ok, stream} = Jido.VFS.write_stream(filesystem, "large.bin")
  Stream.into(data_stream, stream) |> Stream.run()
else
  :ok = Jido.VFS.write(filesystem, "large.bin", IO.iodata_to_binary(Enum.to_list(data_stream)))
end

This avoids relying on matching adapter error payloads to determine capabilities.

Quick Start

# Direct filesystem configuration
filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")

# Write and read files
:ok = Jido.VFS.write(filesystem, "test.txt", "Hello World")
{:ok, "Hello World"} = Jido.VFS.read(filesystem, "test.txt")

# Module-based filesystem (recommended for reuse)
defmodule MyStorage do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

MyStorage.write("test.txt", "Hello World")
{:ok, "Hello World"} = MyStorage.read("test.txt")

Local Adapter

The Local adapter provides standard filesystem operations:

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/path/to/storage")

# Basic operations
:ok = Jido.VFS.write(filesystem, "file.txt", "content")
{:ok, content} = Jido.VFS.read(filesystem, "file.txt")
:ok = Jido.VFS.delete(filesystem, "file.txt")

# Copy and move
:ok = Jido.VFS.copy(filesystem, "source.txt", "dest.txt")
:ok = Jido.VFS.move(filesystem, "old.txt", "new.txt")

# Directory operations
:ok = Jido.VFS.create_directory(filesystem, "new-folder")
{:ok, entries} = Jido.VFS.list_contents(filesystem, "folder/")
:ok = Jido.VFS.delete_directory(filesystem, "old-folder")

# File info
{:ok, stat} = Jido.VFS.stat(filesystem, "file.txt")
{:ok, :exists} = Jido.VFS.file_exists(filesystem, "file.txt")

S3 Adapter

The S3 adapter works with AWS S3, Minio, and S3-compatible storage:

# Configure S3 filesystem
filesystem = Jido.VFS.Adapter.S3.configure(
  bucket: "my-bucket",
  prefix: "uploads/",
  region: "us-east-1"
)

# For Minio or custom S3-compatible storage
filesystem = Jido.VFS.Adapter.S3.configure(
  bucket: "my-bucket",
  host: "localhost",
  port: 9000,
  scheme: "http://",
  access_key_id: "minioadmin",
  secret_access_key: "minioadmin"
)

# All standard operations work
:ok = Jido.VFS.write(filesystem, "document.pdf", pdf_binary)
{:ok, content} = Jido.VFS.read(filesystem, "document.pdf")

# Streaming for large files
{:ok, stream} = Jido.VFS.read_stream(filesystem, "large-file.bin", chunk_size: 65536)
Enum.each(stream, fn chunk -> process(chunk) end)

Sprite Adapter

The Sprite adapter executes shell commands on a Fly.io Sprite through sprites-ex.

# Add sprites-ex in your project if needed
# {:sprites, github: "superfly/sprites-ex"}

filesystem =
  Jido.VFS.Adapter.Sprite.configure(
    sprite_name: "my-sprite",
    token: System.fetch_env!("SPRITES_TOKEN"),
    root: "/workspace",
    encoding: :base64
  )

:ok = Jido.VFS.write(filesystem, "notes/hello.txt", "hello sprite")
{:ok, "hello sprite"} = Jido.VFS.read(filesystem, "notes/hello.txt")
{:ok, entries} = Jido.VFS.list_contents(filesystem, "notes")
  • encoding: :base64 is binary-safe and default.
  • encoding: :raw is text-oriented and avoids base64 overhead.
  • Pass create_on_demand: true to call Sprite create during configure.

Sprite versioning is backed by Sprite checkpoints:

:ok = Jido.VFS.write(filesystem, "doc.txt", "v1")
:ok = Jido.VFS.commit(filesystem, "checkpoint v1")

:ok = Jido.VFS.write(filesystem, "doc.txt", "v2")
:ok = Jido.VFS.commit(filesystem, "checkpoint v2")

{:ok, revisions} = Jido.VFS.revisions(filesystem, "doc.txt")
old_revision = List.last(revisions)

{:ok, "v1"} = Jido.VFS.read_revision(filesystem, "doc.txt", old_revision.sha)
:ok = Jido.VFS.rollback(filesystem, old_revision.sha, path: "doc.txt")

Git Adapter

The Git adapter provides version-controlled filesystem operations:

# Manual commit mode - you control when commits happen
filesystem = Jido.VFS.Adapter.Git.configure(
  path: "/path/to/repo",
  mode: :manual,
  author: [name: "Bot", email: "bot@example.com"]
)

# Write files and commit manually
Jido.VFS.write(filesystem, "document.txt", "Version 1")
Jido.VFS.write(filesystem, "notes.txt", "Some notes")
:ok = Jido.VFS.commit(filesystem, "Add initial documents")

# Auto-commit mode - each write creates a commit
filesystem = Jido.VFS.Adapter.Git.configure(
  path: "/path/to/repo",
  mode: :auto
)
Jido.VFS.write(filesystem, "file.txt", "content")  # Automatically committed

# View revision history
{:ok, revisions} = Jido.VFS.revisions(filesystem, "document.txt")

# Read historical versions
{:ok, old_content} = Jido.VFS.read_revision(filesystem, "document.txt", revision_sha)

# Rollback to a previous revision
:ok = Jido.VFS.rollback(filesystem, revision_sha)

GitHub Adapter

The GitHub adapter allows you to interact with GitHub repositories as a virtual filesystem:

# Read-only access to public repos
filesystem = Jido.VFS.Adapter.GitHub.configure(
  owner: "octocat",
  repo: "Hello-World",
  ref: "main"
)

{:ok, content} = Jido.VFS.read(filesystem, "README.md")
{:ok, files} = Jido.VFS.list_contents(filesystem, "src/")

# Authenticated access for write operations
filesystem = Jido.VFS.Adapter.GitHub.configure(
  owner: "your-username",
  repo: "your-repo",
  ref: "main",
  auth: %{access_token: "ghp_your_token"},
  commit_info: %{
    message: "Update via Jido.VFS",
    committer: %{name: "Your Name", email: "you@example.com"},
    author: %{name: "Your Name", email: "you@example.com"}
  }
)

# Write files (creates commits)
Jido.VFS.write(filesystem, "new_file.txt", "Hello GitHub!", 
  message: "Add new file via Jido.VFS")

ETS and InMemory Adapters

These adapters are ideal for testing and caching:

# ETS adapter - persists to ETS table
filesystem = Jido.VFS.Adapter.ETS.configure(name: :my_cache)

# InMemory adapter - ephemeral storage
filesystem = Jido.VFS.Adapter.InMemory.configure(name: :test_fs)

# Both support versioning
Jido.VFS.write(filesystem, "file.txt", "v1")
:ok = Jido.VFS.commit(filesystem, "Version 1")

Jido.VFS.write(filesystem, "file.txt", "v2")
:ok = Jido.VFS.commit(filesystem, "Version 2")

{:ok, revisions} = Jido.VFS.revisions(filesystem, "file.txt")
{:ok, "v1"} = Jido.VFS.read_revision(filesystem, "file.txt", first_revision_id)

Cross-Filesystem Operations

Copy files between different storage backends:

local_fs = Jido.VFS.Adapter.Local.configure(prefix: "/local/storage")
s3_fs = Jido.VFS.Adapter.S3.configure(bucket: "my-bucket")

# Copy from local to S3
:ok = Jido.VFS.copy_between_filesystem(
  {local_fs, "document.pdf"},
  {s3_fs, "uploads/document.pdf"}
)

# Copy from S3 to local
:ok = Jido.VFS.copy_between_filesystem(
  {s3_fs, "backup.zip"},
  {local_fs, "downloads/backup.zip"}
)

copy_between_filesystem/3 prefers native adapter copy, then stream-based copy, and finally tempfile spooling for bounded-memory fallback behavior.

Streaming

Efficiently handle large files with streaming:

# Read stream
{:ok, stream} = Jido.VFS.read_stream(filesystem, "large-file.bin", chunk_size: 65536)
Enum.each(stream, fn chunk -> process(chunk) end)

# Write stream
{:ok, stream} = Jido.VFS.write_stream(filesystem, "output.bin")
data |> Stream.into(stream) |> Stream.run()

Visibility

Control file permissions with visibility settings:

# Write with visibility
:ok = Jido.VFS.write(filesystem, "public-file.txt", "content", visibility: :public)
:ok = Jido.VFS.write(filesystem, "private-file.txt", "secret", visibility: :private)

# Get/set visibility
{:ok, :public} = Jido.VFS.visibility(filesystem, "public-file.txt")
:ok = Jido.VFS.set_visibility(filesystem, "file.txt", :private)

Summary

Functions

Check file access permissions

Append content to a file

Clear the filesystem.

Commit changes to a version-controlled filesystem.

Configure an adapter, raising when configuration fails.

Copy a file from source to destination on a filesystem

Copy a file from one filesystem to the other

Delete a file from a filesystem

Copy a file from source to destination on a filesystem

List the contents of a folder on a filesystem

Move a file from source to destination on a filesystem

Read from a filesystem

Read a file as it existed at a specific revision.

Returns a Stream for reading the given path.

List revisions/commits for a path in a version-controlled filesystem.

Rollback the filesystem to a previous revision.

Safely configure an adapter and normalize configure-time failures into typed errors.

Get file or directory metadata (stat information)

Returns whether a filesystem supports a specific operation.

Truncate a file to a specific size

Update file modification time

Returns a Stream for writing to the given path.

Types

adapter()

@type adapter() :: module()

copy_between_strategy()

@type copy_between_strategy() :: :native | :stream | :tempfile

filesystem()

@type filesystem() :: {module(), Jido.VFS.Adapter.config()}

operation()

@type operation() ::
  :write
  | :write_stream
  | :read
  | :read_stream
  | :delete
  | :move
  | :copy
  | :copy_between
  | :file_exists
  | :list_contents
  | :create_directory
  | :delete_directory
  | :clear
  | :set_visibility
  | :visibility
  | :stat
  | :access
  | :append
  | :truncate
  | :utime
  | :commit
  | :revisions
  | :read_revision
  | :rollback

Functions

access(arg, path, modes)

@spec access(filesystem(), Path.t(), [:read | :write]) :: :ok | {:error, term()}

Check file access permissions

Checks whether the given file or directory can be accessed with the specified modes.

Modes

  • :read - Check read access
  • :write - Check write access

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.access(filesystem, "test.txt", [:read, :write])

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.access("test.txt", [:read])

append(arg, path, contents, opts \\ [])

@spec append(filesystem(), Path.t(), iodata(), keyword()) :: :ok | {:error, term()}

Append content to a file

If the file exists, the content is appended to the end. If it doesn't exist, a new file is created with the given content.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.append(filesystem, "test.txt", "Additional content")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.append("test.txt", "More data")

clear(arg, opts \\ [])

@spec clear(
  filesystem(),
  keyword()
) :: :ok | {:error, term()}

Clear the filesystem.

This is always recursive.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.clear(filesystem)

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

LocalFileSystem.clear()

commit(arg, message \\ nil, opts \\ [])

@spec commit(filesystem(), String.t() | nil, keyword()) :: :ok | {:error, term()}

Commit changes to a version-controlled filesystem.

Uses the polymorphic versioning interface to support any adapter that implements versioning functionality (Git, ETS, InMemory).

Examples

# Git adapter
filesystem = Jido.VFS.Adapter.Git.configure(path: "/repo", mode: :manual)
Jido.VFS.write(filesystem, "file.txt", "content")
:ok = Jido.VFS.commit(filesystem, "Add new file")

# ETS adapter (uses versioning wrapper)
filesystem = Jido.VFS.Adapter.ETS.configure(name: :test_ets)
:ok = Jido.VFS.commit(filesystem, "Snapshot")

configure!(adapter, opts \\ [])

@spec configure!(
  adapter(),
  keyword()
) :: filesystem()

Configure an adapter, raising when configuration fails.

copy(arg, source, destination, opts \\ [])

@spec copy(filesystem(), Path.t(), Path.t(), keyword()) :: :ok | {:error, term()}

Copy a file from source to destination on a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.copy(filesystem, "test.txt", "other-test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.copy("test.txt", "other-test.txt")

copy_between_filesystem(source, destination, opts \\ [])

@spec copy_between_filesystem(
  source :: {filesystem(), Path.t()},
  destination :: {filesystem(), Path.t()},
  keyword()
) :: :ok | {:error, term()}

Copy a file from one filesystem to the other

Copy behavior is controlled by :copy_between_strategy:

  • :native - use adapter-native cross-filesystem copy only (copy/5).
  • :stream - stream chunks from source to destination without local temp files.
  • :tempfile - spool through a local temp file.

The default strategy is :tempfile.

Options

  • :copy_between_strategy - :native | :stream | :tempfile (default: :tempfile)

  • :copy_between_temp_dir - temp directory for :tempfile strategy (default: System.tmp_dir!/0)
  • :chunk_size - chunk size for streaming strategies (default: 64 * 1024)
  • all other options are forwarded to adapter read/read_stream/write/write_stream/append calls.

Examples

Direct filesystem

filesystem_source = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
filesystem_destination = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage2")
:ok = Jido.VFS.copy_between_filesystem({filesystem_source, "test.txt"}, {filesystem_destination, "copy.txt"})

Module-based filesystem

defmodule LocalSourceFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

defmodule LocalDestinationFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage2"
end

:ok = Jido.VFS.copy_between_filesystem(
  {LocalSourceFileSystem.__filesystem__(), "test.txt"},
  {LocalDestinationFileSystem.__filesystem__(), "copy.txt"}
)

create_directory(arg, path, opts \\ [])

@spec create_directory(filesystem(), Path.t(), keyword()) :: :ok | {:error, term()}

Create a directory

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.create_directory(filesystem, "test/")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

LocalFileSystem.create_directory("test/")

delete(arg, path, opts \\ [])

@spec delete(filesystem(), Path.t(), keyword()) :: :ok | {:error, term()}

Delete a file from a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.delete(filesystem, "test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.delete("test.txt")

delete_directory(arg, path, opts \\ [])

@spec delete_directory(filesystem(), Path.t(), keyword()) :: :ok | {:error, term()}

Delete a directory.

Options

  • :recursive - Recursively delete contents. Defaults to false.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.delete_directory(filesystem, "test/")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

LocalFileSystem.delete_directory("test/")

file_exists(arg, path, opts \\ [])

@spec file_exists(filesystem(), Path.t(), keyword()) ::
  {:ok, :exists | :missing} | {:error, term()}

Copy a file from source to destination on a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.copy(filesystem, "test.txt", "other-test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.copy("test.txt", "other-test.txt")

list_contents(arg, path, opts \\ [])

@spec list_contents(filesystem(), Path.t(), keyword()) ::
  {:ok,
   [
     %Jido.VFS.Stat.Dir{
       mtime: term(),
       name: term(),
       size: term(),
       visibility: term()
     }
     | %Jido.VFS.Stat.File{
         mtime: term(),
         name: term(),
         size: term(),
         visibility: term()
       }
   ]}
  | {:error, term()}

List the contents of a folder on a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
{:ok, contents} = Jido.VFS.list_contents(filesystem, ".")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

{:ok, contents} = LocalFileSystem.list_contents(".")

move(arg, source, destination, opts \\ [])

@spec move(filesystem(), Path.t(), Path.t(), keyword()) :: :ok | {:error, term()}

Move a file from source to destination on a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.move(filesystem, "test.txt", "other-test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.move("test.txt", "other-test.txt")

read(arg, path, opts \\ [])

@spec read(filesystem(), Path.t(), keyword()) :: {:ok, binary()} | {:error, term()}

Read from a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
{:ok, "Hello World"} = Jido.VFS.read(filesystem, "test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

{:ok, "Hello World"} = LocalFileSystem.read("test.txt")

read_revision(arg, path, revision, opts \\ [])

@spec read_revision(filesystem(), Path.t(), String.t(), keyword()) ::
  {:ok, binary()} | {:error, term()}

Read a file as it existed at a specific revision.

Uses the polymorphic versioning interface to support any adapter that implements versioning functionality.

Examples

# Git adapter
filesystem = Jido.VFS.Adapter.Git.configure(path: "/repo")
{:ok, content} = Jido.VFS.read_revision(filesystem, "file.txt", "abc123")

# ETS adapter
filesystem = Jido.VFS.Adapter.ETS.configure(name: :test_ets)
{:ok, content} = Jido.VFS.read_revision(filesystem, "file.txt", "version_id")

read_stream(arg, path, opts \\ [])

@spec read_stream(filesystem(), Path.t(), keyword()) ::
  {:ok, Enumerable.t()} | {:error, term()}

Returns a Stream for reading the given path.

Options

The following stream options apply to all adapters:

  • :chunk_size - When reading, the amount to read, usually expressed as a number of bytes.

Examples

Note: The shape of the returned stream will necessarily depend on the adapter in use. In the following examples the Local adapter is invoked, which returns a File.Stream.

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
{:ok, %File.Stream{}} = Jido.VFS.read_stream(filesystem, "test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

{:ok, %File.Stream{}} = LocalFileSystem.read_stream("test.txt")

revisions(arg, path \\ ".", opts \\ [])

@spec revisions(filesystem(), Path.t(), keyword()) ::
  {:ok, [Jido.VFS.Revision.t()]} | {:error, term()}

List revisions/commits for a path in a version-controlled filesystem.

Uses the polymorphic versioning interface to support any adapter that implements versioning functionality. Returns a list of revision maps with standardized format.

Options

  • :limit - Maximum number of revisions to return
  • :since - Only revisions after this datetime
  • :until - Only revisions before this datetime
  • :author - Only revisions by this author

Examples

# Git adapter
filesystem = Jido.VFS.Adapter.Git.configure(path: "/repo")
{:ok, revisions} = Jido.VFS.revisions(filesystem, "file.txt", limit: 10)

# ETS adapter
filesystem = Jido.VFS.Adapter.ETS.configure(name: :test_ets)
{:ok, revisions} = Jido.VFS.revisions(filesystem, "file.txt")

rollback(arg, revision, opts \\ [])

@spec rollback(filesystem(), String.t(), keyword()) :: :ok | {:error, term()}

Rollback the filesystem to a previous revision.

Uses the polymorphic versioning interface to support any adapter that implements versioning functionality.

Options

  • :path - Only rollback changes to a specific path (if supported)

Examples

# Git adapter - full rollback
filesystem = Jido.VFS.Adapter.Git.configure(path: "/repo")
:ok = Jido.VFS.rollback(filesystem, "abc123")

# ETS adapter - single file rollback
filesystem = Jido.VFS.Adapter.ETS.configure(name: :test_ets)
:ok = Jido.VFS.rollback(filesystem, "version_id", path: "file.txt")

safe_configure(adapter, opts \\ [])

@spec safe_configure(
  adapter(),
  keyword()
) :: {:ok, filesystem()} | {:error, term()}

Safely configure an adapter and normalize configure-time failures into typed errors.

set_visibility(arg, path, visibility)

@spec set_visibility(filesystem(), Path.t(), Jido.VFS.Visibility.t()) ::
  :ok | {:error, term()}

stat(arg, path)

@spec stat(filesystem(), Path.t()) ::
  {:ok,
   %Jido.VFS.Stat.File{
     mtime: term(),
     name: term(),
     size: term(),
     visibility: term()
   }
   | %Jido.VFS.Stat.Dir{
       mtime: term(),
       name: term(),
       size: term(),
       visibility: term()
     }}
  | {:error, term()}

Get file or directory metadata (stat information)

Returns detailed metadata about a file or directory including size, modification time, and visibility.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
{:ok, %Jido.VFS.Stat.File{}} = Jido.VFS.stat(filesystem, "test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

{:ok, %Jido.VFS.Stat.File{}} = LocalFileSystem.stat("test.txt")

supports?(arg, operation)

@spec supports?(filesystem(), operation()) :: boolean()

Returns whether a filesystem supports a specific operation.

truncate(arg, path, new_size)

@spec truncate(filesystem(), Path.t(), non_neg_integer()) :: :ok | {:error, term()}

Truncate a file to a specific size

Resizes the file to the specified number of bytes. If the new size is larger than the current size, the file is padded with null bytes. If smaller, the file is truncated.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.truncate(filesystem, "test.txt", 100)

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.truncate("test.txt", 0)  # Empty the file

utime(arg, path, mtime)

@spec utime(filesystem(), Path.t(), DateTime.t()) :: :ok | {:error, term()}

Update file modification time

Changes the modification time of a file or directory.

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.utime(filesystem, "test.txt", DateTime.utc_now())

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

:ok = LocalFileSystem.utime("test.txt", ~U[2023-01-01 00:00:00Z])

visibility(arg, path)

@spec visibility(filesystem(), Path.t()) ::
  {:ok, Jido.VFS.Visibility.t()} | {:error, term()}

write(arg, path, contents, opts \\ [])

@spec write(filesystem(), Path.t(), iodata(), keyword()) :: :ok | {:error, term()}

Write to a filesystem

Examples

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
:ok = Jido.VFS.write(filesystem, "test.txt", "Hello World")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

LocalFileSystem.write("test.txt", "Hello World")

write_stream(arg, path, opts \\ [])

@spec write_stream(filesystem(), Path.t(), keyword()) ::
  {:ok, Enumerable.t()} | {:error, term()}

Returns a Stream for writing to the given path.

Options

The following stream options apply to all adapters:

  • :chunk_size - When reading, the amount to read, usually expressed as a number of bytes.

Examples

Note: The shape of the returned stream will necessarily depend on the adapter in use. In the following examples the Local adapter is invoked, which returns a File.Stream.

Direct filesystem

filesystem = Jido.VFS.Adapter.Local.configure(prefix: "/home/user/storage")
{:ok, %File.Stream{}} = Jido.VFS.write_stream(filesystem, "test.txt")

Module-based filesystem

defmodule LocalFileSystem do
  use Jido.VFS.Filesystem,
    adapter: Jido.VFS.Adapter.Local,
    prefix: "/home/user/storage"
end

{:ok, %File.Stream{}} = LocalFileSystem.write_stream("test.txt")