Module: Pikuri::Workspace::ProjectRoot
- Defined in:
- lib/pikuri/workspace/project_root.rb
Overview
Climb from a working directory toward the project root, looking for a VCS
marker (+.git+ / .hg / .svn). Host binaries use it to decide the
Filesystem project_root: — the writable containment ceiling and (under
the Bubblewrap sandbox) the bind-mount root, so +git+/+make+ can climb
inside the sandbox to find <repo>/.git / <repo>/Makefile.
Why VCS-only markers
Build-system fallbacks (+Gemfile+, pyproject.toml, package.json,
pom.xml, build.gradle, ...) were rejected: they aren't reliable root
markers in multi-module setups (a Gradle subproject, a Maven module, a
yarn-workspaces package each has its own), so climbing for them lands on
the nearest subtree root — and a wrong project_root means the sandbox
bind-mounts the wrong tree and git can't see the real .git. VCS markers
sit only at the actual root (or a submodule root, the user's intended
boundary when they cd'd in).
If no marker is found within the safe-climb bounds, ProjectRoot.find returns nil
and the caller falls back to the launch cwd (losing visibility to sibling
code; git init or invoke from the project root to fix).
Safety bounds
The climb refuses to enter the home directory or a system root
(DENIED_CLIMB_ROOTS) — reaching either means "left the project tree" and
the climb stops. The starting cwd is always considered even if banned
(the user invoked there); only ancestors are gated.
Priority
All markers are checked at each ancestor before climbing, so the
nearest VCS marker wins regardless of type.
Constant Summary collapse
- DENIED_CLIMB_ROOTS =
Climb-up boundary. Overlaps Filesystem::DENIED_PROJECT_ROOTS but kept separate — different semantics (climb boundary vs. project_root rejection), may drift apart.
%w[ / /etc /var /proc /sys /dev /boot /root /usr /opt /lib /lib64 /bin /sbin /tmp ].map { |p| Pathname.new(p) }.freeze
- VCS_MARKERS =
VCS metadata dirs/files.
.gitis the common case; +.hg+/+.svn+ for the rare users on those.File.exist?matches both a directory (normal checkout) and a regular file (+.git+ in a worktree/submodule). %w[.git .hg .svn].freeze
Class Method Summary collapse
-
.find(cwd:, markers: VCS_MARKERS) ⇒ Pathname?
Find the nearest ancestor of
cwdcontaining any ofmarkers.
Class Method Details
.find(cwd:, markers: VCS_MARKERS) ⇒ Pathname?
Find the nearest ancestor of cwd containing any of markers. See the
class header for the safety bounds and priority.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/pikuri/workspace/project_root.rb', line 61 def self.find(cwd:, markers: VCS_MARKERS) current = Pathname.new(cwd).realpath home = Pathname.new(Dir.home).realpath loop do return current if markers.any? { |m| current.join(m).exist? } parent = current.parent return nil if parent == current # at the filesystem root return nil if parent == home # crossing into $HOME return nil if DENIED_CLIMB_ROOTS.include?(parent) current = parent end end |