78 lines
2.3 KiB
Elixir
78 lines
2.3 KiB
Elixir
defmodule BDS.Generation do
|
|
@moduledoc false
|
|
|
|
import Ecto.Query
|
|
|
|
alias BDS.Generation.GeneratedFileHash
|
|
alias BDS.Projects
|
|
alias BDS.Repo
|
|
|
|
def write_generated_file(project_id, relative_path, content)
|
|
when is_binary(project_id) and is_binary(relative_path) and is_binary(content) do
|
|
project = Projects.get_project!(project_id)
|
|
content_hash = sha256(content)
|
|
now = System.system_time(:second)
|
|
|
|
case Repo.get_by(GeneratedFileHash, project_id: project_id, relative_path: relative_path) do
|
|
%GeneratedFileHash{content_hash: ^content_hash} ->
|
|
{:ok, %{relative_path: relative_path, content_hash: content_hash, written?: false}}
|
|
|
|
_existing ->
|
|
full_path = output_path(project, relative_path)
|
|
:ok = File.mkdir_p(Path.dirname(full_path))
|
|
:ok = File.write(full_path, content)
|
|
|
|
attrs = %{
|
|
project_id: project_id,
|
|
relative_path: relative_path,
|
|
content_hash: content_hash,
|
|
updated_at: now
|
|
}
|
|
|
|
%GeneratedFileHash{}
|
|
|> GeneratedFileHash.changeset(attrs)
|
|
|> Repo.insert!(
|
|
on_conflict: [set: [content_hash: content_hash, updated_at: now]],
|
|
conflict_target: [:project_id, :relative_path]
|
|
)
|
|
|
|
{:ok, %{relative_path: relative_path, content_hash: content_hash, written?: true}}
|
|
end
|
|
end
|
|
|
|
def list_generated_files(project_id) when is_binary(project_id) do
|
|
{:ok,
|
|
Repo.all(
|
|
from generated_file in GeneratedFileHash,
|
|
where: generated_file.project_id == ^project_id,
|
|
order_by: [asc: generated_file.relative_path]
|
|
)}
|
|
end
|
|
|
|
def delete_generated_file(project_id, relative_path) when is_binary(project_id) and is_binary(relative_path) do
|
|
project = Projects.get_project!(project_id)
|
|
|
|
case File.rm(output_path(project, relative_path)) do
|
|
:ok -> :ok
|
|
{:error, :enoent} -> :ok
|
|
{:error, reason} -> {:error, reason}
|
|
end
|
|
|
|
Repo.delete_all(
|
|
from generated_file in GeneratedFileHash,
|
|
where: generated_file.project_id == ^project_id and generated_file.relative_path == ^relative_path
|
|
)
|
|
|
|
:ok
|
|
end
|
|
|
|
defp output_path(project, relative_path) do
|
|
Path.join([Projects.project_data_dir(project), "html", relative_path])
|
|
end
|
|
|
|
defp sha256(content) do
|
|
:crypto.hash(:sha256, content)
|
|
|> Base.encode16(case: :lower)
|
|
end
|
|
end
|