file-digests 0.0.32 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/file-digests +14 -0
- data/lib/file-digests.rb +161 -97
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 27e992f2a4849569d6c87e53807ebdc53676b3e47ca2c1efd2799927fd16d0c7
|
|
4
|
+
data.tar.gz: 9e292709b7978d906b0423a980cc72b23f8a44c665f070d71f30953ccdc59256
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c80f844d16255d9437c8dd012eff010df23f5a14d87336bf987b34e913a12fa0932fd85e18760884c63d10f882041afecf77b0b354555cef62aadc98de5ba091
|
|
7
|
+
data.tar.gz: f5f5c8309b8921f034edeb36643cab34dff52e4091cd5508462294a48e79002dfdbdf09a126988449d1775d207651579ca19ffb7cd169038fe71067dabb5b8af
|
data/bin/file-digests
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
+
# Copyright 2020 Stanislav Senotrusov <stan@senotrusov.com>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
3
17
|
require 'file-digests'
|
|
4
18
|
|
|
5
19
|
FileDigests.run_cli_utility
|
data/lib/file-digests.rb
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# Copyright 2020 Stanislav Senotrusov <stan@senotrusov.com>
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
1
15
|
require "date"
|
|
2
16
|
require "digest"
|
|
3
17
|
require "fileutils"
|
|
@@ -8,7 +22,8 @@ require "set"
|
|
|
8
22
|
require "sqlite3"
|
|
9
23
|
|
|
10
24
|
class FileDigests
|
|
11
|
-
|
|
25
|
+
VERSION = Gem.loaded_specs["file-digests"]&.version&.to_s
|
|
26
|
+
DIGEST_ALGORITHMS = ["BLAKE2b512", "SHA3-256", "SHA512-256"]
|
|
12
27
|
LEGACY_DIGEST_ALGORITHMS = ["SHA512", "SHA256"]
|
|
13
28
|
|
|
14
29
|
def self.canonical_digest_algorithm_name(string)
|
|
@@ -75,7 +90,12 @@ class FileDigests
|
|
|
75
90
|
options[:quiet] = true
|
|
76
91
|
end
|
|
77
92
|
|
|
78
|
-
opts.on(
|
|
93
|
+
opts.on(
|
|
94
|
+
"-t", "--test",
|
|
95
|
+
"Perform a test to verify directory contents.",
|
|
96
|
+
"Compare actual files with the stored digests, check if any files are missing.",
|
|
97
|
+
"Digest database will not be modified."
|
|
98
|
+
) do
|
|
79
99
|
options[:test_only] = true
|
|
80
100
|
end
|
|
81
101
|
|
|
@@ -96,6 +116,7 @@ class FileDigests
|
|
|
96
116
|
|
|
97
117
|
def initialize files_path, digest_database_path, options = {}
|
|
98
118
|
@options = options
|
|
119
|
+
@user_input_wait_time = 0
|
|
99
120
|
|
|
100
121
|
initialize_paths files_path, digest_database_path
|
|
101
122
|
initialize_database
|
|
@@ -139,8 +160,6 @@ class FileDigests
|
|
|
139
160
|
@db.results_as_hash = true
|
|
140
161
|
@db.busy_timeout = 5000
|
|
141
162
|
|
|
142
|
-
file_digests_gem_version = Gem.loaded_specs["file-digests"]&.version&.to_s
|
|
143
|
-
|
|
144
163
|
execute "PRAGMA encoding = 'UTF-8'"
|
|
145
164
|
execute "PRAGMA locking_mode = 'EXCLUSIVE'"
|
|
146
165
|
execute "PRAGMA journal_mode = 'WAL'"
|
|
@@ -155,14 +174,13 @@ class FileDigests
|
|
|
155
174
|
execute "CREATE TABLE metadata (
|
|
156
175
|
key TEXT NOT NULL PRIMARY KEY,
|
|
157
176
|
value TEXT)"
|
|
158
|
-
execute "CREATE UNIQUE INDEX metadata_key ON metadata(key)"
|
|
159
177
|
metadata_table_was_created = true
|
|
160
178
|
end
|
|
161
179
|
|
|
162
180
|
prepare_method :set_metadata_query, "INSERT INTO metadata (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value=excluded.value"
|
|
163
181
|
prepare_method :get_metadata_query, "SELECT value FROM metadata WHERE key = ?"
|
|
164
182
|
|
|
165
|
-
set_metadata("metadata_table_created_by_gem_version",
|
|
183
|
+
set_metadata("metadata_table_created_by_gem_version", FileDigests::VERSION) if FileDigests::VERSION && metadata_table_was_created
|
|
166
184
|
|
|
167
185
|
# Heuristic to detect database version 1 (metadata was not stored back then)
|
|
168
186
|
unless get_metadata("database_version")
|
|
@@ -179,20 +197,19 @@ class FileDigests
|
|
|
179
197
|
digest TEXT NOT NULL,
|
|
180
198
|
digest_check_time TEXT NOT NULL)"
|
|
181
199
|
execute "CREATE UNIQUE INDEX digests_filename ON digests(filename)"
|
|
182
|
-
|
|
200
|
+
execute "CREATE INDEX digests_digest ON digests(digest)"
|
|
201
|
+
set_metadata("digests_table_created_by_gem_version", FileDigests::VERSION) if FileDigests::VERSION
|
|
183
202
|
end
|
|
184
203
|
|
|
185
|
-
prepare_method :
|
|
186
|
-
prepare_method :
|
|
187
|
-
prepare_method :
|
|
188
|
-
prepare_method :
|
|
189
|
-
prepare_method :
|
|
190
|
-
prepare_method :
|
|
191
|
-
prepare_method :query_duplicates, "SELECT digest, filename FROM digests WHERE digest IN (SELECT digest FROM digests GROUP BY digest HAVING count(*) > 1) ORDER BY digest, filename;"
|
|
192
|
-
prepare_method :update_digest_to_new_digest, "UPDATE digests SET digest = ? WHERE digest = ?"
|
|
204
|
+
prepare_method :digests_insert, "INSERT INTO digests (filename, mtime, digest, digest_check_time) VALUES (?, ?, ?, datetime('now'))"
|
|
205
|
+
prepare_method :digests_find_by_filename_query, "SELECT id, mtime, digest FROM digests WHERE filename = ?"
|
|
206
|
+
prepare_method :digests_touch_check_time, "UPDATE digests SET digest_check_time = datetime('now') WHERE id = ?"
|
|
207
|
+
prepare_method :digests_update_mtime_and_digest, "UPDATE digests SET mtime = ?, digest = ?, digest_check_time = datetime('now') WHERE id = ?"
|
|
208
|
+
prepare_method :digests_update_mtime, "UPDATE digests SET mtime = ?, digest_check_time = datetime('now') WHERE id = ?"
|
|
209
|
+
prepare_method :digests_select_duplicates, "SELECT digest, filename FROM digests WHERE digest IN (SELECT digest FROM digests GROUP BY digest HAVING count(*) > 1) ORDER BY digest, filename;"
|
|
193
210
|
|
|
194
211
|
unless get_metadata("database_version")
|
|
195
|
-
set_metadata "database_version", "
|
|
212
|
+
set_metadata "database_version", "3"
|
|
196
213
|
end
|
|
197
214
|
|
|
198
215
|
# Convert database from 1st to 2nd version
|
|
@@ -207,79 +224,110 @@ class FileDigests
|
|
|
207
224
|
end
|
|
208
225
|
end
|
|
209
226
|
|
|
210
|
-
if get_metadata("database_version")
|
|
211
|
-
|
|
212
|
-
|
|
227
|
+
if get_metadata("database_version") == "2"
|
|
228
|
+
execute "CREATE INDEX digests_digest ON digests(digest)"
|
|
229
|
+
set_metadata "database_version", "3"
|
|
213
230
|
end
|
|
231
|
+
|
|
232
|
+
check_if_database_is_at_certain_version "3"
|
|
233
|
+
|
|
234
|
+
create_temporary_tables
|
|
214
235
|
end
|
|
215
236
|
end
|
|
216
237
|
|
|
217
|
-
def
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
238
|
+
def create_temporary_tables
|
|
239
|
+
execute "CREATE TEMPORARY TABLE new_files (
|
|
240
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
|
241
|
+
digest TEXT NOT NULL)"
|
|
242
|
+
execute "CREATE INDEX new_files_digest ON new_files(digest)"
|
|
243
|
+
|
|
244
|
+
prepare_method :new_files_insert, "INSERT INTO new_files (filename, digest) VALUES (?, ?)"
|
|
245
|
+
prepare_method :new_files_count_query, "SELECT count(*) FROM new_files"
|
|
246
|
+
|
|
247
|
+
execute "CREATE TEMPORARY TABLE missing_files (
|
|
248
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
|
249
|
+
digest TEXT NOT NULL)"
|
|
250
|
+
execute "CREATE INDEX missing_files_digest ON missing_files(digest)"
|
|
251
|
+
|
|
252
|
+
execute "INSERT INTO missing_files (filename, digest) SELECT filename, digest FROM digests"
|
|
253
|
+
|
|
254
|
+
prepare_method :missing_files_delete, "DELETE FROM missing_files WHERE filename = ?"
|
|
255
|
+
prepare_method :missing_files_delete_renamed_files, "DELETE FROM missing_files WHERE digest IN (SELECT digest FROM new_files)"
|
|
256
|
+
prepare_method :missing_files_select_all_filenames, "SELECT filename FROM missing_files ORDER BY filename"
|
|
257
|
+
prepare_method :missing_files_delete_all, "DELETE FROM missing_files"
|
|
258
|
+
prepare_method :missing_files_count_query, "SELECT count(*) FROM missing_files"
|
|
259
|
+
|
|
260
|
+
prepare_method :digests_delete_renamed_files, "DELETE FROM digests WHERE filename IN (SELECT filename FROM missing_files WHERE digest IN (SELECT digest FROM new_files))"
|
|
261
|
+
prepare_method :digests_delete_all_missing_files, "DELETE FROM digests WHERE filename IN (SELECT filename FROM missing_files)"
|
|
262
|
+
|
|
263
|
+
execute "CREATE TEMPORARY TABLE new_digests (
|
|
264
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
|
265
|
+
digest TEXT NOT NULL)"
|
|
266
|
+
|
|
267
|
+
prepare_method :new_digests_insert, "INSERT INTO new_digests (filename, digest) VALUES (?, ?)"
|
|
268
|
+
prepare_method :digests_update_digests_to_new_digests, "INSERT INTO digests (filename, digest, digest_check_time) SELECT filename, digest, false FROM new_digests WHERE true ON CONFLICT (filename) DO UPDATE SET digest=excluded.digest"
|
|
269
|
+
end
|
|
222
270
|
|
|
223
|
-
|
|
271
|
+
def perform_check
|
|
272
|
+
measure_time do
|
|
273
|
+
perhaps_transaction(@new_digest_algorithm, :exclusive) do
|
|
274
|
+
@counters = {good: 0, updated: 0, renamed: 0, likely_damaged: 0, exceptions: 0}
|
|
224
275
|
|
|
225
|
-
measure_time do
|
|
226
276
|
walk_files do |filename|
|
|
227
277
|
process_file filename
|
|
228
278
|
end
|
|
229
|
-
end
|
|
230
279
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
280
|
+
nested_transaction do
|
|
281
|
+
puts "Tracking renames..." if @options[:verbose]
|
|
282
|
+
track_renames
|
|
283
|
+
end
|
|
235
284
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
285
|
+
if any_missing_files?
|
|
286
|
+
if any_exceptions?
|
|
287
|
+
STDERR.puts "Due to previously occurred errors, missing files will not removed from the database."
|
|
288
|
+
else
|
|
289
|
+
print_missing_files
|
|
290
|
+
if !@options[:test_only] && (@options[:auto] || confirm("Remove missing files from the database"))
|
|
291
|
+
nested_transaction do
|
|
292
|
+
puts "Removing missing files..." if @options[:verbose]
|
|
293
|
+
remove_missing_files
|
|
294
|
+
end
|
|
245
295
|
end
|
|
246
296
|
end
|
|
247
297
|
end
|
|
248
|
-
end
|
|
249
298
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
299
|
+
if @new_digest_algorithm && !@options[:test_only]
|
|
300
|
+
if any_missing_files? || any_likely_damaged? || any_exceptions?
|
|
301
|
+
STDERR.puts "ERROR: New digest algorithm will not be in effect until there are files that are missing, likely damaged, or processed with an exception."
|
|
302
|
+
else
|
|
303
|
+
puts "Updating database to a new digest algorithm..." if @options[:verbose]
|
|
304
|
+
digests_update_digests_to_new_digests
|
|
305
|
+
set_metadata "digest_algorithm", @new_digest_algorithm
|
|
306
|
+
puts "Transition to a new digest algorithm complete: #{@new_digest_algorithm}"
|
|
257
307
|
end
|
|
258
|
-
set_metadata "digest_algorithm", @new_digest_algorithm
|
|
259
|
-
puts "Transition to a new digest algorithm complete: #{@new_digest_algorithm}"
|
|
260
308
|
end
|
|
261
|
-
end
|
|
262
309
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
310
|
+
if any_likely_damaged? || any_exceptions?
|
|
311
|
+
STDERR.puts "PLEASE REVIEW ERRORS THAT WERE OCCURRED!"
|
|
312
|
+
end
|
|
266
313
|
|
|
267
|
-
|
|
314
|
+
set_metadata(@options[:test_only] ? "latest_test_only_check_time" : "latest_complete_check_time", time_to_database(Time.now))
|
|
268
315
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
316
|
+
print_counters
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
puts "Performing database maintenance..." if @options[:verbose]
|
|
320
|
+
execute "PRAGMA optimize"
|
|
321
|
+
execute "VACUUM"
|
|
322
|
+
execute "PRAGMA wal_checkpoint(TRUNCATE)"
|
|
276
323
|
|
|
277
|
-
|
|
324
|
+
hide_database_files
|
|
325
|
+
end
|
|
278
326
|
end
|
|
279
327
|
|
|
280
328
|
def show_duplicates
|
|
281
329
|
current_digest = nil
|
|
282
|
-
|
|
330
|
+
digests_select_duplicates.each do |found|
|
|
283
331
|
if current_digest != found["digest"]
|
|
284
332
|
puts "" if current_digest
|
|
285
333
|
current_digest = found["digest"]
|
|
@@ -311,9 +359,10 @@ class FileDigests
|
|
|
311
359
|
|
|
312
360
|
normalized_filename = filename.delete_prefix("#{@files_path.to_s}/").encode("utf-8", universal_newline: true).unicode_normalize(:nfkc)
|
|
313
361
|
mtime_string = time_to_database stat.mtime
|
|
314
|
-
digest = get_file_digest(filename)
|
|
362
|
+
digest, new_digest = get_file_digest(filename)
|
|
315
363
|
|
|
316
364
|
nested_transaction do
|
|
365
|
+
new_digests_insert(normalized_filename, new_digest) if new_digest
|
|
317
366
|
process_file_indeed normalized_filename, mtime_string, digest
|
|
318
367
|
end
|
|
319
368
|
|
|
@@ -331,15 +380,15 @@ class FileDigests
|
|
|
331
380
|
end
|
|
332
381
|
|
|
333
382
|
def process_previously_seen_file found, filename, mtime, digest
|
|
334
|
-
|
|
383
|
+
missing_files_delete filename
|
|
335
384
|
if found["digest"] == digest
|
|
336
385
|
@counters[:good] += 1
|
|
337
386
|
puts "GOOD: #{filename}" if @options[:verbose]
|
|
338
387
|
unless @options[:test_only]
|
|
339
388
|
if found["mtime"] == mtime
|
|
340
|
-
|
|
389
|
+
digests_touch_check_time found["id"]
|
|
341
390
|
else
|
|
342
|
-
|
|
391
|
+
digests_update_mtime mtime, found["id"]
|
|
343
392
|
end
|
|
344
393
|
end
|
|
345
394
|
else
|
|
@@ -350,18 +399,17 @@ class FileDigests
|
|
|
350
399
|
@counters[:updated] += 1
|
|
351
400
|
puts "UPDATED#{" (FATE ACCEPTED)" if found["mtime"] == mtime && @options[:accept_fate]}: #{filename}" unless @options[:quiet]
|
|
352
401
|
unless @options[:test_only]
|
|
353
|
-
|
|
402
|
+
digests_update_mtime_and_digest mtime, digest, found["id"]
|
|
354
403
|
end
|
|
355
404
|
end
|
|
356
405
|
end
|
|
357
406
|
end
|
|
358
407
|
|
|
359
408
|
def process_new_file filename, mtime, digest
|
|
360
|
-
@counters[:new] += 1
|
|
361
409
|
puts "NEW: #{filename}" unless @options[:quiet]
|
|
410
|
+
new_files_insert filename, digest
|
|
362
411
|
unless @options[:test_only]
|
|
363
|
-
|
|
364
|
-
insert filename, mtime, digest
|
|
412
|
+
digests_insert filename, mtime, digest
|
|
365
413
|
end
|
|
366
414
|
end
|
|
367
415
|
|
|
@@ -369,29 +417,31 @@ class FileDigests
|
|
|
369
417
|
# Renames and missing files
|
|
370
418
|
|
|
371
419
|
def track_renames
|
|
372
|
-
@
|
|
373
|
-
|
|
374
|
-
@counters[:renamed] += 1
|
|
375
|
-
unless @options[:test_only]
|
|
376
|
-
delete_by_filename filename
|
|
377
|
-
end
|
|
378
|
-
true
|
|
379
|
-
end
|
|
420
|
+
unless @options[:test_only]
|
|
421
|
+
digests_delete_renamed_files
|
|
380
422
|
end
|
|
423
|
+
missing_files_delete_renamed_files
|
|
424
|
+
@counters[:renamed] = @db.changes
|
|
381
425
|
end
|
|
382
426
|
|
|
383
427
|
def print_missing_files
|
|
384
428
|
puts "\nMISSING FILES:"
|
|
385
|
-
|
|
386
|
-
puts filename
|
|
429
|
+
missing_files_select_all_filenames.each do |record|
|
|
430
|
+
puts record["filename"]
|
|
387
431
|
end
|
|
388
432
|
end
|
|
389
433
|
|
|
390
434
|
def remove_missing_files
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
435
|
+
digests_delete_all_missing_files
|
|
436
|
+
missing_files_delete_all
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def missing_files_count
|
|
440
|
+
missing_files_count_query!&.first&.first
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def any_missing_files?
|
|
444
|
+
missing_files_count > 0
|
|
395
445
|
end
|
|
396
446
|
|
|
397
447
|
|
|
@@ -402,6 +452,7 @@ class FileDigests
|
|
|
402
452
|
end
|
|
403
453
|
|
|
404
454
|
def integrity_check
|
|
455
|
+
puts "Checking database integrity..." if @options[:verbose]
|
|
405
456
|
if execute("PRAGMA integrity_check")&.first&.fetch("integrity_check") != "ok"
|
|
406
457
|
raise "Database integrity check failed"
|
|
407
458
|
end
|
|
@@ -456,7 +507,7 @@ class FileDigests
|
|
|
456
507
|
end
|
|
457
508
|
|
|
458
509
|
def find_by_filename filename
|
|
459
|
-
result =
|
|
510
|
+
result = digests_find_by_filename_query filename
|
|
460
511
|
found = result.next
|
|
461
512
|
raise "Multiple records found" if result.next
|
|
462
513
|
found
|
|
@@ -476,6 +527,18 @@ class FileDigests
|
|
|
476
527
|
end
|
|
477
528
|
end
|
|
478
529
|
|
|
530
|
+
def check_if_database_is_at_certain_version target_version
|
|
531
|
+
current_version = get_metadata("database_version")
|
|
532
|
+
if current_version != target_version
|
|
533
|
+
STDERR.puts "This version of file-digests (#{FileDigests::VERSION || "unknown"}) is only compartible with the database version #{target_version}. Current database version is #{current_version}. To use this database, please install appropriate version if file-digest."
|
|
534
|
+
raise "Incompatible database version"
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
def new_files_count
|
|
539
|
+
new_files_count_query!&.first&.first
|
|
540
|
+
end
|
|
541
|
+
|
|
479
542
|
|
|
480
543
|
# Filesystem-related helpers
|
|
481
544
|
|
|
@@ -514,18 +577,13 @@ class FileDigests
|
|
|
514
577
|
digest.update(buffer)
|
|
515
578
|
new_digest.update(buffer) if @new_digest_algorithm
|
|
516
579
|
end
|
|
517
|
-
|
|
518
|
-
return digest.hexdigest
|
|
580
|
+
return [digest.hexdigest, (new_digest.hexdigest if @new_digest_algorithm)]
|
|
519
581
|
end
|
|
520
582
|
end
|
|
521
583
|
|
|
522
584
|
|
|
523
585
|
# Runtime state helpers
|
|
524
586
|
|
|
525
|
-
def any_missing_files?
|
|
526
|
-
@missing_files.length > 0
|
|
527
|
-
end
|
|
528
|
-
|
|
529
587
|
def any_exceptions?
|
|
530
588
|
@counters[:exceptions] > 0
|
|
531
589
|
end
|
|
@@ -539,14 +597,17 @@ class FileDigests
|
|
|
539
597
|
def confirm text
|
|
540
598
|
if STDIN.tty? && STDOUT.tty?
|
|
541
599
|
puts "#{text} (y/n)?"
|
|
542
|
-
|
|
600
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
601
|
+
result = (STDIN.gets.strip.downcase == "y")
|
|
602
|
+
@user_input_wait_time += (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
|
|
603
|
+
result
|
|
543
604
|
end
|
|
544
605
|
end
|
|
545
606
|
|
|
546
607
|
def measure_time
|
|
547
608
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
548
609
|
yield
|
|
549
|
-
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
|
|
610
|
+
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) - @user_input_wait_time
|
|
550
611
|
puts "Elapsed time: #{elapsed.to_i / 3600}h #{(elapsed.to_i % 3600) / 60}m #{"%.3f" % (elapsed % 60)}s" unless @options[:quiet]
|
|
551
612
|
end
|
|
552
613
|
|
|
@@ -564,11 +625,14 @@ class FileDigests
|
|
|
564
625
|
end
|
|
565
626
|
|
|
566
627
|
def print_counters
|
|
628
|
+
missing_files_count_result = missing_files_count
|
|
629
|
+
new_files_count_result = new_files_count - @counters[:renamed]
|
|
630
|
+
|
|
567
631
|
puts "#{@counters[:good]} file(s) passes digest check" if @counters[:good] > 0
|
|
568
632
|
puts "#{@counters[:updated]} file(s) are updated" if @counters[:updated] > 0
|
|
569
|
-
puts "#{
|
|
633
|
+
puts "#{new_files_count_result} file(s) are new" if new_files_count_result > 0
|
|
570
634
|
puts "#{@counters[:renamed]} file(s) are renamed" if @counters[:renamed] > 0
|
|
571
|
-
puts "#{
|
|
635
|
+
puts "#{missing_files_count_result} file(s) are missing" if missing_files_count_result > 0
|
|
572
636
|
puts "#{@counters[:likely_damaged]} file(s) are likely damaged (!)" if @counters[:likely_damaged] > 0
|
|
573
637
|
puts "#{@counters[:exceptions]} file(s) had exceptions occured during processing (!)" if @counters[:exceptions] > 0
|
|
574
638
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: file-digests
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.37
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stanislav Senotrusov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-10-
|
|
11
|
+
date: 2020-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: openssl
|