Class: Ibex::Watch::SourceSnapshot

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/watch/source_snapshot.rb,
sig/ibex/watch/source_snapshot.rbs

Overview

Stable metadata and content fingerprints for watched source paths.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(paths) ⇒ SourceSnapshot

Returns a new instance of SourceSnapshot.

RBS:

  • (Array[String] paths) -> void

Parameters:

  • paths (Array[String])


13
14
15
16
17
# File 'lib/ibex/watch/source_snapshot.rb', line 13

def initialize(paths)
  @paths = paths.map { |path| File.expand_path(path) }.uniq.sort.freeze
  @entries = @paths.to_h { |path| [path, fingerprint(path)] }.freeze #: Hash[String, Hash[Symbol, untyped]]
  freeze
end

Instance Attribute Details

#entriesHash[String, Hash[Symbol, untyped]] (readonly)

Signature:

  • Hash[String, Hash[Symbol, untyped]]

Returns:

  • (Hash[String, Hash[Symbol, untyped]])


34
35
36
# File 'lib/ibex/watch/source_snapshot.rb', line 34

def entries
  @entries
end

#pathsArray[String] (readonly)

Signature:

  • Array[String]

Returns:

  • (Array[String])


10
11
12
# File 'lib/ibex/watch/source_snapshot.rb', line 10

def paths
  @paths
end

Instance Method Details

#==(other) ⇒ Boolean

RBS:

  • (SourceSnapshot other) -> bool

Parameters:

Returns:

  • (Boolean)


20
21
22
# File 'lib/ibex/watch/source_snapshot.rb', line 20

def ==(other)
  @entries == other.__send__(:entries)
end

#add_resolved_target(value, path) ⇒ void

This method returns an undefined value.

RBS:

  • (Hash[Symbol, untyped] value, String path) -> void

Parameters:

  • value (Hash[Symbol, untyped])
  • path (String)


82
83
84
85
86
87
88
89
90
# File 'lib/ibex/watch/source_snapshot.rb', line 82

def add_resolved_target(value, path)
  target = File.realpath(path)
  stat = File.stat(target)
  value[:resolved_path] = target
  value[:resolved] = stat_signature(stat)
  value[:resolved][:sha256] = Digest::SHA256.file(target).hexdigest if stat.file?
rescue SystemCallError => e
  value[:resolved] = { kind: :error, error: e.class.name, errno: e.respond_to?(:errno) ? e.errno : nil }
end

#entry(path) ⇒ Hash[Symbol, untyped]?

RBS:

  • (String path) -> Hash[Symbol, untyped]?

Parameters:

  • path (String)

Returns:

  • (Hash[Symbol, untyped], nil)


37
38
39
# File 'lib/ibex/watch/source_snapshot.rb', line 37

def entry(path)
  @entries[path]
end

#file_kind(stat) ⇒ Symbol

RBS:

  • (File::Stat stat) -> Symbol

Parameters:

  • stat (File::Stat)

Returns:

  • (Symbol)


68
69
70
71
72
73
74
# File 'lib/ibex/watch/source_snapshot.rb', line 68

def file_kind(stat)
  return :file if stat.file?
  return :directory if stat.directory?
  return :symlink if stat.symlink?

  :other
end

#fingerprint(path) ⇒ Hash[Symbol, untyped]

RBS:

  • (String path) -> Hash[Symbol, untyped]

Parameters:

  • path (String)

Returns:

  • (Hash[Symbol, untyped])


44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ibex/watch/source_snapshot.rb', line 44

def fingerprint(path)
  stat = File.lstat(path)
  value = stat_signature(stat)
  if stat.symlink?
    value[:readlink] = File.readlink(path)
    add_resolved_target(value, path)
  else
    value[:resolved_path] = File.realpath(path)
    value[:sha256] = Digest::SHA256.file(path).hexdigest if stat.file?
  end
  value
rescue SystemCallError => e
  { kind: :error, error: e.class.name, errno: e.respond_to?(:errno) ? e.errno : nil }
end

#nanoseconds(time) ⇒ Integer

RBS:

  • (Time time) -> Integer

Parameters:

  • time (Time)

Returns:

  • (Integer)


77
78
79
# File 'lib/ibex/watch/source_snapshot.rb', line 77

def nanoseconds(time)
  (time.to_i * 1_000_000_000) + time.nsec
end

#stat_signature(stat) ⇒ Hash[Symbol, untyped]

RBS:

  • (File::Stat stat) -> Hash[Symbol, untyped]

Parameters:

  • stat (File::Stat)

Returns:

  • (Hash[Symbol, untyped])


60
61
62
63
64
65
# File 'lib/ibex/watch/source_snapshot.rb', line 60

def stat_signature(stat)
  {
    kind: file_kind(stat), dev: stat.dev, ino: stat.ino, size: stat.size,
    mtime_ns: nanoseconds(stat.mtime), ctime_ns: nanoseconds(stat.ctime)
  }
end

#unchanged_since?(older) ⇒ Boolean

Every path in this snapshot must have had the same value in the older snapshot.

RBS:

  • (SourceSnapshot older) -> bool

Parameters:

Returns:

  • (Boolean)


26
27
28
29
30
# File 'lib/ibex/watch/source_snapshot.rb', line 26

def unchanged_since?(older)
  @paths.all? do |path|
    older.__send__(:entry, path) == @entries.fetch(path)
  end
end