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.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/file-digests.rb', line 38

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



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/file-digests.rb', line 69

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



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/file-digests.rb', line 109

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