fingerprint 1.4.0 → 3.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2c6867e9566430e12dc2d913a013c469e3b2bc47
4
- data.tar.gz: 58d9a1812dcd041743816328ac3e71fc79496014
2
+ SHA256:
3
+ metadata.gz: 29779cfa264198432f16e421ed412e812a464332c4499d65e6a8039d0c08522f
4
+ data.tar.gz: 97dc135381bfa725ab41d34fbaf58ff56a16c89bb2bb8749b1539c90abe30cd1
5
5
  SHA512:
6
- metadata.gz: ac0bfcca4b51a31797849aa039c795626f78d7a5d0b5278aadbb9872b635d7ca3cd369b3cd08de77c48545ca58af4aad83ede79e99749b56e896a03b8e238e5e
7
- data.tar.gz: 76f51cf43136114a35cafb99958da8e7099c98ee68a931efa7a1b853e76dc9025a2bedd6df697ebf69b7c7f47004f3616865514beea9c980d8a9e4798f7eec58
6
+ metadata.gz: a8f9fdb7259e57057bc10f9e412b0444393ab2bcd90d11b7091fffa40800759f2a52f7fcc25a2f8edafe8cebbc199ae6a81eb95401e2e2204f2bb28d1ab611d0
7
+ data.tar.gz: 418347660a6002e3e1cc5092a0e50c6d4462a034a6ccb1afe5e74f2912d2bb1d9dc3eda892fe4342a2db151d2952410461cbdde5f954fa6e881dc59e2df6d251
checksums.yaml.gz.sig ADDED
@@ -0,0 +1,4 @@
1
+ .P�v�������m���\Q=G �iv O,����/�.>e��'\����0H���$ѭ5X�����,D���J!�����Ҝ�+*��T04mPkTR�:>F -^��i`�/��G�w�ܺ�ź����F1A<>�J
2
+ �?&'�.�PvqsL���W���G�Q��p[��@�M�����P�,H�q�����S e>��u�_��K��r�� A��?�)g/�׍=��/�#����=-�R2�������a���^�,�=����> Y������7;K�tA��;���D��;� O��_�����B4�Y��ߕ�y%8sb�ͦ��x�
3
+ �C�S��xG�
4
+ [I�c/�[r+W>�&��Ӈ�~H E�R�K�Y"��l>:
data/bin/fingerprint CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
3
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -20,201 +20,10 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'optparse'
24
- require 'pathname'
25
- require 'fingerprint'
26
- require 'fileutils'
23
+ # This script takes a given path, and renames it with the given format.
24
+ # It then ensures that there is a symlink called "latest" that points
25
+ # to the renamed directory.
27
26
 
28
- OPTIONS = {
29
- :root => "./",
30
- :mode => :scan,
31
- :output => $stdout,
32
- :verbose => false,
33
- :force => false,
34
- :name => "index.fingerprint",
35
- :extended => false,
36
- :checksums => Fingerprint::DEFAULT_CHECKSUMS,
37
- :additions => false,
38
- :failures => :ignore,
39
- }
27
+ require_relative '../lib/fingerprint/command'
40
28
 
41
- ARGV.options do |o|
42
- script_name = File.basename($0)
43
-
44
- o.banner = "Usage: #{script_name} [options] [path]"
45
- o.define_head "This script is used to create and compare file system fingerprints."
46
-
47
- o.separator ""
48
- o.separator "Directory analysis and verification:"
49
-
50
- o.on("-a", "--analyze [path]", String, "Generage a fingerprint of the given path and save it for later verification.") do |path|
51
- OPTIONS[:mode] = :analyze
52
- OPTIONS[:root] = path if path
53
- end
54
-
55
- o.on("-v", "--verify [path]", String, "Verify a given path based on a previously saved fingerprint.") do |path|
56
- OPTIONS[:mode] = :verify
57
- OPTIONS[:root] = path if path
58
- end
59
-
60
- o.on("-n name", String, "Specify the name of the fingerprint file.", "Default: #{OPTIONS[:name]}") do |name|
61
- OPTIONS[:name] = name
62
- end
63
-
64
- o.on("-f", "Force any operation to complete despite warnings.") do
65
- OPTIONS[:force] = true
66
- end
67
-
68
- o.separator ""
69
-
70
- o.on("-x", "Include additional extended information about files and directories.") do
71
- OPTIONS[:extended] = true
72
- end
73
-
74
- o.on("-s [checksum1,checksum2]", "Provide a list of the checksum algorithms to use.", "Available: #{Fingerprint::CHECKSUMS.keys.join(', ')}; Default: #{OPTIONS[:checksums].join(', ')}") do |checksums|
75
- OPTIONS[:checksums] = checksums.split(/[\s,]+/)
76
- end
77
-
78
- o.separator ""
79
- o.separator "Compare fingerprints:"
80
-
81
- o.on("-c", "Compare the given fingerprints. Check that the second fingerprint is a superset of the first.") do
82
- OPTIONS[:mode] = :check
83
- end
84
-
85
- o.on("-A", "Report files that have been added to the second fingerprint.") do
86
- OPTIONS[:additions] = true
87
- end
88
-
89
- o.separator ""
90
- o.separator "Output manipulation:"
91
-
92
- o.on("-o [output-path]", String, "Write the fingerprint output to the given file.") do |path|
93
- OPTIONS[:output] = File.open(path, "w")
94
- end
95
-
96
- o.on("--verbose", "Verbose output, include additional details in the file transcript.") do
97
- OPTIONS[:verbose] = true
98
- end
99
-
100
- o.on("--progress", "Print percentage progress to standard error.") do
101
- OPTIONS[:progress] = true
102
- end
103
-
104
- o.on("--die", "Give a non-zero exit code if errors are detected by check or verify.") do
105
- OPTIONS[:failures] = :die
106
- end
107
-
108
- o.separator ""
109
- o.separator "Help and Copyright information:"
110
-
111
- o.on_tail("--copy", "Display copyright and warranty information") do
112
- $stderr.puts "#{script_name} v#{Fingerprint::VERSION}. Copyright (c) 2011 Samuel Williams."
113
- $stderr.puts "This software is released under the MIT license and comes with ABSOLUTELY NO WARRANTY."
114
- $stderr.puts "See http://www.oriontransfer.co.nz/ for more information."
115
- exit
116
- end
117
-
118
- o.on_tail("-h", "--help", "Show this help message.") do
119
- $stderr.puts o
120
- exit
121
- end
122
- end.parse!
123
-
124
- unless File.directory? OPTIONS[:root]
125
- $stderr.puts "Path #{OPTIONS[:root]} doesn't exist!"
126
- exit(255)
127
- end
128
-
129
- if OPTIONS[:checksums].size == 0
130
- OPTIONS[:checksums] = ['MD5', 'SHA2.256']
131
- end
132
-
133
- def finish_check(error_count)
134
- if error_count == 0
135
- $stderr.puts "Data verified, 0 errors found."
136
- exit(0)
137
- else
138
- $stderr.puts "Data inconsistent, #{error_count} errors found!"
139
- exit(OPTIONS[:failures] == :die ? 1 : 0)
140
- end
141
- end
142
-
143
- case (OPTIONS[:mode])
144
- when :analyze
145
- output_file = Pathname.new(OPTIONS[:root]) + OPTIONS[:name]
146
-
147
- if output_file.exist? && !OPTIONS[:force]
148
- $stderr.puts "Output file #{output_file} already exists. Aborting."
149
- exit(2)
150
- end
151
-
152
- options = OPTIONS.dup
153
- options[:excludes] = [OPTIONS[:name]]
154
-
155
- finished = false
156
- begin
157
- File.open(output_file, "w") do |io|
158
- options[:output] = io
159
-
160
- Fingerprint::Scanner.scan_paths([OPTIONS[:root]], options)
161
- end
162
- finished = true
163
- ensure
164
- FileUtils.rm(output_file) unless finished
165
- end
166
- when :verify
167
- error_count = 0
168
-
169
- input_file = Pathname.new(OPTIONS[:root]) + OPTIONS[:name]
170
-
171
- unless File.exist? input_file
172
- $stderr.puts "Can't find index #{input_file}. Aborting."
173
- exit(3)
174
- end
175
-
176
- options = OPTIONS.dup
177
-
178
- master = Fingerprint::RecordSet.new
179
-
180
- File.open(input_file, "r") do |io|
181
- master.parse(io)
182
- end
183
-
184
- if master.configuration
185
- options.merge!(master.configuration.options)
186
- end
187
-
188
- scanner = Fingerprint::Scanner.new([OPTIONS[:root]], options)
189
- copy = Fingerprint::SparseRecordSet.new(scanner)
190
-
191
- error_count += Fingerprint::Checker::verify(master, copy, options)
192
-
193
- finish_check(error_count)
194
- when :scan
195
- roots = ARGV
196
- roots << Dir.pwd if roots.size == 0
197
-
198
- # Check that all supplied paths exist
199
- roots.delete_if do |root|
200
- if File.exist? root
201
- false
202
- else
203
- $stderr.puts "Path #{root} doesn't exist, skipping!"
204
- true
205
- end
206
- end
207
-
208
- options = OPTIONS.dup
209
-
210
- # Discard output once it has been written to disk:
211
- options[:recordset] = nil
212
-
213
- Fingerprint::Scanner.scan_paths(roots, options)
214
- when :check
215
- options = OPTIONS.dup
216
-
217
- error_count = Fingerprint::Checker.check_files(ARGV[0], ARGV[1], options)
218
-
219
- finish_check(error_count)
220
- end
29
+ Fingerprint::Command.call
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
1
+ # Copyright, 2011, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -18,7 +18,7 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'fingerprint/record'
21
+ require_relative 'record'
22
22
 
23
23
  module Fingerprint
24
24
  # Given two fingerprints (master and copy) ensures that the copy has at least everything contained
@@ -31,7 +31,7 @@ module Fingerprint
31
31
  #
32
32
  # Master and copy are +IO+ objects corresponding to the output produced by +Fingerprint::Scanner+.
33
33
  class Checker
34
- def initialize(master, copy, options = {})
34
+ def initialize(master, copy, **options)
35
35
  @master = master
36
36
  @copy = copy
37
37
 
@@ -42,7 +42,7 @@ module Fingerprint
42
42
  attr :copy
43
43
 
44
44
  # Run the checking process.
45
- def check (&block)
45
+ def check(&block)
46
46
  # For every file in the src, we check that it exists
47
47
  # in the destination:
48
48
  total_count = @master.records.count
@@ -77,7 +77,7 @@ module Fingerprint
77
77
  end
78
78
 
79
79
  if @options[:progress]
80
- $stderr.puts "# Progress: File #{processed_count} / #{total_count}; Byte #{processed_size} / #{total_size} = #{sprintf('%0.2f%', processed_size.to_f / total_size.to_f * 100.0)}"
80
+ $stderr.puts "# Progress: File #{processed_count} / #{total_count}; Byte #{processed_size} / #{total_size} = #{sprintf('%0.2f%%', processed_size.to_f / total_size.to_f * 100.0)}"
81
81
 
82
82
  processed_size += (record['file.size'] || 0).to_i
83
83
  end
@@ -95,7 +95,7 @@ module Fingerprint
95
95
  # A list of files which either did not exist in the copy, or had the wrong checksum.
96
96
  attr :failures
97
97
 
98
- def self.check_files(master, copy, options = {}, &block)
98
+ def self.check_files(master, copy, **options, &block)
99
99
  # New API that takes two RecordSets...
100
100
 
101
101
  File.open(master) do |master_file|
@@ -106,13 +106,13 @@ module Fingerprint
106
106
  copy_recordset = RecordSet.new
107
107
  copy_recordset.parse(copy_file)
108
108
 
109
- verify(master_recordset, copy_recordset, options, &block)
109
+ verify(master_recordset, copy_recordset, **options, &block)
110
110
  end
111
111
  end
112
112
  end
113
113
 
114
114
  # Helper function to check two fingerprint files.
115
- def self.verify(master, copy, options = {}, &block)
115
+ def self.verify(master, copy, **options, &block)
116
116
  error_count = 0
117
117
 
118
118
  errors = options.delete(:recordset) || RecordSet.new
@@ -120,7 +120,7 @@ module Fingerprint
120
120
  errors = RecordSetPrinter.new(errors, options[:output])
121
121
  end
122
122
 
123
- checker = Checker.new(master, copy, options)
123
+ checker = Checker.new(master, copy, **options)
124
124
 
125
125
  checker.check do |record, result, message|
126
126
  error_count += 1
@@ -0,0 +1,33 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # This script takes a given path, and renames it with the given format.
22
+ # It then ensures that there is a symlink called "latest" that points
23
+ # to the renamed directory.
24
+
25
+ require 'samovar'
26
+
27
+ module Fingerprint
28
+ module Checksums
29
+ def self.call(result)
30
+ result.split(/\s*,\s*/)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,74 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # This script takes a given path, and renames it with the given format.
22
+ # It then ensures that there is a symlink called "latest" that points
23
+ # to the renamed directory.
24
+
25
+ require 'samovar'
26
+ require 'fileutils'
27
+
28
+ require_relative '../checksums'
29
+ require_relative '../scanner'
30
+ require_relative '../record'
31
+
32
+ module Fingerprint
33
+ module Command
34
+ class Analyze < Samovar::Command
35
+ self.description = "Generates a fingerprint for the specified paths and saves it."
36
+
37
+ options do
38
+ option "-n/--name <name>", "The fingerprint file name.", default: INDEX_FINGERPRINT
39
+
40
+ option "-f/--force", "Force all operations to complete despite warnings."
41
+ option "-x/--extended", "Include extended information about files and directories."
42
+ option "-s/--checksums <SHA2.256>", "Specify what checksum algorithms to use: #{CHECKSUMS.keys.join(', ')}.", default: DEFAULT_CHECKSUMS, type: Checksums
43
+
44
+ option "--progress", "Print structured progress to standard error."
45
+ option "--verbose", "Verbose fingerprint output, e.g. excluded paths."
46
+ end
47
+
48
+ many :paths, "Paths relative to the root to use for verification, or pwd if not specified.", default: ["./"]
49
+
50
+ def call
51
+ output_file = @options[:name]
52
+
53
+ if File.exist?(output_file) and !@options[:force]
54
+ abort "Output file #{output_file} already exists. Aborting."
55
+ end
56
+
57
+ options = @options.dup
58
+ options[:excludes] = [File.expand_path(options[:name], Dir.pwd)]
59
+
60
+ finished = false
61
+ begin
62
+ File.open(output_file, "w") do |io|
63
+ options[:output] = io
64
+
65
+ Scanner.scan_paths(@paths, **options)
66
+ end
67
+ finished = true
68
+ ensure
69
+ FileUtils.rm(output_file) unless finished
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # This script takes a given path, and renames it with the given format.
22
+ # It then ensures that there is a symlink called "latest" that points
23
+ # to the renamed directory.
24
+
25
+ require 'samovar'
26
+
27
+ module Fingerprint
28
+ module Command
29
+ class Compare < Samovar::Command
30
+ self.description = "Compare two fingerprints and report additions, removals and changes."
31
+
32
+ options do
33
+ option "-x/--extended", "Include extended information about files and directories."
34
+ option "-a/--additions", "Report files that have been added to the copy."
35
+ option "--fail-on-errors", "Exit with non-zero status if errors are encountered."
36
+
37
+ option "--progress", "Print structured progress to standard error."
38
+ end
39
+
40
+ one :master, "The fingerprint which represents the original data."
41
+ one :copy, "The fingerprint which represents a copy of the data."
42
+
43
+ def call
44
+ options = @options.dup
45
+ options[:output] = @parent.output
46
+
47
+ error_count = Checker.check_files(@master, @copy, **options)
48
+
49
+ if @options[:fail_on_errors]
50
+ abort "Data inconsistent, #{error_count} error(s) found!" if error_count != 0
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,98 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # This script takes a given path, and renames it with the given format.
22
+ # It then ensures that there is a symlink called "latest" that points
23
+ # to the renamed directory.
24
+
25
+ require 'samovar'
26
+
27
+ module Fingerprint
28
+ module Command
29
+ class Duplicates < Samovar::Command
30
+ self.description = "Efficiently find duplicates in a given fingerprint."
31
+
32
+ options do
33
+ option "-i/--inverse", "Invert the output, i.e. show files which are not duplicates."
34
+ option "-x/--extended", "Include extended information about files and directories."
35
+
36
+ option "--verbose", "Verbose output, e.g. what is happening."
37
+ end
38
+
39
+ one :master, "The source fingerprint which represents the primarily file list."
40
+ many :copies, "Zero or more fingerprints which might contain duplicates.", default: []
41
+
42
+ attr :duplicates_recordset
43
+
44
+ def call
45
+ @options[:output] = @parent.output
46
+
47
+ @duplicates_recordset = RecordSet.new
48
+ results = RecordSetPrinter.new(duplicates_recordset, @options[:output])
49
+
50
+ master_file_path = @master
51
+ File.open(master_file_path) do |master_file|
52
+ master_recordset = RecordSet.new
53
+ master_recordset.parse(master_file)
54
+
55
+ ignore_similar = false
56
+
57
+ copy_file_paths = @copies
58
+
59
+ if copy_file_paths.size == 0
60
+ copy_file_paths = [master_file_path]
61
+ ignore_similar = true
62
+ end
63
+
64
+ copy_file_paths.each do |copy_file_path|
65
+ File.open(copy_file_path) do |copy_file|
66
+ copy_recordset = RecordSet.new
67
+ copy_recordset.parse(copy_file)
68
+
69
+ copy_recordset.records.each do |record|
70
+ record.metadata['fingerprint'] = copy_file_path
71
+ # We need to see if the record exists in the master
72
+
73
+ if @options[:verbose]
74
+ $stderr.puts "Checking #{record.inspect}"
75
+ end
76
+
77
+ main_record = master_recordset.find_by_key(record)
78
+
79
+ # If we are scanning the same index, don't print out every file, just those that are duplicates within the single file.
80
+ if ignore_similar && main_record && (main_record.path == record.path)
81
+ main_record = nil
82
+ end
83
+
84
+ if main_record
85
+ record.metadata['original.path'] = main_record.path
86
+ record.metadata['original.fingerprint'] = master_file_path
87
+ results << record if !@options[:inverse]
88
+ else
89
+ results << record if @options[:inverse]
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ # This script takes a given path, and renames it with the given format.
22
+ # It then ensures that there is a symlink called "latest" that points
23
+ # to the renamed directory.
24
+
25
+ require 'samovar'
26
+
27
+ require_relative '../checksums'
28
+ require_relative '../scanner'
29
+ require_relative '../record'
30
+
31
+ module Fingerprint
32
+ module Command
33
+ class Scan < Samovar::Command
34
+ self.description = "Generate a fingerprint from the given paths."
35
+
36
+ options do
37
+ option "-p/--path <path>", "Analyze the given path relative to root.", default: "./"
38
+
39
+ option "-x/--extended", "Include extended information about files and directories."
40
+ option "-s/--checksums <SHA2.256>", "Specify what checksum algorithms to use: #{CHECKSUMS.keys.join(', ')}.", default: DEFAULT_CHECKSUMS, type: Checksums
41
+
42
+ option "--progress", "Print structured progress to standard error."
43
+ option "--verbose", "Verbose fingerprint output, e.g. excluded paths."
44
+ end
45
+
46
+ many :paths, "Paths to scan."
47
+
48
+ def call
49
+ @paths = [Dir.pwd] unless @paths
50
+
51
+ options = @options.dup
52
+
53
+ # This configuration ensures that the output is printed to $stdout.
54
+ options[:output] = @parent.output
55
+ options[:recordset] = nil
56
+
57
+ Scanner.scan_paths(@paths, **options)
58
+ end
59
+ end
60
+ end
61
+ end