Packages
fnord
0.8.86
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/resolve_project.ex
# This module determines the current project based on the current working directory
# or falls back to git worktree and repository roots to ensure the most specific project
# context is identified.
defmodule ResolveProject do
@moduledoc """
Project resolution from the current working directory.
Behavior:
- If inside a git worktree, `resolve/1` will map the cwd to the repository root.
- Select the configured project whose root contains that directory, choosing the one with the deepest (longest) root path.
Returns `{:ok, project_name}` or `{:error, :not_in_project}`.
"""
@type project_name :: binary
# Find the configured project whose root most specifically contains the provided directory.
@spec resolve(cwd :: binary | nil) :: {:ok, project_name} | {:error, :not_in_project}
def resolve(cwd \\ nil) do
projects =
Settings.new()
|> Settings.get_projects()
|> Enum.flat_map(fn
{name, %{"root" => nil}} ->
UI.warn("Project '#{name}' missing 'root' configuration, skipping.")
[]
{name, %{"root" => root}} ->
[{Path.absname(root), name}]
{name, _project_config} ->
UI.warn("Project '#{name}' missing 'root' configuration, skipping.")
[]
end)
# If we are inside a git worktree, prefer resolving at the primary repo root
# so that project selection reflects the clone from which the worktree was created.
base_dir =
case cwd do
nil -> File.cwd!()
dir -> dir
end
repo_root_in_ctx =
case cwd do
nil ->
case System.cmd("git", ["rev-parse", "--is-inside-work-tree"],
cd: base_dir,
stderr_to_stdout: true
) do
{"true\n", 0} ->
case System.cmd("git", ["rev-parse", "--git-common-dir"],
cd: base_dir,
stderr_to_stdout: true
) do
{out, 0} ->
out
|> String.trim()
|> Path.dirname()
_ ->
nil
end
_ ->
nil
end
_ ->
nil
end
cwd_base = repo_root_in_ctx || base_dir
cwd_abs = Path.absname(cwd_base)
# Filter to projects whose root contains the current working directory.
matching_projects =
projects
|> Enum.filter(fn {root_abs, _name} -> Util.path_within_root?(cwd_abs, root_abs) end)
# Decide outcome based on whether any matching projects were found.
case matching_projects do
# No matching project roots found, return error.
[] ->
{:error, :not_in_project}
# Select the project with the deepest root path as the most specific match.
_ ->
{_, project_name} =
Enum.max_by(matching_projects, fn {root_abs, _} -> String.length(root_abs) end)
{:ok, project_name}
end
end
end