file-digests 0.0.30 → 0.0.35
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 +162 -92
- 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: 42e870b2a0e4e711e84a2748d09d8a378fc6964d78706d573ab22737d0f2519e
|
|
4
|
+
data.tar.gz: e14bef4ccd63fdc07950a257654c6594b793eabf44bbdf26cae59e621838e5c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6b9eb636258ba06b29bd21736b477c0d225ba119ad3b3ccb82612c941bf892109876aa4e8da7402f580f4167f84000a1b2b4ae91e568ac50f223325fab856ef
|
|
7
|
+
data.tar.gz: afcdffefe0dcb346afcdf37ce6f3f523d4862a45a455838d8b7cbf603cead2c8fadbac185640088c79bd7e8c412b5da932bf301d90dd4337171b675a65f34388
|
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,74 +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
|
-
|
|
280
|
+
nested_transaction do
|
|
281
|
+
puts "Tracking renames..." if @options[:verbose]
|
|
282
|
+
track_renames
|
|
283
|
+
end
|
|
234
284
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
|
243
295
|
end
|
|
244
296
|
end
|
|
245
297
|
end
|
|
246
|
-
end
|
|
247
298
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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}"
|
|
254
307
|
end
|
|
255
|
-
set_metadata "digest_algorithm", @new_digest_algorithm
|
|
256
|
-
puts "Transition to a new digest algorithm complete: #{@new_digest_algorithm}"
|
|
257
308
|
end
|
|
258
|
-
end
|
|
259
309
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
310
|
+
if any_likely_damaged? || any_exceptions?
|
|
311
|
+
STDERR.puts "PLEASE REVIEW ERRORS THAT WERE OCCURRED!"
|
|
312
|
+
end
|
|
263
313
|
|
|
264
|
-
|
|
314
|
+
set_metadata(@options[:test_only] ? "latest_test_only_check_time" : "latest_complete_check_time", time_to_database(Time.now))
|
|
265
315
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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)"
|
|
271
323
|
|
|
272
|
-
|
|
324
|
+
hide_database_files
|
|
325
|
+
end
|
|
273
326
|
end
|
|
274
327
|
|
|
275
328
|
def show_duplicates
|
|
276
329
|
current_digest = nil
|
|
277
|
-
|
|
330
|
+
digests_select_duplicates.each do |found|
|
|
278
331
|
if current_digest != found["digest"]
|
|
279
332
|
puts "" if current_digest
|
|
280
333
|
current_digest = found["digest"]
|
|
@@ -306,9 +359,10 @@ class FileDigests
|
|
|
306
359
|
|
|
307
360
|
normalized_filename = filename.delete_prefix("#{@files_path.to_s}/").encode("utf-8", universal_newline: true).unicode_normalize(:nfkc)
|
|
308
361
|
mtime_string = time_to_database stat.mtime
|
|
309
|
-
digest = get_file_digest(filename)
|
|
362
|
+
digest, new_digest = get_file_digest(filename)
|
|
310
363
|
|
|
311
364
|
nested_transaction do
|
|
365
|
+
new_digests_insert(normalized_filename, new_digest) if new_digest
|
|
312
366
|
process_file_indeed normalized_filename, mtime_string, digest
|
|
313
367
|
end
|
|
314
368
|
|
|
@@ -326,15 +380,15 @@ class FileDigests
|
|
|
326
380
|
end
|
|
327
381
|
|
|
328
382
|
def process_previously_seen_file found, filename, mtime, digest
|
|
329
|
-
|
|
383
|
+
missing_files_delete filename
|
|
330
384
|
if found["digest"] == digest
|
|
331
385
|
@counters[:good] += 1
|
|
332
386
|
puts "GOOD: #{filename}" if @options[:verbose]
|
|
333
387
|
unless @options[:test_only]
|
|
334
388
|
if found["mtime"] == mtime
|
|
335
|
-
|
|
389
|
+
digests_touch_check_time found["id"]
|
|
336
390
|
else
|
|
337
|
-
|
|
391
|
+
digests_update_mtime mtime, found["id"]
|
|
338
392
|
end
|
|
339
393
|
end
|
|
340
394
|
else
|
|
@@ -345,18 +399,17 @@ class FileDigests
|
|
|
345
399
|
@counters[:updated] += 1
|
|
346
400
|
puts "UPDATED#{" (FATE ACCEPTED)" if found["mtime"] == mtime && @options[:accept_fate]}: #{filename}" unless @options[:quiet]
|
|
347
401
|
unless @options[:test_only]
|
|
348
|
-
|
|
402
|
+
digests_update_mtime_and_digest mtime, digest, found["id"]
|
|
349
403
|
end
|
|
350
404
|
end
|
|
351
405
|
end
|
|
352
406
|
end
|
|
353
407
|
|
|
354
408
|
def process_new_file filename, mtime, digest
|
|
355
|
-
@counters[:new] += 1
|
|
356
409
|
puts "NEW: #{filename}" unless @options[:quiet]
|
|
410
|
+
new_files_insert filename, digest
|
|
357
411
|
unless @options[:test_only]
|
|
358
|
-
|
|
359
|
-
insert filename, mtime, digest
|
|
412
|
+
digests_insert filename, mtime, digest
|
|
360
413
|
end
|
|
361
414
|
end
|
|
362
415
|
|
|
@@ -364,29 +417,31 @@ class FileDigests
|
|
|
364
417
|
# Renames and missing files
|
|
365
418
|
|
|
366
419
|
def track_renames
|
|
367
|
-
@
|
|
368
|
-
|
|
369
|
-
@counters[:renamed] += 1
|
|
370
|
-
unless @options[:test_only]
|
|
371
|
-
delete_by_filename filename
|
|
372
|
-
end
|
|
373
|
-
true
|
|
374
|
-
end
|
|
420
|
+
unless @options[:test_only]
|
|
421
|
+
digests_delete_renamed_files
|
|
375
422
|
end
|
|
423
|
+
missing_files_delete_renamed_files
|
|
424
|
+
@counters[:renamed] = @db.changes
|
|
376
425
|
end
|
|
377
426
|
|
|
378
427
|
def print_missing_files
|
|
379
428
|
puts "\nMISSING FILES:"
|
|
380
|
-
|
|
381
|
-
puts filename
|
|
429
|
+
missing_files_select_all_filenames.each do |record|
|
|
430
|
+
puts record["filename"]
|
|
382
431
|
end
|
|
383
432
|
end
|
|
384
433
|
|
|
385
434
|
def remove_missing_files
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
390
445
|
end
|
|
391
446
|
|
|
392
447
|
|
|
@@ -397,6 +452,7 @@ class FileDigests
|
|
|
397
452
|
end
|
|
398
453
|
|
|
399
454
|
def integrity_check
|
|
455
|
+
puts "Checking database integrity..." if @options[:verbose]
|
|
400
456
|
if execute("PRAGMA integrity_check")&.first&.fetch("integrity_check") != "ok"
|
|
401
457
|
raise "Database integrity check failed"
|
|
402
458
|
end
|
|
@@ -451,7 +507,7 @@ class FileDigests
|
|
|
451
507
|
end
|
|
452
508
|
|
|
453
509
|
def find_by_filename filename
|
|
454
|
-
result =
|
|
510
|
+
result = digests_find_by_filename_query filename
|
|
455
511
|
found = result.next
|
|
456
512
|
raise "Multiple records found" if result.next
|
|
457
513
|
found
|
|
@@ -471,6 +527,18 @@ class FileDigests
|
|
|
471
527
|
end
|
|
472
528
|
end
|
|
473
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
|
+
|
|
474
542
|
|
|
475
543
|
# Filesystem-related helpers
|
|
476
544
|
|
|
@@ -493,6 +561,7 @@ class FileDigests
|
|
|
493
561
|
end
|
|
494
562
|
|
|
495
563
|
def walk_files
|
|
564
|
+
puts "Gathering the list of files..." if @options[:verbose]
|
|
496
565
|
Dir.glob(@files_path + "**" + "*", File::FNM_DOTMATCH) do |filename|
|
|
497
566
|
yield filename
|
|
498
567
|
end
|
|
@@ -508,18 +577,13 @@ class FileDigests
|
|
|
508
577
|
digest.update(buffer)
|
|
509
578
|
new_digest.update(buffer) if @new_digest_algorithm
|
|
510
579
|
end
|
|
511
|
-
|
|
512
|
-
return digest.hexdigest
|
|
580
|
+
return [digest.hexdigest, (new_digest.hexdigest if @new_digest_algorithm)]
|
|
513
581
|
end
|
|
514
582
|
end
|
|
515
583
|
|
|
516
584
|
|
|
517
585
|
# Runtime state helpers
|
|
518
586
|
|
|
519
|
-
def any_missing_files?
|
|
520
|
-
@missing_files.length > 0
|
|
521
|
-
end
|
|
522
|
-
|
|
523
587
|
def any_exceptions?
|
|
524
588
|
@counters[:exceptions] > 0
|
|
525
589
|
end
|
|
@@ -533,14 +597,17 @@ class FileDigests
|
|
|
533
597
|
def confirm text
|
|
534
598
|
if STDIN.tty? && STDOUT.tty?
|
|
535
599
|
puts "#{text} (y/n)?"
|
|
536
|
-
|
|
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
|
|
537
604
|
end
|
|
538
605
|
end
|
|
539
606
|
|
|
540
607
|
def measure_time
|
|
541
608
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
542
609
|
yield
|
|
543
|
-
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
|
|
610
|
+
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) - @user_input_wait_time
|
|
544
611
|
puts "Elapsed time: #{elapsed.to_i / 3600}h #{(elapsed.to_i % 3600) / 60}m #{"%.3f" % (elapsed % 60)}s" unless @options[:quiet]
|
|
545
612
|
end
|
|
546
613
|
|
|
@@ -558,11 +625,14 @@ class FileDigests
|
|
|
558
625
|
end
|
|
559
626
|
|
|
560
627
|
def print_counters
|
|
628
|
+
missing_files_count_result = missing_files_count
|
|
629
|
+
new_files_count_result = new_files_count - @counters[:renamed]
|
|
630
|
+
|
|
561
631
|
puts "#{@counters[:good]} file(s) passes digest check" if @counters[:good] > 0
|
|
562
632
|
puts "#{@counters[:updated]} file(s) are updated" if @counters[:updated] > 0
|
|
563
|
-
puts "#{
|
|
633
|
+
puts "#{new_files_count_result} file(s) are new" if new_files_count_result > 0
|
|
564
634
|
puts "#{@counters[:renamed]} file(s) are renamed" if @counters[:renamed] > 0
|
|
565
|
-
puts "#{
|
|
635
|
+
puts "#{missing_files_count_result} file(s) are missing" if missing_files_count_result > 0
|
|
566
636
|
puts "#{@counters[:likely_damaged]} file(s) are likely damaged (!)" if @counters[:likely_damaged] > 0
|
|
567
637
|
puts "#{@counters[:exceptions]} file(s) had exceptions occured during processing (!)" if @counters[:exceptions] > 0
|
|
568
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.35
|
|
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
|