Class: FileDigests::DigestDatabase

Inherits:
Object
  • Object
show all
Defined in:
lib/file-digests.rb

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ DigestDatabase

Returns a new instance of DigestDatabase.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/file-digests.rb', line 17

def initialize path
  @db = SQLite3::Database.new path.to_s
  @db.results_as_hash = true

  execute 'PRAGMA journal_mode = "WAL"'
  execute 'PRAGMA synchronous = "NORMAL"'
  execute 'PRAGMA locking_mode = "EXCLUSIVE"'
  execute 'PRAGMA cache_size = "5000"'

  unless execute("SELECT name FROM sqlite_master WHERE type='table' AND name = 'digests'").length == 1
    execute 'PRAGMA encoding = "UTF-8"'
    execute "CREATE TABLE digests (
      id INTEGER PRIMARY KEY,
      filename TEXT,
      mtime TEXT,
      digest TEXT,
      digest_check_time TEXT)"
    execute "CREATE UNIQUE INDEX digests_filename ON digests(filename)"
  end

  @missing_files = Hash[@db.prepare("SELECT filename, digest FROM digests").execute!]
  @new_files = {}

  prepare_method :insert, "INSERT INTO digests (filename, mtime, digest, digest_check_time) VALUES (?, ?, ?, datetime('now'))"
  prepare_method :find_by_filename, "SELECT id, mtime, digest FROM digests WHERE filename = ?"
  prepare_method :touch_digest_check_time, "UPDATE digests SET digest_check_time = datetime('now') WHERE id = ?"
  prepare_method :update_mtime_and_digest, "UPDATE digests SET mtime = ?, digest = ?, digest_check_time = datetime('now') WHERE id = ?"
  prepare_method :update_mtime, "UPDATE digests SET mtime = ?, digest_check_time = datetime('now') WHERE id = ?"
  prepare_method :delete_by_filename, "DELETE FROM digests WHERE filename = ?"
end

Instance Method Details

#insert_or_update(file_path, mtime, digest, counters) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/file-digests.rb', line 48

def insert_or_update file_path, mtime, digest, counters
  result = find_by_filename file_path

  if found = result.next_hash
    raise "Multiple records found" if result.next

    @missing_files.delete(file_path)

    if found['digest'] == digest
      counters[:good] += 1
      # puts "GOOD: #{file_path}" unless QUIET
      unless TEST_ONLY
        if found['mtime'] == mtime
          touch_digest_check_time found['id']
        else
          update_mtime mtime, found['id']
        end
      end
    else
      if found['mtime'] == mtime # Digest is different and mtime is the same
        counters[:likely_damaged] += 1
        STDERR.puts "LIKELY DAMAGED: #{file_path}"
      else
        counters[:updated] += 1
        puts "UPDATED: #{file_path}" unless QUIET
        unless TEST_ONLY
          update_mtime_and_digest mtime, digest, found['id']
        end
      end
    end
  else
    counters[:new] += 1
    puts "NEW: #{file_path}" unless QUIET
    unless TEST_ONLY
      @new_files[file_path] = digest
      insert file_path, mtime, digest
    end
  end
end

#process_missing_files(counters) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/file-digests.rb', line 88

def process_missing_files counters
  @missing_files.delete_if do |filename, digest|
    if @new_files.value?(digest)
      counters[:renamed] += 1
      unless TEST_ONLY
        delete_by_filename filename
      end
      true
    end
  end

  if (counters[:missing] = @missing_files.length) > 0
    puts "\nMISSING FILES:"
    @missing_files.sort.to_h.each do |filename, digest|
      puts filename
    end
    unless TEST_ONLY
      puts "Remove missing files from the database (y/n)?"
      if STDIN.gets.strip.downcase == "y"
        @db.transaction do
          @missing_files.each do |filename, digest|
            delete_by_filename filename
          end
        end
      end
    end
  end
end