Class: Nandi::Lockfile

Inherits:
Object
  • Object
show all
Defined in:
lib/nandi/lockfile.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db_name = nil) ⇒ Lockfile

Returns a new instance of Lockfile.



28
29
30
# File 'lib/nandi/lockfile.rb', line 28

def initialize(db_name = nil)
  @db_name = db_name || Nandi.config.default.name
end

Instance Attribute Details

#db_nameObject (readonly)

Returns the value of attribute db_name.



8
9
10
# File 'lib/nandi/lockfile.rb', line 8

def db_name
  @db_name
end

Class Method Details

.clear_instances!Object



21
22
23
# File 'lib/nandi/lockfile.rb', line 21

def clear_instances!
  @instances = {}
end

.for(db_name) ⇒ Object

Registry pattern using class variables to maintain singleton instances per database. This ensures that lockfile operations for the same database always work with the same instance, maintaining consistency.



14
15
16
17
18
19
# File 'lib/nandi/lockfile.rb', line 14

def for(db_name)
  @instances ||= {}
  # Handle nil by using :primary as default
  key = db_name.nil? ? :primary : db_name.to_sym
  @instances[key] ||= new(key)
end

Instance Method Details

#add(file_name:, source_digest:, compiled_digest:) ⇒ Object



42
43
44
45
46
47
48
49
# File 'lib/nandi/lockfile.rb', line 42

def add(file_name:, source_digest:, compiled_digest:)
  load!

  @lockfile[file_name] = {
    source_digest: source_digest,
    compiled_digest: compiled_digest,
  }
end

#create!Object



36
37
38
39
40
# File 'lib/nandi/lockfile.rb', line 36

def create!
  return if file_present?

  File.write(path, {}.to_yaml)
end

#file_present?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/nandi/lockfile.rb', line 32

def file_present?
  File.exist?(path)
end

#get(file_name) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/nandi/lockfile.rb', line 51

def get(file_name)
  load!

  {
    source_digest: @lockfile.dig(file_name, :source_digest),
    compiled_digest: @lockfile.dig(file_name, :compiled_digest),
  }
end

#load!Object



60
61
62
63
64
65
66
# File 'lib/nandi/lockfile.rb', line 60

def load!
  return @lockfile if @lockfile

  create! unless file_present?

  @lockfile = YAML.safe_load_file(path).with_indifferent_access
end

#persist!Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/nandi/lockfile.rb', line 68

def persist!
  load!
  # This is a somewhat ridiculous trick to avoid merge conflicts in git.
  #
  # Normally, new migrations are added to the bottom of the Nandi lockfile.
  # This is relatively unfriendly to git's merge algorithm, and means that
  # if someone merges a pull request with a completely unrelated migration,
  # you'll have to rebase to get yours merged as the last line of the file
  # will be seen as a conflict (both branches added content there).
  #
  # This is in contrast to something like Gemfile.lock, where changes tend
  # to be distributed throughout the file. The idea behind sorting by
  # SHA-256 hash is to distribute new Nandi lockfile entries evenly, but
  # also stably through the file. It needs to be stable or we'd have even
  # worse merge conflict problems (e.g. if we randomised the order on
  # writing the file, the whole thing would conflict pretty much every time
  # it was regenerated).
  content = @lockfile.to_h.deep_stringify_keys.sort_by do |k, _|
    Digest::SHA256.hexdigest(k)
  end.to_h.to_yaml

  File.write(path, content)
end