file-digests 0.0.13 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b587b7a9fd95e7a09b488041e0e80ee91e95f685b32b159f80c0bf494eabc77b
4
- data.tar.gz: 8b261afd681d6d6213b03c7dc65391e7533f04896e4e13f3c1bd73ddebca74a7
3
+ metadata.gz: d69e75a52c05cbc2caf912491be9fbaaadb5136a2dfc723920a9010d3e4c2592
4
+ data.tar.gz: f90deae82f2581d301d1cb7ba7c730e684b24f5c9582d6deb2581b9f2e6fa557
5
5
  SHA512:
6
- metadata.gz: aa76de6ec0bae260aa6bf289ead5a1443769f7823ae8886c2730b1235fbc9721eb39b8be56167ce654e41f6df5c5e6a10c8f1c08c03282cb32d580c09749e398
7
- data.tar.gz: a6ecefb33487aa3738b42922004d4b671b39172448a0af37d183ad6f41cf4c99be80083390bf28d695ba01badf2940a5e89cf4bf9220eca8ac9b00cba3faaa24
6
+ metadata.gz: 5ad20e936d21d42f56ed20250728eb0b7c2b9a034877e764f528c6e297853bb7724d6780a56b7c0f11a3df975c1d51fed04852ddb3f3ff9848f4c546167902e8
7
+ data.tar.gz: 27f86166310f420ac5858fa86c0233af666bbb2af40f53501a9f8e02205a3753151db5cfd6777558bbf0040e2472f9bc296d9382afebb8dd45f65fb981fc173b
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- QUIET = (ENV["QUIET"] == "true")
4
- TEST_ONLY = (ENV["TEST_ONLY"] == "true")
5
-
6
3
  require 'file-digests'
7
4
 
8
5
  FileDigests.perform_check
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENV["AUTO"] = "true"
4
+
5
+ require 'file-digests'
6
+
7
+ FileDigests.perform_check
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- QUIET = (ENV["QUIET"] == "true")
4
- TEST_ONLY = true
3
+ ENV["TEST_ONLY"] = "true"
5
4
 
6
5
  require 'file-digests'
7
6
 
@@ -1,4 +1,3 @@
1
-
2
1
  require 'date'
3
2
  require 'set'
4
3
  require 'digest'
@@ -8,34 +7,20 @@ require 'sqlite3'
8
7
 
9
8
  module FileDigests
10
9
 
11
- def self.ensure_dir_exists path
12
- if File.exist?(path)
13
- unless File.directory?(path)
14
- raise "#{path} is not a directory"
15
- end
16
- else
17
- FileUtils.mkdir_p path
18
- end
19
- end
20
-
21
- def self.measure_time
22
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
23
- yield
24
- elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).to_i
25
- puts "Elapsed time: #{elapsed / 3600}h #{(elapsed % 3600) / 60}m #{elapsed % 60}s" unless QUIET
26
- end
27
-
28
- def self.patch_path_string path
29
- Gem.win_platform? ? path.gsub(/\\/, '/') : path
30
- end
31
-
32
10
  def self.perform_check
33
- checker = Checker.new ARGV[0], ARGV[1]
11
+ options = {
12
+ auto: (ENV["AUTO"] == "true"),
13
+ quiet: (ENV["QUIET"] == "true"),
14
+ test_only: (ENV["TEST_ONLY"] == "true")
15
+ }
16
+ checker = Checker.new ARGV[0], ARGV[1], options
34
17
  checker.perform_check
35
18
  end
36
19
 
37
20
  class DigestDatabase
38
- def initialize path
21
+ def initialize path, options = {}
22
+ @options = options
23
+
39
24
  @db = SQLite3::Database.new path.to_s
40
25
  @db.results_as_hash = true
41
26
 
@@ -76,8 +61,8 @@ module FileDigests
76
61
 
77
62
  if found['digest'] == digest
78
63
  counters[:good] += 1
