Class: Rails::Hyperdrive::LockFile
- Inherits:
-
Object
- Object
- Rails::Hyperdrive::LockFile
- Defined in:
- lib/rails/hyperdrive/lock_file.rb
Overview
installed_at is volatile metadata, never an input to any comparison.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- SCHEMA_VERSION =
2- STATE_PRESENT =
"present".freeze
- STATE_REMOVED =
"removed-by-user".freeze
- DISABLED_KEYS =
{ skill: "skills", guideline: "guidelines", agent: "agents", command: "commands" }.freeze
Instance Attribute Summary collapse
-
#claude_md_state ⇒ Object
Returns the value of attribute claude_md_state.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#schema_version ⇒ Object
readonly
Returns the value of attribute schema_version.
Class Method Summary collapse
-
.load(path) ⇒ Object
Load existing lock state from disk (absent file → empty lock).
-
.orphan_reason(source_label:, source_gem:, bundled:) ⇒ Object
Every surface reporting an orphan must name the same two cases, or a sync and a bundle install would disagree about why a file is stranded.
Instance Method Summary collapse
- #carry(entry) ⇒ Object
-
#carry_settings(other) ⇒ Object
Adopt the state that is not derived from installed content, so rewriting the file preserves it.
- #disabled?(type, name) ⇒ Boolean
- #each_entry(&block) ⇒ Object
-
#enabled_gems ⇒ Object
Hand-editable list of gems the app opts into as companions.
- #entry(file_path) ⇒ Object
- #guideline_paths ⇒ Object
-
#initialize(path) ⇒ LockFile
constructor
A new instance of LockFile.
- #read ⇒ Object
-
#schema_ahead? ⇒ Boolean
A lock written by a newer installer holds state this one cannot read, so rewriting it would silently drop the user's settings.
- #schema_ahead_message(display_path) ⇒ Object
- #to_yaml ⇒ Object
- #upsert(path:, kind:, source_gem:, source_version:, source_sha:, installed_at:) ⇒ Object
Constructor Details
#initialize(path) ⇒ LockFile
Returns a new instance of LockFile.
37 38 39 40 41 42 43 44 45 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 37 def initialize(path) @path = path.to_s @claude_md_state = nil # nil = no lock has been written yet @files = {} # path(String) => Entry @document = {} # raw parsed YAML, kept so unknown keys survive @disabled = empty_disabled @enabled = [] @schema_version = nil end |
Instance Attribute Details
#claude_md_state ⇒ Object
Returns the value of attribute claude_md_state.
23 24 25 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 23 def claude_md_state @claude_md_state end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
22 23 24 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 22 def path @path end |
#schema_version ⇒ Object (readonly)
Returns the value of attribute schema_version.
22 23 24 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 22 def schema_version @schema_version end |
Class Method Details
.load(path) ⇒ Object
Load existing lock state from disk (absent file → empty lock).
26 27 28 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 26 def self.load(path) new(path).tap(&:read) end |
.orphan_reason(source_label:, source_gem:, bundled:) ⇒ Object
Every surface reporting an orphan must name the same two cases, or a sync and a bundle install would disagree about why a file is stranded.
32 33 34 35 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 32 def self.orphan_reason(source_label:, source_gem:, bundled:) return "no longer shipped by #{source_label}" unless bundled "#{source_gem} is still bundled but did not offer this file" end |
Instance Method Details
#carry(entry) ⇒ Object
123 124 125 126 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 123 def carry(entry) return unless entry && entry.path @files[entry.path] = entry end |
#carry_settings(other) ⇒ Object
Adopt the state that is not derived from installed content, so rewriting the file preserves it.
105 106 107 108 109 110 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 105 def carry_settings(other) @document = other.document.dup @disabled = other.disabled_lists.dup @enabled = other.enabled_gems.dup self end |
#disabled?(type, name) ⇒ Boolean
94 95 96 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 94 def disabled?(type, name) Array(@disabled[type.to_sym]).include?(name.to_s) end |
#each_entry(&block) ⇒ Object
90 91 92 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 90 def each_entry(&block) @files.values.each(&block) end |
#enabled_gems ⇒ Object
Hand-editable list of gems the app opts into as companions.
99 100 101 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 99 def enabled_gems @enabled end |
#entry(file_path) ⇒ Object
82 83 84 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 82 def entry(file_path) @files[file_path.to_s] end |
#guideline_paths ⇒ Object
86 87 88 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 86 def guideline_paths @files.values.select { |e| e.kind == "guideline" }.map(&:path) end |
#read ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 47 def read return self unless File.exist?(@path) data = YAML.safe_load(File.read(@path)) return self unless data.is_a?(Hash) @document = data @schema_version = data["version"] claude_md = data["claude_md"] @claude_md_state = claude_md["state"] if claude_md.is_a?(Hash) @disabled = parse_disabled(data["disabled"]) @enabled = parse_enabled(data["enabled"]) Array(data["files"]).each do |raw| next unless raw.is_a?(Hash) entry = build_entry(raw) @files[entry.path] = entry if entry.path end self rescue Psych::SyntaxError self end |
#schema_ahead? ⇒ Boolean
A lock written by a newer installer holds state this one cannot read, so rewriting it would silently drop the user's settings. A missing or non-numeric version reads as not ahead: every lock ever written carries an integer version, and a hand-broken one must not block a sync.
73 74 75 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 73 def schema_ahead? @schema_version.is_a?(Numeric) && @schema_version > SCHEMA_VERSION end |
#schema_ahead_message(display_path) ⇒ Object
77 78 79 80 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 77 def (display_path) "#{display_path} was written by a newer rails-hyperdrive (lock schema #{@schema_version}, " \ "this installer supports #{SCHEMA_VERSION}); upgrade rails-hyperdrive" end |
#to_yaml ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 128 def to_yaml carried = @document["claude_md"] carried = {} unless carried.is_a?(Hash) document = @document.merge( "version" => SCHEMA_VERSION, "claude_md" => carried.merge("state" => @claude_md_state), "disabled" => DISABLED_KEYS.each_with_object({}) { |(type, key), h| h[key] = @disabled[type] }, "enabled" => @enabled, "files" => @files.values.sort_by(&:path).map { |e| serialize_entry(e) } ) # A nil state means no import line is being managed. Recording one anyway # would make the next run read the absent line as a deletion the user # made, and never add it back. document.delete("claude_md") if @claude_md_state.nil? document.to_yaml end |
#upsert(path:, kind:, source_gem:, source_version:, source_sha:, installed_at:) ⇒ Object
112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rails/hyperdrive/lock_file.rb', line 112 def upsert(path:, kind:, source_gem:, source_version:, source_sha:, installed_at:) @files[path.to_s] = Entry.new( path: path.to_s, kind: kind.to_s, source_gem: source_gem.to_s, source_version: source_version.to_s, source_sha: source_sha.to_s, installed_at: installed_at.to_s ) end |