Store.Project.Source (fnord v0.9.27)

View Source

Abstraction over "where does this project's source come from?"

Git projects index the default branch's tree: enumeration comes from git ls-tree, content from git show <branch>:<path>, and the freshness key is the git blob SHA. A user on a feature branch with WIP changes still sees the default-branch snapshot indexed, which is what the rest of the codebase (search, file_notes, reviewer) expects as its ground truth.

Non-git projects fall back to the filesystem: enumeration via find on source_root, content via File.read, freshness via sha256 of the file contents.

The mode is decided once per project (mode/1) and all reads/hashes go through this module so callers never branch on git-ness themselves.

Summary

Functions

Returns the default branch name when the project is in :git mode, nil otherwise. GitCli.default_branch/1 is NOT cached today - it forks 2-4 git subprocesses per call (symbolic-ref, then rev-parse probes for main/master). Callers under async_stream should memoize if the overhead matters; cached_ls_tree/2 in this module uses the returned branch as part of its cache key but does not cache the branch lookup itself.

True when rel_path still exists under the project's active source. Used by delete_missing_files to scope deletion correctly: a file present in the working tree but not on the default branch is "missing" for our purposes.

Returns the freshness hash for rel_path under the project's active source. In git mode that's the blob SHA (fetched from ls-tree if available, else computed via git hash-object). In fs mode, sha256 of the file's current content.

Enumerates all source items in the project as %{rel_path, abs_path, hash} maps. In git mode the list reflects the default branch's tree (blob SHA as hash); in fs mode it reflects the working tree's filesystem walk (sha256 as hash, computed lazily by callers — the listing returns hash: nil for fs mode).

Returns :git when the project's source_root is a git repo whose default branch can be resolved, and :fs otherwise.

Returns the content of rel_path under the project's active source. Routed to git show in git mode, File.read in fs mode.

Types

listing_entry()

@type listing_entry() :: %{
  rel_path: String.t(),
  abs_path: String.t(),
  hash: String.t() | nil
}

mode()

@type mode() :: :git | :fs

Functions

default_branch(project)

@spec default_branch(Store.Project.t()) :: String.t() | nil

Returns the default branch name when the project is in :git mode, nil otherwise. GitCli.default_branch/1 is NOT cached today - it forks 2-4 git subprocesses per call (symbolic-ref, then rev-parse probes for main/master). Callers under async_stream should memoize if the overhead matters; cached_ls_tree/2 in this module uses the returned branch as part of its cache key but does not cache the branch lookup itself.

exists?(project, rel_path)

@spec exists?(Store.Project.t() | nil, String.t() | nil) :: boolean()

True when rel_path still exists under the project's active source. Used by delete_missing_files to scope deletion correctly: a file present in the working tree but not on the default branch is "missing" for our purposes.

hash(project, rel_path)

@spec hash(Store.Project.t() | nil, String.t() | nil) ::
  {:ok, String.t()} | {:error, term()}

Returns the freshness hash for rel_path under the project's active source. In git mode that's the blob SHA (fetched from ls-tree if available, else computed via git hash-object). In fs mode, sha256 of the file's current content.

list(project)

@spec list(Store.Project.t()) :: [listing_entry()]

Enumerates all source items in the project as %{rel_path, abs_path, hash} maps. In git mode the list reflects the default branch's tree (blob SHA as hash); in fs mode it reflects the working tree's filesystem walk (sha256 as hash, computed lazily by callers — the listing returns hash: nil for fs mode).

Callers are responsible for applying project-level excludes and text/binary filtering; this function only answers "what source items exist?".

mode(arg1)

@spec mode(Store.Project.t() | nil) :: mode()

Returns :git when the project's source_root is a git repo whose default branch can be resolved, and :fs otherwise.

read(project, rel_path)

@spec read(Store.Project.t() | nil, String.t()) :: {:ok, binary()} | {:error, term()}

Returns the content of rel_path under the project's active source. Routed to git show in git mode, File.read in fs mode.