79
- # puts "GOOD: #{file_path}" unless QUIET
80
- unless TEST_ONLY
64
+ # puts "GOOD: #{file_path}" unless @options[:quiet]
65
+ unless @options[:test_only]
81
66
  if found['mtime'] == mtime
82
67
  touch_digest_check_time found['id']
83
68
  else
@@ -90,47 +75,50 @@ module FileDigests
90
75
  STDERR.puts "LIKELY DAMAGED: #{file_path}"
91
76
  else
92
77
  counters[:updated] += 1
93
- puts "UPDATED: #{file_path}" unless QUIET
94
- unless TEST_ONLY
78
+ puts "UPDATED: #{file_path}" unless @options[:quiet]
79
+ unless @options[:test_only]
95
80
  update_mtime_and_digest mtime, digest, found['id']
96
81
  end
97
82
  end
98
83
  end
99
84
  else
100
85
  counters[:new] += 1
101
- puts "NEW: #{file_path}" unless QUIET
102
- unless TEST_ONLY
86
+ puts "NEW: #{file_path}" unless @options[:quiet]
87
+ unless @options[:test_only]
103
88
  @new_files[file_path] = digest
104
89
  insert file_path, mtime, digest
105
90
  end
106
91
  end
107
92
  end
108
93
 
109
- def process_missing_files counters
94
+ def track_renames counters
110
95
  @missing_files.delete_if do |filename, digest|
111
96
  if @new_files.value?(digest)
112
97
  counters[:renamed] += 1
113
- unless TEST_ONLY
98
+ unless @options[:test_only]
114
99
  delete_by_filename filename
115
100
  end
116
101
  true
117
102
  end
118
103
  end
104
+ counters[:missing] = @missing_files.length
105
+ end
119
106
 
120
- if (counters[:missing] = @missing_files.length) > 0
121
- puts "\nMISSING FILES:"
122
- @missing_files.sort.to_h.each do |filename, digest|
123
- puts filename
124
- end
125
- unless TEST_ONLY
126
- puts "Remove missing files from the database (y/n)?"
127
- if STDIN.gets.strip.downcase == "y"
128
- @db.transaction do
129
- @missing_files.each do |filename, digest|
130
- delete_by_filename filename
131
- end
132
- end
133
- end
107
+ def any_missing_files?
108
+ @missing_files.length > 0
109
+ end
110
+
111
+ def print_missing_files
112
+ puts "\nMISSING FILES:"
113
+ @missing_files.sort.to_h.each do |filename, digest|
114
+ puts filename
115
+ end
116
+ end
117
+
118
+ def remove_missing_files
119
+ @db.transaction do
120
+ @missing_files.each do |filename, digest|
121
+ delete_by_filename filename
134
122
  end
135
123
  end
136
124
  end
@@ -151,14 +139,15 @@ module FileDigests
151
139
  end
152
140
 
153
141
  class Checker
154
- def initialize files_path, digest_database_path
155
- @files_path = Pathname.new(FileDigests::patch_path_string(files_path || ".")).cleanpath
142
+ def initialize files_path, digest_database_path, options = {}
143
+ @options = options
144
+ @files_path = cleanup_path(files_path || ".")
156
145
  @prefix_to_remove = @files_path.to_s + '/'
157
146
 
158
147
  raise "Files path must be a readable directory" unless (File.directory?(@files_path) && File.readable?(@files_path))
159
148
 
160
149
  @digest_database_path = if digest_database_path
161
- Pathname.new(FileDigests::patch_path_string(digest_database_path)).cleanpath
150
+ cleanup_path(digest_database_path)
162
151
  else
163
152
  @files_path + '.file-digests.sqlite'
164
153
  end
@@ -171,24 +160,32 @@ module FileDigests
171
160
  @skip_file_digests_sqlite = true
172
161
  end
173
162
 
174
- FileDigests::ensure_dir_exists @digest_database_path.dirname
163
+ ensure_dir_exists @digest_database_path.dirname
175
164
 
