fingerprint 1.4.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:test)
5
+
6
+ task :default => :test
@@ -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,7 +1,5 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'fingerprint/version'
1
+
2
+ require_relative 'lib/fingerprint/version'
5
3
 
6
4
  Gem::Specification.new do |spec|
7
5
  spec.name = "fingerprint"
@@ -20,8 +18,11 @@ Gem::Specification.new do |spec|
20
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
19
  spec.require_paths = ["lib"]
22
20
 
23
- spec.add_development_dependency "bundler", "~> 1.3"
24
- spec.add_development_dependency "rake"
21
+ spec.add_dependency "samovar", "~> 2.0"
22
+ spec.add_dependency "build-files", "~> 1.2"
25
23
 
26
- spec.add_dependency "lockfile"
24
+ spec.add_development_dependency "covered"
25
+ spec.add_development_dependency "bundler"
26
+ spec.add_development_dependency "rspec", "~> 3.4"
27
+ spec.add_development_dependency "rake"
27
28
  end
@@ -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
@@ -25,7 +25,7 @@ require 'fingerprint/checker'
25
25
 
26
26
  module Fingerprint
27
27
  # A helper function to check two paths for consistency. Provides callback from +Fingerprint::Checker+.
28
- def self.check_paths(master_path, copy_path, &block)
28
+ def self.check_paths(master_path, copy_path, **options, &block)
29
29
  master = Scanner.new([master_path])
30
30
  copy = Scanner.new([copy_path])
31
31
 
@@ -34,10 +34,23 @@ module Fingerprint
34
34
 
35
35
  master.scan(master_recordset)
36
36
 
37
- checker = Checker.new(master_recordset, copy_recordset)
37
+ checker = Checker.new(master_recordset, copy_recordset, **options)
38
38
 
39
39
  checker.check(&block)
40
40
 
41
41
  return checker
42
42
  end
43
+
44
+ # Returns true if the given paths contain identical files. Useful for expectations, e.g. `expect(Fingerprint).to be_identical(source, destination)`
45
+ def self.identical?(source, destination, &block)
46
+ failures = 0
47
+
48
+ check_paths(source, destination) do |record, name, message|
49
+ failures += 1
50
+
51
+ yield(record) if block_given?
52
+ end
53
+
54
+ return failures == 0
55
+ end
43
56
  end
@@ -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
@@ -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
@@ -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,90 @@
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 'scanner'
28
+
29
+ require_relative 'command/scan'
30
+ require_relative 'command/analyze'
31
+ require_relative 'command/verify'
32
+ require_relative 'command/compare'
33
+ require_relative 'command/duplicates'
34
+
35
+ module Fingerprint
36
+ module Command
37
+ def self.call(*args)
38
+ Top.call(*args)
39
+ end
40
+
41
+ class Top < Samovar::Command
42
+ self.description = "A file checksum analysis and verification tool."
43
+
44
+ options do
45
+ option '--root <path>', "Work in the given root directory."
46
+
47
+ option '-o/--output <path>', "Output the transcript to a specific file rather than stdout."
48
+
49
+ option '-h/--help', "Print out help information."
50
+ option '-v/--version', "Print out the application version."
51
+ end
52
+
53
+ def chdir(&block)
54
+ if root = @options[:root]
55
+ Dir.chdir(root, &block)
56
+ else
57
+ yield
58
+ end
59
+ end
60
+
61
+ def output
62
+ if path = @options[:output]
63
+ File.open(path, "w")
64
+ else
65
+ $stdout
66
+ end
67
+ end
68
+
69
+ nested :command, {
70
+ 'scan' => Scan,
71
+ 'analyze' => Analyze,
72
+ 'verify' => Verify,
73
+ 'compare' => Compare,
74
+ 'duplicates' => Duplicates
75
+ }, default: 'analyze'
76
+
77
+ def call
78
+ if @options[:version]
79
+ puts "fingerprint v#{VERSION}"
80
+ elsif @options[:help]
81
+ self.print_usage(program_name)
82
+ else
83
+ chdir do
84
+ @command.call
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end