Packages

Simple Elixir Library for creating self-cleaning tmp directories

Current section

Files

Jump to
tempdir lib tempdir.ex
Raw

lib/tempdir.ex

defmodule TempDir do
@moduledoc """
This GenServer is a module for creating temporary
directories that auto cleanup after themselves on
process exit.
"""
use GenServer
defmodule Directory do
defstruct path: "", files: []
end
# Public API
@doc """
Starts a new tmp process that creates its own tmp
directory.
"""
def start_link(default \\ %{}) do
GenServer.start_link(__MODULE__, default)
end
@doc """
Manually terminates a tmp process and performs cleanup.
"""
def stop(pid), do: GenServer.stop(pid)
@doc """
Gets the tmp path for the process.
"""
def get_path(pid), do: GenServer.call(pid, :path)
@doc """
Gets the tmp path for the process.
"""
def get_files(pid), do: GenServer.call(pid, :files)
@doc """
Creates a temporary file in the current processes'
directory.
"""
def create_file(pid), do: GenServer.call(pid, :create_file)
# Server Callbacks
def init(args) do
case mkdir(args) do
{:ok, state} -> {:ok, state}
{:error, reason} -> {:stop, reason}
end
end
def handle_call(:path, _from, state), do: {:reply, state.path, state}
def handle_call(:files, _from, state), do: {:reply, state.files, state}
def handle_call(:create_file, _from, state) do
case mkfile(state, %{}) do
{:ok, io_device} -> {:reply, io_device, %Directory{state | files: state.files ++ [io_device]}}
{:error, reason} -> {:stop, reason, state}
end
end
def handle_info({:DOWN, _, _, _, _}, state) do
{:stop, "main process died", state}
end
def terminate(_reason, state), do: cleanup(state)
defp cleanup(state), do: cleanup(File.exists?(state.path), state.path)
defp cleanup(true, path), do: File.rm_rf(path)
defp cleanup(false, _path), do: {:ok, []}
@compile {:inline, i: 1}
defp i(integer), do: Integer.to_string(integer)
defp mkdir(args) do
dir_prefix = args[:dir_prefix] || "elixir"
tmp_dir = args[:tmp_dir] || "/tmp"
path = gen_path(dir_prefix, tmp_dir)
case File.mkdir_p(path) do
:ok -> {:ok, %Directory{path: path}}
{:error, reason} -> {:error, reason}
end
end
defp mkfile(state, args) do
file_prefix = args[:file_prefix] || ""
file_path = state.path <> "/" <> file_prefix <> gen_name()
File.open(file_path, [:write])
end
defp gen_name do
{_mega, sec, micro} = :os.timestamp
scheduler_id = :erlang.system_info(:scheduler_id)
i(sec) <> "-" <> i(micro) <> "-" <> i(scheduler_id)
end
defp gen_path(prefix, tmp) do
tmp <> "/" <> prefix <> "-" <> gen_name()
end
end