fingerprint 1.4.0 → 3.2.0

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
- 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