file-digests 0.0.31 → 0.0.36
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/file-digests +14 -0
- data/lib/file-digests.rb +164 -99
- 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: 624f7ec80a0cb15be2bc07a3dd592c33c7a178c22fb7f59ef326760d17cc564f
|
4
|
+
data.tar.gz: 92bb88c58bc152ad01649b0688861ea16af6801d2d6625c238b96e9ff00aaed4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9dbca39af63f07ddfe4d92618d0ff5e0813fa30561d42b629caa918f664f1149f8ad895e8555137b0f462eb4eac942adda07efed03859d17cb635a8d9bb25b57
|
7
|
+
data.tar.gz: 788d37c5d82e8892dfcfb6f4a8532f484f7cf17c5f937e8a64b09af902fe3a904ed034fc88d403852bbd8819a9d11ab61a672e2d6f3114420ed7777ea9db2961
|
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,6 +1,21 @@
|
|
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"
|
18
|
+
require "find"
|
4
19
|
require "openssl"
|
5
20
|
require "optparse"
|
6
21
|
require "pathname"
|
@@ -8,7 +23,8 @@ require "set"
|
|
8
23
|
require "sqlite3"
|
9
24
|
|
10
25
|
class FileDigests
|
11
|
-
|
26
|
+
VERSION = Gem.loaded_specs["file-digests"]&.version&.to_s
|
27
|
+
DIGEST_ALGORITHMS = ["BLAKE2b512", "SHA3-256", "SHA512-256"]
|
12
28
|
LEGACY_DIGEST_ALGORITHMS = ["SHA512", "SHA256"]
|
13
29
|
|
14
30
|
def self.canonical_digest_algorithm_name(string)
|
@@ -75,7 +91,12 @@ class FileDigests
|
|
75
91
|
options[:quiet] = true
|
76
92
|
end
|
77
93
|
|
78
|
-
opts.on(
|
94
|
+
opts.on(
|
95
|
+
"-t", "--test",
|
96
|
+
"Perform a test to verify directory contents.",
|
97
|
+
"Compare actual files with the stored digests, check if any files are missing.",
|
98
|
+
"Digest database will not be modified."
|
99
|
+
) do
|
79
100
|
options[:test_only] = true
|
80
101
|
end
|
81
102
|
|
@@ -96,6 +117,7 @@ class FileDigests
|
|
96
117
|
|
97
118
|
def initialize files_path, digest_database_path, options = {}
|
98
119
|
@options = options
|
120
|
+
@user_input_wait_time = 0
|
99
121
|
|
100
122
|
initialize_paths files_path, digest_database_path
|
101
123
|
initialize_database
|
@@ -139,8 +161,6 @@ class FileDigests
|
|
139
161
|
@db.results_as_hash = true
|
140
162
|
@db.busy_timeout = 5000
|
141
163
|
|
142
|
-
file_digests_gem_version = Gem.loaded_specs["file-digests"]&.version&.to_s
|
143
|
-
|
144
164
|
execute "PRAGMA encoding = 'UTF-8'"
|
145
165
|
execute "PRAGMA locking_mode = 'EXCLUSIVE'"
|
146
166
|
execute "PRAGMA journal_mode = 'WAL'"
|
@@ -155,14 +175,13 @@ class FileDigests
|
|
155
175
|
execute "CREATE TABLE metadata (
|
156
176
|
key TEXT NOT NULL PRIMARY KEY,
|
157
177
|
value TEXT)"
|
158
|
-
execute "CREATE UNIQUE INDEX metadata_key ON metadata(key)"
|
159
178
|
metadata_table_was_created = true
|
160
179
|
end
|
161
180
|
|
162
181
|
prepare_method :set_metadata_query, "INSERT INTO metadata (key, value) VALUES (?, ?) ON CONFLICT (key) DO UPDATE SET value=excluded.value"
|
163
182
|
prepare_method :get_metadata_query, "SELECT value FROM metadata WHERE key = ?"
|
164
183
|
|
165
|
-
set_metadata("metadata_table_created_by_gem_version",
|
184
|
+
set_metadata("metadata_table_created_by_gem_version", FileDigests::VERSION) if FileDigests::VERSION && metadata_table_was_created
|
166
185
|
|
167
186
|
# Heuristic to detect database version 1 (metadata was not stored back then)
|
168
187
|
unless get_metadata("database_version")
|
@@ -179,20 +198,19 @@ class FileDigests
|
|
179
198
|
digest TEXT NOT NULL,
|
180
199
|
digest_check_time TEXT NOT NULL)"
|
181
200
|
execute "CREATE UNIQUE INDEX digests_filename ON digests(filename)"
|
182
|
-
|
201
|
+
execute "CREATE INDEX digests_digest ON digests(digest)"
|
202
|
+
set_metadata("digests_table_created_by_gem_version", FileDigests::VERSION) if FileDigests::VERSION
|
183
203
|
end
|
184
204
|
|
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 = ?"
|
205
|
+
prepare_method :digests_insert, "INSERT INTO digests (filename, mtime, digest, digest_check_time) VALUES (?, ?, ?, datetime('now'))"
|
206
|
+
prepare_method :digests_find_by_filename_query, "SELECT id, mtime, digest FROM digests WHERE filename = ?"
|
207
|
+
prepare_method :digests_touch_check_time, "UPDATE digests SET digest_check_time = datetime('now') WHERE id = ?"
|
208
|
+
prepare_method :digests_update_mtime_and_digest, "UPDATE digests SET mtime = ?, digest = ?, digest_check_time = datetime('now') WHERE id = ?"
|
209
|
+
prepare_method :digests_update_mtime, "UPDATE digests SET mtime = ?, digest_check_time = datetime('now') WHERE id = ?"
|
210
|
+
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
211
|
|
194
212
|
unless get_metadata("database_version")
|
195
|
-
set_metadata "database_version", "
|
213
|
+
set_metadata "database_version", "3"
|
196
214
|
end
|
197
215
|
|
198
216
|
# Convert database from 1st to 2nd version
|
@@ -207,79 +225,110 @@ class FileDigests
|
|
207
225
|
end
|
208
226
|
end
|
209
227
|
|
210
|
-
if get_metadata("database_version")
|
211
|
-
|
212
|
-
|
228
|
+
if get_metadata("database_version") == "2"
|
229
|
+
execute "CREATE INDEX digests_digest ON digests(digest)"
|
230
|
+
set_metadata "database_version", "3"
|
213
231
|
end
|
232
|
+
|
233
|
+
check_if_database_is_at_certain_version "3"
|
234
|
+
|
235
|
+
create_temporary_tables
|
214
236
|
end
|
215
237
|
end
|
216
238
|
|
217
|
-
def
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
239
|
+
def create_temporary_tables
|
240
|
+
execute "CREATE TEMPORARY TABLE new_files (
|
241
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
242
|
+
digest TEXT NOT NULL)"
|
243
|
+
execute "CREATE INDEX new_files_digest ON new_files(digest)"
|
244
|
+
|
245
|
+
prepare_method :new_files_insert, "INSERT INTO new_files (filename, digest) VALUES (?, ?)"
|
246
|
+
prepare_method :new_files_count_query, "SELECT count(*) FROM new_files"
|
247
|
+
|
248
|
+
execute "CREATE TEMPORARY TABLE missing_files (
|
249
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
250
|
+
digest TEXT NOT NULL)"
|
251
|
+
execute "CREATE INDEX missing_files_digest ON missing_files(digest)"
|
252
|
+
|
253
|
+
execute "INSERT INTO missing_files (filename, digest) SELECT filename, digest FROM digests"
|
254
|
+
|
255
|
+
prepare_method :missing_files_delete, "DELETE FROM missing_files WHERE filename = ?"
|
256
|
+
prepare_method :missing_files_delete_renamed_files, "DELETE FROM missing_files WHERE digest IN (SELECT digest FROM new_files)"
|
257
|
+
prepare_method :missing_files_select_all_filenames, "SELECT filename FROM missing_files ORDER BY filename"
|
258
|
+
prepare_method :missing_files_delete_all, "DELETE FROM missing_files"
|
259
|
+
prepare_method :missing_files_count_query, "SELECT count(*) FROM missing_files"
|
260
|
+
|
261
|
+
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))"
|
262
|
+
prepare_method :digests_delete_all_missing_files, "DELETE FROM digests WHERE filename IN (SELECT filename FROM missing_files)"
|
263
|
+
|
264
|
+
execute "CREATE TEMPORARY TABLE new_digests (
|
265
|
+
filename TEXT NOT NULL PRIMARY KEY,
|
266
|
+
digest TEXT NOT NULL)"
|
267
|
+
|
268
|
+
prepare_method :new_digests_insert, "INSERT INTO new_digests (filename, digest) VALUES (?, ?)"
|
269
|
+
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"
|
270
|
+
end
|
222
271
|
|
223
|
-
|
272
|
+
def perform_check
|
273
|
+
measure_time do
|
274
|
+
perhaps_transaction(@new_digest_algorithm, :exclusive) do
|
275
|
+
@counters = {good: 0, updated: 0, renamed: 0, likely_damaged: 0, exceptions: 0}
|
224
276
|
|
225
|
-
measure_time do
|
226
277
|
walk_files do |filename|
|
227
278
|
process_file filename
|
228
279
|
end
|
229
|
-
end
|
230
280
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
281
|
+
nested_transaction do
|
282
|
+
puts "Tracking renames..." if @options[:verbose]
|
283
|
+
track_renames
|
284
|
+
end
|
235
285
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
286
|
+
if any_missing_files?
|
287
|
+
if any_exceptions?
|
288
|
+
STDERR.puts "Due to previously occurred errors, missing files will not removed from the database."
|
289
|
+
else
|
290
|
+
print_missing_files
|
291
|
+
if !@options[:test_only] && (@options[:auto] || confirm("Remove missing files from the database"))
|
292
|
+
nested_transaction do
|
293
|
+
puts "Removing missing files..." if @options[:verbose]
|
294
|
+
remove_missing_files
|
295
|
+
end
|
245
296
|
end
|
246
297
|
end
|
247
298
|
end
|
248
|
-
end
|
249
299
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
300
|
+
if @new_digest_algorithm && !@options[:test_only]
|
301
|
+
if any_missing_files? || any_likely_damaged? || any_exceptions?
|
302
|
+
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."
|
303
|
+
else
|
304
|
+
puts "Updating database to a new digest algorithm..." if @options[:verbose]
|
305
|
+
digests_update_digests_to_new_digests
|
306
|
+
set_metadata "digest_algorithm", @new_digest_algorithm
|
307
|
+
puts "Transition to a new digest algorithm complete: #{@new_digest_algorithm}"
|
257
308
|
end
|
258
|
-
set_metadata "digest_algorithm", @new_digest_algorithm
|
259
|
-
puts "Transition to a new digest algorithm complete: #{@new_digest_algorithm}"
|
260
309
|
end
|
261
|
-
end
|
262
310
|
|
263
|
-
|
264
|
-
|
265
|
-
|
311
|
+
if any_likely_damaged? || any_exceptions?
|
312
|
+
STDERR.puts "PLEASE REVIEW ERRORS THAT WERE OCCURRED!"
|
313
|
+
end
|
266
314
|
|
267
|
-
|
315
|
+
set_metadata(@options[:test_only] ? "latest_test_only_check_time" : "latest_complete_check_time", time_to_database(Time.now))
|
268
316
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
317
|
+
print_counters
|
318
|
+
end
|
319
|
+
|
320
|
+
puts "Performing database maintenance..." if @options[:verbose]
|
321
|
+
execute "PRAGMA optimize"
|
322
|
+
execute "VACUUM"
|
323
|
+
execute "PRAGMA wal_checkpoint(TRUNCATE)"
|
276
324
|
|
277
|
-
|
325
|
+
hide_database_files
|
326
|
+
end
|
278
327
|
end
|
279
328
|
|
280
329
|
def show_duplicates
|
281
330
|
current_digest = nil
|
282
|
-
|
331
|
+
digests_select_duplicates.each do |found|
|
283
332
|
if current_digest != found["digest"]
|
284
333
|
puts "" if current_digest
|
285
334
|
current_digest = found["digest"]
|
@@ -311,9 +360,10 @@ class FileDigests
|
|
311
360
|
|
312
361
|
normalized_filename = filename.delete_prefix("#{@files_path.to_s}/").encode("utf-8", universal_newline: true).unicode_normalize(:nfkc)
|
313
362
|
mtime_string = time_to_database stat.mtime
|
314
|
-
digest = get_file_digest(filename)
|
363
|
+
digest, new_digest = get_file_digest(filename)
|
315
364
|
|
316
365
|
nested_transaction do
|
366
|
+
new_digests_insert(normalized_filename, new_digest) if new_digest
|
317
367
|
process_file_indeed normalized_filename, mtime_string, digest
|
318
368
|
end
|
319
369
|
|
@@ -331,15 +381,15 @@ class FileDigests
|
|
331
381
|
end
|
332
382
|
|
333
383
|
def process_previously_seen_file found, filename, mtime, digest
|
334
|
-
|
384
|
+
missing_files_delete filename
|
335
385
|
if found["digest"] == digest
|
336
386
|
@counters[:good] += 1
|
337
387
|
puts "GOOD: #{filename}" if @options[:verbose]
|
338
388
|
unless @options[:test_only]
|
339
389
|
if found["mtime"] == mtime
|
340
|
-
|
390
|
+
digests_touch_check_time found["id"]
|
341
391
|
else
|
342
|
-
|
392
|
+
digests_update_mtime mtime, found["id"]
|
343
393
|
end
|
344
394
|
end
|
345
395
|
else
|
@@ -350,18 +400,17 @@ class FileDigests
|
|
350
400
|
@counters[:updated] += 1
|
351
401
|
puts "UPDATED#{" (FATE ACCEPTED)" if found["mtime"] == mtime && @options[:accept_fate]}: #{filename}" unless @options[:quiet]
|
352
402
|
unless @options[:test_only]
|
353
|
-
|
403
|
+
digests_update_mtime_and_digest mtime, digest, found["id"]
|
354
404
|
end
|
355
405
|
end
|
356
406
|
end
|
357
407
|
end
|
358
408
|
|
359
409
|
def process_new_file filename, mtime, digest
|
360
|
-
@counters[:new] += 1
|
361
410
|
puts "NEW: #{filename}" unless @options[:quiet]
|
411
|
+
new_files_insert filename, digest
|
362
412
|
unless @options[:test_only]
|
363
|
-
|
364
|
-
insert filename, mtime, digest
|
413
|
+
digests_insert filename, mtime, digest
|
365
414
|
end
|
366
415
|
end
|
367
416
|
|
@@ -369,29 +418,31 @@ class FileDigests
|
|
369
418
|
# Renames and missing files
|
370
419
|
|
371
420
|
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
|
421
|
+
unless @options[:test_only]
|
422
|
+
digests_delete_renamed_files
|
380
423
|
end
|
424
|
+
missing_files_delete_renamed_files
|
425
|
+
@counters[:renamed] = @db.changes
|
381
426
|
end
|
382
427
|
|
383
428
|
def print_missing_files
|
384
429
|
puts "\nMISSING FILES:"
|
385
|
-
|
386
|
-
puts filename
|
430
|
+
missing_files_select_all_filenames.each do |record|
|
431
|
+
puts record["filename"]
|
387
432
|
end
|
388
433
|
end
|
389
434
|
|
390
435
|
def remove_missing_files
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
436
|
+
digests_delete_all_missing_files
|
437
|
+
missing_files_delete_all
|
438
|
+
end
|
439
|
+
|
440
|
+
def missing_files_count
|
441
|
+
missing_files_count_query!&.first&.first
|
442
|
+
end
|
443
|
+
|
444
|
+
def any_missing_files?
|
445
|
+
missing_files_count > 0
|
395
446
|
end
|
396
447
|
|
397
448
|
|
@@ -402,6 +453,7 @@ class FileDigests
|
|
402
453
|
end
|
403
454
|
|
404
455
|
def integrity_check
|
456
|
+
puts "Checking database integrity..." if @options[:verbose]
|
405
457
|
if execute("PRAGMA integrity_check")&.first&.fetch("integrity_check") != "ok"
|
406
458
|
raise "Database integrity check failed"
|
407
459
|
end
|
@@ -456,7 +508,7 @@ class FileDigests
|
|
456
508
|
end
|
457
509
|
|
458
510
|
def find_by_filename filename
|
459
|
-
result =
|
511
|
+
result = digests_find_by_filename_query filename
|
460
512
|
found = result.next
|
461
513
|
raise "Multiple records found" if result.next
|
462
514
|
found
|
@@ -476,6 +528,18 @@ class FileDigests
|
|
476
528
|
end
|
477
529
|
end
|
478
530
|
|
531
|
+
def check_if_database_is_at_certain_version target_version
|
532
|
+
current_version = get_metadata("database_version")
|
533
|
+
if current_version != target_version
|
534
|
+
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."
|
535
|
+
raise "Incompatible database version"
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def new_files_count
|
540
|
+
new_files_count_query!&.first&.first
|
541
|
+
end
|
542
|
+
|
479
543
|
|
480
544
|
# Filesystem-related helpers
|
481
545
|
|
@@ -498,8 +562,8 @@ class FileDigests
|
|
498
562
|
end
|
499
563
|
|
500
564
|
def walk_files
|
501
|
-
|
502
|
-
yield
|
565
|
+
Find.find(@files_path) do |path|
|
566
|
+
yield path
|
503
567
|
end
|
504
568
|
end
|
505
569
|
|
@@ -513,18 +577,13 @@ class FileDigests
|
|
513
577
|
digest.update(buffer)
|
514
578
|
new_digest.update(buffer) if @new_digest_algorithm
|
515
579
|
end
|
516
|
-
|
517
|
-
return digest.hexdigest
|
580
|
+
return [digest.hexdigest, (new_digest.hexdigest if @new_digest_algorithm)]
|
518
581
|
end
|
519
582
|
end
|
520
583
|
|
521
584
|
|
522
585
|
# Runtime state helpers
|
523
586
|
|
524
|
-
def any_missing_files?
|
525
|
-
@missing_files.length > 0
|
526
|
-
end
|
527
|
-
|
528
587
|
def any_exceptions?
|
529
588
|
@counters[:exceptions] > 0
|
530
589
|
end
|
@@ -538,14 +597,17 @@ class FileDigests
|
|
538
597
|
def confirm text
|
539
598
|
if STDIN.tty? && STDOUT.tty?
|
540
599
|
puts "#{text} (y/n)?"
|
541
|
-
|
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
|
542
604
|
end
|
543
605
|
end
|
544
606
|
|
545
607
|
def measure_time
|
546
608
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
547
609
|
yield
|
548
|
-
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
|
610
|
+
elapsed = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) - @user_input_wait_time
|
549
611
|
puts "Elapsed time: #{elapsed.to_i / 3600}h #{(elapsed.to_i % 3600) / 60}m #{"%.3f" % (elapsed % 60)}s" unless @options[:quiet]
|
550
612
|
end
|
551
613
|
|
@@ -563,11 +625,14 @@ class FileDigests
|
|
563
625
|
end
|
564
626
|
|
565
627
|
def print_counters
|
628
|
+
missing_files_count_result = missing_files_count
|
629
|
+
new_files_count_result = new_files_count - @counters[:renamed]
|
630
|
+
|
566
631
|
puts "#{@counters[:good]} file(s) passes digest check" if @counters[:good] > 0
|
567
632
|
puts "#{@counters[:updated]} file(s) are updated" if @counters[:updated] > 0
|
568
|
-
puts "#{
|
633
|
+
puts "#{new_files_count_result} file(s) are new" if new_files_count_result > 0
|
569
634
|
puts "#{@counters[:renamed]} file(s) are renamed" if @counters[:renamed] > 0
|
570
|
-
puts "#{
|
635
|
+
puts "#{missing_files_count_result} file(s) are missing" if missing_files_count_result > 0
|
571
636
|
puts "#{@counters[:likely_damaged]} file(s) are likely damaged (!)" if @counters[:likely_damaged] > 0
|
572
637
|
puts "#{@counters[:exceptions]} file(s) had exceptions occured during processing (!)" if @counters[:exceptions] > 0
|
573
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.36
|
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
|