Class: Agent::Lock::Tree
- Inherits:
-
Object
- Object
- Agent::Lock::Tree
- Defined in:
- lib/agent/lock/tree.rb
Overview
The working tree a lock is about, and where its locks are kept.
Locks live in <git-common-dir>/agent-locks, which is chosen rather than
~/.agent-locks or a dotfile at the root for three reasons. Git cannot
track anything inside .git, so no repository needs a .gitignore line
and git clean -xdf cannot wipe the locks. Every worktree of a
repository resolves --git-common-dir to the same directory, so one
store serves all of them. And it dies with the checkout, instead of
outliving it in a home directory nobody thinks to sweep.
Outside a repository the store falls back to ~/.agent-locks, keyed by a
digest of the tree, since there is no .git to hide in.
Instance Attribute Summary collapse
-
#root ⇒ String
readonly
Absolute, symlinks resolved, so /tmp and /private/tmp cannot become two names for one tree.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(dir = Dir.pwd) ⇒ Tree
constructor
A new instance of Tree.
-
#relative(path) ⇒ String
A path the user typed, read from where they stand, as a name inside this tree.
-
#store_dir ⇒ String
$AGENT_LOCK_DIR environment variable if defined, or 'agent-locks' inside .git if available, or the ~/.agent-locks/
in user's home folder. -
#worktree? ⇒ Boolean
A linked worktree rather than the original checkout.
Constructor Details
#initialize(dir = Dir.pwd) ⇒ Tree
Returns a new instance of Tree.
31 32 33 34 35 |
# File 'lib/agent/lock/tree.rb', line 31 def initialize(dir = Dir.pwd) @dir = File.realpath(dir) @root = git("rev-parse", "--show-toplevel") || @dir @root = File.realpath(@root) end |
Instance Attribute Details
#root ⇒ String (readonly)
Returns absolute, symlinks resolved, so /tmp and /private/tmp cannot become two names for one tree.
29 30 31 |
# File 'lib/agent/lock/tree.rb', line 29 def root @root end |
Class Method Details
.for(dir = Dir.pwd) ⇒ Tree
24 |
# File 'lib/agent/lock/tree.rb', line 24 def for(dir = Dir.pwd) = new(dir) |
Instance Method Details
#relative(path) ⇒ String
A path the user typed, read from where they stand, as a name inside this tree.
There used to be a fallback to the basename for anything outside the
root, so /etc/passwd quietly locked the tree's own passwd: an agent
was told it held something it had never asked for, and the thing it had
asked for stayed unguarded. Outside is now an error.
The path is compared as typed first, then with symlinks resolved, so an
alias of the tree (/tmp for /private/tmp) is still inside it, while
an in-tree symlink that points elsewhere keeps its in-tree name, which is
what the lock is about. The path need not exist: an agent claims a file
before writing it.
69 70 71 72 73 |
# File 'lib/agent/lock/tree.rb', line 69 def relative(path) absolute = File.absolute_path(path, @dir) inside(absolute) || inside(resolve(absolute)) || raise(Scope::Invalid, "#{path} is outside the tree #{root}") end |
#store_dir ⇒ String
$AGENT_LOCK_DIR environment variable if defined, or 'agent-locks'
inside .git if available, or the ~/.agent-locks/
45 46 47 48 49 50 |
# File 'lib/agent/lock/tree.rb', line 45 def store_dir return File.(ENV["AGENT_LOCK_DIR"]) if ENV["AGENT_LOCK_DIR"] return File.join(common_dir, "agent-locks") if common_dir File.join(Dir.home, ".agent-locks", ::Digest::SHA256.hexdigest(root)[0, 12]) end |
#worktree? ⇒ Boolean
Returns a linked worktree rather than the original checkout.
38 |
# File 'lib/agent/lock/tree.rb', line 38 def worktree? = !git_dir.nil? && git_dir != common_dir |