Class: Lyman::CLI::Manifest

Inherits:
Object
  • Object
show all
Defined in:
lib/lyman/cli/manifest.rb

Overview

Reads and writes <project_root>/.lyman/manifest.yml — the record that makes update cheap (hash comparison instead of guessing) and eject meaningful (a tombstone, not a deletion). See docs/design/deployment.md.

Constant Summary collapse

RELATIVE_PATH =
File.join(".lyman", "manifest.yml")
PRISTINE_DIR =
File.join(".lyman", "pristine")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_root) ⇒ Manifest

Returns a new instance of Manifest.



41
42
43
44
# File 'lib/lyman/cli/manifest.rb', line 41

def initialize(project_root)
  @project_root = project_root
  @data = read
end

Instance Attribute Details

#project_rootObject (readonly)

Returns the value of attribute project_root.



13
14
15
# File 'lib/lyman/cli/manifest.rb', line 13

def project_root
  @project_root
end

Class Method Details

.find(start_dir = Dir.pwd) ⇒ Object

Walks up from start_dir looking for .lyman/manifest.yml, the same way git walks up looking for .git. Returns the project root or nil.



17
18
19
20
21
22
23
24
25
26
# File 'lib/lyman/cli/manifest.rb', line 17

def self.find(start_dir = Dir.pwd)
  dir = File.expand_path(start_dir)
  loop do
    return dir if File.exist?(File.join(dir, RELATIVE_PATH))
    parent = File.dirname(dir)
    break if parent == dir
    dir = parent
  end
  nil
end

.find!(start_dir = Dir.pwd) ⇒ Object

Every command except new needs a project to act on; this is the one place that error is raised, worded for an agent to act on directly.



30
31
32
33
34
35
# File 'lib/lyman/cli/manifest.rb', line 30

def self.find!(start_dir = Dir.pwd)
  find(start_dir) || raise(Thor::Error, <<~MSG.strip)
    Not inside a lyman project (no .lyman/manifest.yml found walking up
    from #{start_dir}). Run `lyman new NAME` to create one.
  MSG
end

.load(project_root) ⇒ Object



37
38
39
# File 'lib/lyman/cli/manifest.rb', line 37

def self.load(project_root)
  new(project_root)
end

Instance Method Details

#artifact(name) ⇒ Object



58
59
60
# File 'lib/lyman/cli/manifest.rb', line 58

def artifact(name)
  artifacts[name]
end

#artifactsObject



54
55
56
# File 'lib/lyman/cli/manifest.rb', line 54

def artifacts
  @data["artifacts"] ||= {}
end

#delete_artifact(name) ⇒ Object



66
67
68
# File 'lib/lyman/cli/manifest.rb', line 66

def delete_artifact(name)
  artifacts.delete(name)
end

#lyman_versionObject



50
51
52
# File 'lib/lyman/cli/manifest.rb', line 50

def lyman_version
  @data["lyman"]
end

#pathObject



46
47
48
# File 'lib/lyman/cli/manifest.rb', line 46

def path
  File.join(project_root, RELATIVE_PATH)
end

#pristine?(rel_path) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/lyman/cli/manifest.rb', line 93

def pristine?(rel_path)
  File.exist?(pristine_path(rel_path))
end

#pristine_path(rel_path) ⇒ Object

The pristine cache mirrors the planted tree (.lyman/pristine/lib/ lyman/conversation.rb, not a flat name) — collision-proof, and browsable as a shadow of exactly what was planted where.



80
81
82
# File 'lib/lyman/cli/manifest.rb', line 80

def pristine_path(rel_path)
  File.join(project_root, PRISTINE_DIR, rel_path)
end

#read_pristine(rel_path) ⇒ Object



89
90
91
# File 'lib/lyman/cli/manifest.rb', line 89

def read_pristine(rel_path)
  File.read(pristine_path(rel_path))
end

#saveObject



70
71
72
73
74
75
# File 'lib/lyman/cli/manifest.rb', line 70

def save
  @data["lyman"] = Lyman::CLI::VERSION
  FileUtils.mkdir_p(File.dirname(path))
  File.write(path, dump)
  self
end

#set_artifact(name, attrs) ⇒ Object



62
63
64
# File 'lib/lyman/cli/manifest.rb', line 62

def set_artifact(name, attrs)
  artifacts[name] = attrs
end

#write_pristine(rel_path, bytes) ⇒ Object



84
85
86
87
# File 'lib/lyman/cli/manifest.rb', line 84

def write_pristine(rel_path, bytes)
  FileUtils.mkdir_p(File.dirname(pristine_path(rel_path)))
  File.write(pristine_path(rel_path), bytes)
end