defmodule GitGud.Repositories.Storage do
@moduledoc """
On-disk layout for bare git repositories.
Layout:
<base>/<owner_handle>/<repo_name>.git
<base>/<owner_handle>/<repo_name>.wiki.git
`owner_handle` resolves the same way for users (local-part of their
email until we grow a `username` field) and organizations (their
`handle`). The handle namespace is shared — see
`GitGud.Repositories.resolve_namespace/1` for collision handling.
"""
alias GitGud.Accounts.User
alias GitGud.Organizations.Organization
@type owner :: User.t() | Organization.t()
@default_base "priv/repos"
@doc "Absolute base path for repo storage."
def base_path do
Application.get_env(:git_gud, __MODULE__, [])
|> Keyword.get(:base_path, @default_base)
|> Path.expand()
end
@doc "Owner-namespaced directory."
def owner_dir(owner), do: Path.join(base_path(), owner_handle(owner))
@doc "Bare repo path on disk."
def repo_path(owner, repo_name) when is_binary(repo_name) do
Path.join(owner_dir(owner), repo_name <> ".git")
end
@doc "Sister wiki bare repo path on disk."
def wiki_path(owner, repo_name) when is_binary(repo_name) do
Path.join(owner_dir(owner), repo_name <> ".wiki.git")
end
def wiki_path_for(repo_path) when is_binary(repo_path) do
String.replace_suffix(repo_path, ".git", ".wiki.git")
end
@doc "Stable string handle for a user or an organization."
def owner_handle(%User{handle: h}) when is_binary(h) and h != "", do: h
def owner_handle(%User{email: email}) when is_binary(email),
do: email |> String.split("@", parts: 2) |> List.first()
def owner_handle(%Organization{handle: handle}) when is_binary(handle), do: handle
@doc """
Resolve the namespace handle for a Repository. Prefers the organization
if the repo is org-owned, falls back to the user owner. The repo is
expected to have `:owner` and `:organization` preloaded.
"""
def repo_handle(%GitGud.Repositories.Repository{} = repo) do
cond do
match?(%Organization{handle: _}, repo.organization) -> repo.organization.handle
match?(%User{}, repo.owner) -> owner_handle(repo.owner)
true -> raise "repo has no namespace; preload :owner and :organization first"
end
end
end
2.2 KiB · text
5af55d9