Packages
fnord
0.8.97
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/memory/project.ex
defmodule Memory.Project do
@moduledoc """
Project-level memory storage implementation for the `Memory` behaviour.
Memories are stored as JSON files in `~/.fnord/projects/<project>/memory`.
"""
# ----------------------------------------------------------------------------
# Behaviour Implementation
# ----------------------------------------------------------------------------
@behaviour Memory
@impl Memory
def init() do
with {:ok, project} <- get_project(),
{:ok, _path} <- ensure_storage_path(project) do
drop_old_storage(project)
:ok
end
end
@impl Memory
def list() do
with {:ok, project} <- get_project(),
{:ok, files} <- project |> storage_path() |> File.ls() do
files
|> Enum.filter(&String.ends_with?(&1, ".json"))
|> Enum.map(fn file ->
file
|> Path.rootname()
|> Memory.slug_to_title()
end)
|> then(&{:ok, &1})
end
end
@impl Memory
def exists?(title) do
with {:ok, project} <- get_project() do
title
|> file_path(project)
|> File.exists?()
else
_ -> false
end
end
@impl Memory
def read(title) do
with {:ok, project} <- get_project(),
path = file_path(title, project),
true <- exists?(title),
{:ok, content} <- read_file(path),
{:ok, memory} <- Memory.unmarshal(content) do
{:ok, memory}
else
false -> {:error, :not_found}
end
end
@impl Memory
def save(%{title: title} = memory) do
with {:ok, project} <- get_project(),
path = file_path(title, project),
{:ok, json} <- Memory.marshal(memory),
{:ok, _result} <- write_file(path, json) do
:ok
end
end
@impl Memory
def forget(title) do
with {:ok, project} <- get_project() do
title
|> file_path(project)
|> rm_path()
end
end
@impl Memory
def is_available?() do
case Store.get_project() do
{:ok, _project} -> true
_ -> false
end
end
# ----------------------------------------------------------------------------
# Internals
# ----------------------------------------------------------------------------
defp get_project() do
Store.get_project()
end
defp storage_path(%Store.Project{store_path: store_path}) do
Path.join(store_path, "memory")
end
defp old_storage_path(%Store.Project{store_path: store_path}) do
Path.join(store_path, "memories")
end
defp ensure_storage_path(project) do
path = storage_path(project)
with false <- File.exists?(path),
:ok <- File.mkdir_p(path) do
{:ok, path}
else
true -> {:ok, path}
end
end
defp drop_old_storage(project) do
path = old_storage_path(project)
if File.exists?(path) do
UI.debug("memory:project", "Removing old project memory storage at #{path}")
File.rm_rf!(path)
end
end
defp file_path(title, project) when is_binary(title) do
slug = Memory.title_to_slug(title)
project
|> storage_path()
|> Path.join("#{slug}.json")
end
defp file_path(%Memory{title: title}, project) do
file_path(title, project)
end
defp read_file(path) do
case FileLock.with_lock(path, fn -> File.read(path) end) do
{:ok, {:ok, contents}} ->
{:ok, contents}
{:ok, {:error, reason}} ->
{:error, reason}
{:error, reason} ->
{:error, reason}
end
end
defp write_file(path, json) do
case FileLock.with_lock(path, fn -> File.write(path, json) end) do
{:ok, :ok} ->
{:ok, :ok}
{:ok, {:error, reason}} ->
{:error, reason}
{:error, reason} ->
{:error, reason}
end
end
defp rm_path(path) do
case FileLock.with_lock(path, fn -> File.rm(path) end) do
{:ok, :ok} ->
:ok
{:ok, {:error, reason}} ->
{:error, reason}
{:error, reason} ->
{:error, reason}
{:callback_error, reason} ->
{:error, reason}
end
end
end