165
+ # Please do not use this flag, support for sha512 is here for backward compatibility, and one day it will be removed.
176
166
  if File.exist?(@digest_database_path.dirname + '.file-digests.sha512')
177
167
  @use_sha512 = true
178
168
  end
179
169
 
180
- @digest_database = DigestDatabase.new @digest_database_path
170
+ @digest_database = DigestDatabase.new @digest_database_path, @options
181
171
  @counters = {good: 0, updated: 0, new: 0, missing: 0, renamed: 0, likely_damaged: 0, exceptions: 0}
182
172
  end
183
173
 
184
174
  def perform_check
185
- FileDigests::measure_time do
175
+ measure_time do
186
176
  walk_files do |filename|
187
177
  process_file filename
188
178
  end
189
179
  end
190
180
 
191
- @digest_database.process_missing_files @counters
181
+ @digest_database.track_renames @counters
182
+
183
+ if @digest_database.any_missing_files?
184
+ @digest_database.print_missing_files
185
+ if !@options[:test_only] && (@options[:auto] || confirm("Remove missing files from the database"))
186
+ @digest_database.remove_missing_files
187
+ end
188
+ end
192
189
 
193
190
  if @counters[:likely_damaged] > 0 || @counters[:exceptions] > 0
194
191
  STDERR.puts "ERRORS WERE OCCURRED"
@@ -197,9 +194,13 @@ module FileDigests
197
194
  puts @counters.inspect
198
195
  end
199
196
 
200
- def walk_files
201
- Dir.glob(@files_path + '**' + '*', File::FNM_DOTMATCH) do |filename|
202
- yield filename
197
+ private
198
+
199
+
200
+ def confirm text
201
+ if STDIN.tty? && STDOUT.tty?
202
+ puts "#{text} (y/n)?"
203
+ STDIN.gets.strip.downcase == "y"
203
204
  end
204
205
  end
205
206
 
@@ -233,7 +234,31 @@ module FileDigests
233
234
  )
234
235
  rescue => exception
235
236
  @counters[:exceptions] += 1
236
- STDERR.puts "EXCEPTION: #{filename}: #{exception.message}"
237
+ STDERR.puts "EXCEPTION: #{filename.encode('utf-8', universal_newline: true)}: #{exception.message}"
238
+ end
239
+
240
+ def patch_path_string path
241
+ Gem.win_platform? ? path.gsub(/\\/, '/') : path
242
+ end
243
+
244
+ def cleanup_path path
245
+ Pathname.new(patch_path_string(path)).cleanpath
246
+ end
247
+
248
+ def ensure_dir_exists path
249
+ if File.exist?(path)
250
+ unless File.directory?(path)
251
+ raise "#{path} is not a directory"
252
+ end
253
+ else
254
+ FileUtils.mkdir_p path
255
+ end
256
+ end
257
+
258
+ def walk_files
259
+ Dir.glob(@files_path + '**' + '*', File::FNM_DOTMATCH) do |filename|
260
+ yield filename
261
+ end
237
262
  end
238
263
 
239
264
  def get_file_digest filename
@@ -247,5 +272,12 @@ module FileDigests
247
272
  end
248
273
  end
249
274
 
275
+ def measure_time
276
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
277
+ yield
278
+ elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).to_i
279
+ puts "Elapsed time: #{elapsed / 3600}h #{(elapsed % 3600) / 60}m #{elapsed % 60}s" unless @options[:quiet]
280
+ end
281
+
250
282
  end
251
283
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file-digests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanislav Senotrusov
@@ -28,11 +28,13 @@ description: Calculate file digests and check for the possible file corruption
28
28
  email: stan@senotrusov.com
29
29
  executables:
30
30
  - file-digests
31
+ - file-digests-auto
31
32
  - file-digests-test
32
33
  extensions: []
33
34
  extra_rdoc_files: []
34
35
  files:
35
36
  - bin/file-digests
37
+ - bin/file-digests-auto
36
38
  - bin/file-digests-test
37
39
  - lib/file-digests.rb
38
40
  homepage: https://github.com/senotrusov/file-digests