fingerprint 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2c6867e9566430e12dc2d913a013c469e3b2bc47
4
+ data.tar.gz: 58d9a1812dcd041743816328ac3e71fc79496014
5
+ SHA512:
6
+ metadata.gz: ac0bfcca4b51a31797849aa039c795626f78d7a5d0b5278aadbb9872b635d7ca3cd369b3cd08de77c48545ca58af4aad83ede79e99749b56e896a03b8e238e5e
7
+ data.tar.gz: 76f51cf43136114a35cafb99958da8e7099c98ee68a931efa7a1b853e76dc9025a2bedd6df697ebf69b7c7f47004f3616865514beea9c980d8a9e4798f7eec58
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fingerprint.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -1,9 +1,4 @@
1
- Fingerprint
2
- ===========
3
-
4
- * Author: Samuel G. D. Williams (<http://www.oriontransfer.co.nz>)
5
- * Copyright (C) 2010, 2011 Samuel G. D. Williams.
6
- * Released under the MIT license.
1
+ # Fingerprint
7
2
 
8
3
  Fingerprint is primarily a command line tool to compare directory structures on
9
4
  disk. It also provides a programmatic interface for this procedure.
@@ -14,10 +9,27 @@ used to check the integrity of a remote backup.
14
9
 
15
10
  For examples and documentation please see the main [project page][1].
16
11
 
17
- [1]: http://www.oriontransfer.co.nz/gems/fingerprint
12
+ [1]: http://www.codeotaku.com/projects/fingerprint/index
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'fingerprint'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
18
25
 
19
- Todo
20
- ----
26
+ $ gem install fingerprint
27
+
28
+ ## Usage
29
+
30
+ Please refer to the [online documentation][http://www.codeotaku.com/projects/fingerprint/documentation/introduction].
31
+
32
+ ## Todo
21
33
 
22
34
  * Command line option to show files that have been created (e.g. don't exist in master fingerprint).
23
35
  * Command line option to show files that have changed but have the same modified time (hardware corrutpion).
@@ -28,10 +40,19 @@ Todo
28
40
  * Support general filenames for `--archive`, e.g. along with `-n`, maybe support a file called `index.fingerprint` by default: improved visibility for end user.
29
41
  * Because fingerprint is currently IO bound in terms of performance, single-threaded checksumming is fine, but for SSD and other fast storage, it might be possible to improve speed somewhat by using a map-reduce style approach.
30
42
 
31
- License
32
- -------
43
+ ## Contributing
44
+
45
+ 1. Fork it
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create new Pull Request
50
+
51
+ ## License
52
+
53
+ Released under the MIT license.
33
54
 
34
- Copyright (c) 2010, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
55
+ Copyright, 2012, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
35
56
 
36
57
  Permission is hereby granted, free of charge, to any person obtaining a copy
37
58
  of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,6 @@
23
23
  require 'optparse'
24
24
  require 'pathname'
25
25
  require 'fingerprint'
26
- require 'lockfile'
27
26
  require 'fileutils'
28
27
 
29
28
  OPTIONS = {
@@ -35,9 +34,8 @@ OPTIONS = {
35
34
  :name => "index.fingerprint",
36
35
  :extended => false,
37
36
  :checksums => Fingerprint::DEFAULT_CHECKSUMS,
38
- :lockfile => true,
39
37
  :additions => false,
40
- :failures_exit_status => 0,
38
+ :failures => :ignore,
41
39
  }
42
40
 
43
41
  ARGV.options do |o|
@@ -103,19 +101,15 @@ ARGV.options do |o|
103
101
  OPTIONS[:progress] = true
104
102
  end
105
103
 
106
- o.on("--no-lockfile", "Don't use a lockfile to validate access to the fingerprint.") do
107
- OPTIONS[:lockfile] = false
108
- end
109
-
110
- o.on("-X", "Give a non-zero exit code if errors are detected by check or verify.") do
111
- OPTIONS[:failures_exit_status] = 1
104
+ o.on("--die", "Give a non-zero exit code if errors are detected by check or verify.") do
105
+ OPTIONS[:failures] = :die
112
106
  end
113
107
 
114
108
  o.separator ""
115
109
  o.separator "Help and Copyright information:"
116
110
 
117
111
  o.on_tail("--copy", "Display copyright and warranty information") do
118
- $stderr.puts "#{script_name} v#{Fingerprint::VERSION::STRING}. Copyright (c) 2011 Samuel Williams."
112
+ $stderr.puts "#{script_name} v#{Fingerprint::VERSION}. Copyright (c) 2011 Samuel Williams."
119
113
  $stderr.puts "This software is released under the MIT license and comes with ABSOLUTELY NO WARRANTY."
120
114
  $stderr.puts "See http://www.oriontransfer.co.nz/ for more information."
121
115
  exit
@@ -136,121 +130,91 @@ if OPTIONS[:checksums].size == 0
136
130
  OPTIONS[:checksums] = ['MD5', 'SHA2.256']
137
131
  end
138
132
 
139
- # Run some block with the given lock, if requested.
140
- def with_lock
141
- lockfile_path = nil
142
- if OPTIONS[:lockfile] == true
143
- lockfile_path = Pathname.new(OPTIONS[:root]) + (OPTIONS[:name] + ".lock")
144
- elsif OPTION[:lockfile] != false
145
- lockfile_path = OPTIONS[:lockfile]
146
- end
147
-
148
- if lockfile_path
149
- begin
150
- Lockfile.new(lockfile_path, :retries => 0) do
151
- yield
152
- end
153
- rescue Lockfile::MaxTriesLockError
154
- $stderr.puts "Could not acquire lock #{lockfile_path}."
155
-
156
- return false
157
- end
158
- else
159
- yield
160
- end
161
-
162
- return true
163
- end
164
-
165
133
  def finish_check(error_count)
166
134
  if error_count == 0
167
135
  $stderr.puts "Data verified, 0 errors found."
168
136
  exit(0)
169
137
  else
170
138
  $stderr.puts "Data inconsistent, #{error_count} errors found!"
171
- exit(OPTIONS[:failures_exit_status])
139
+ exit(OPTIONS[:failures] == :die ? 1 : 0)
172
140
  end
173
141
  end
174
142
 
175
143
  case (OPTIONS[:mode])
176
- when :analyze
177
- result = with_lock do
178
- output_file = Pathname.new(OPTIONS[:root]) + OPTIONS[:name]
179
-
180
- if output_file.exist? && !OPTIONS[:force]
181
- $stderr.puts "Output file #{output_file} already exists. Aborting."
182
- exit(2)
183
- end
184
-
185
- options = OPTIONS.dup
186
- options[:excludes] = [OPTIONS[:name]]
187
-
188
- finished = false
189
- begin
190
- File.open(output_file, "w") do |io|
191
- options[:output] = io
192
-
193
- Fingerprint::Scanner.scan_paths([OPTIONS[:root]], options)
194
- end
195
- finished = true
196
- ensure
197
- FileUtils.rm(output_file) unless finished
198
- end
199
- end
200
-
201
- unless result
202
- # Lockfile failure
203
- exit(4)
204
- end
205
- when :verify
206
- error_count = 0
207
-
208
- input_file = Pathname.new(OPTIONS[:root]) + OPTIONS[:name]
209
-
210
- unless File.exist? input_file
211
- $stderr.puts "Can't find index #{input_file}. Aborting."
212
- exit(3)
213
- end
214
-
215
- options = OPTIONS.dup
216
-
217
- master = Fingerprint::Recordset.new
218
-
219
- File.open(input_file, "r") do |io|
220
- master.parse(io)
221
- end
222
-
223
- if master.configuration
224
- options.merge!(master.configuration.options)
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)
225
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
226
177
 
227
- scanner = Fingerprint::Scanner.new([OPTIONS[:root]], options)
228
- copy = Fingerprint::SparseRecordset.new(scanner)
229
-
230
- error_count += Fingerprint::Checker::verify(master, copy, options)
231
-
232
- finish_check(error_count)
233
- when :scan
234
- roots = ARGV
235
- roots << Dir.pwd if roots.size == 0
236
-
237
- # Check that all supplied paths exist
238
- roots.delete_if do |root|
239
- if File.exist? root
240
- false
241
- else
242
- $stderr.puts "Path #{root} doesn't exist, skipping!"
243
- true
244
- end
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
245
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
246
216
 
247
- options = OPTIONS.dup
217
+ error_count = Fingerprint::Checker.check_files(ARGV[0], ARGV[1], options)
248
218
 
249
- Fingerprint::Scanner.scan_paths(roots, options)
250
- when :check
251
- options = OPTIONS.dup
252
-
253
- error_count = Fingerprint::Checker.check_files(ARGV[0], ARGV[1], options)
254
-
255
- finish_check(error_count)
219
+ finish_check(error_count)
256
220
  end
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'optparse'
24
+ require 'pathname'
25
+ require 'fingerprint'
26
+ require 'lockfile'
27
+ require 'fileutils'
28
+
29
+ OPTIONS = {
30
+ :mode => nil,
31
+ :output => $stdout,
32
+ :verbose => false,
33
+ :force => false,
34
+ :extended => false,
35
+ :inverse => false
36
+ }
37
+
38
+ $options = nil
39
+
40
+ ARGV.options do |o|
41
+ $options = o
42
+
43
+ script_name = File.basename($0)
44
+
45
+ o.banner = "Usage: #{script_name} [options] [path]"
46
+ o.define_head "This script is used to calculate the differences between two fingerprints."
47
+
48
+ o.separator ""
49
+ o.separator "Set operations between fingerprints:"
50
+
51
+ o.on("--duplicates", "Calculate files in copy that already exist in master") do |master, copy|
52
+ OPTIONS[:mode] = :duplicates
53
+ end
54
+
55
+ o.separator ""
56
+ o.separator "Output manipulation:"
57
+
58
+ o.on("-o [output-path]", String, "Write the fingerprint output to the given file.") do |path|
59
+ OPTIONS[:output] = File.open(path, "w")
60
+ end
61
+
62
+ o.on("--verbose", "Verbose output, include additional details in the file transcript.") do
63
+ OPTIONS[:verbose] = true
64
+ end
65
+
66
+ o.on("--progress", "Print percentage progress to standard error.") do
67
+ OPTIONS[:progress] = true
68
+ end
69
+
70
+ o.on("--inverse", "Show the inverse of the selected operation.") do
71
+ OPTIONS[:inverse] = true
72
+ end
73
+
74
+ o.separator ""
75
+ o.separator "Help and Copyright information:"
76
+
77
+ o.on_tail("--copy", "Display copyright and warranty information") do
78
+ $stderr.puts "#{script_name} v#{Fingerprint::VERSION::STRING}. Copyright (c) 2011 Samuel Williams."
79
+ $stderr.puts "This software is released under the MIT license and comes with ABSOLUTELY NO WARRANTY."
80
+ $stderr.puts "See http://www.oriontransfer.co.nz/ for more information."
81
+ exit
82
+ end
83
+
84
+ o.on_tail("-h", "--help", "Show this help message.") do
85
+ $stderr.puts o
86
+ exit
87
+ end
88
+ end.parse!
89
+
90
+ case (OPTIONS[:mode])
91
+ when :duplicates
92
+ options = OPTIONS.dup
93
+
94
+ include Fingerprint
95
+
96
+ duplicates_recordset = RecordSet.new
97
+ results = RecordSetPrinter.new(duplicates_recordset, OPTIONS[:output])
98
+
99
+ master_file_path = ARGV.shift
100
+ File.open(master_file_path) do |master_file|
101
+ master_recordset = RecordSet.new
102
+ master_recordset.parse(master_file)
103
+
104
+ ignore_similar = false
105
+
106
+ copy_file_paths = ARGV
107
+ if copy_file_paths.size == 0
108
+ copy_file_paths = [master_file_path]
109
+ ignore_similar = true
110
+ end
111
+
112
+ copy_file_paths.each do |copy_file_path|
113
+ File.open(copy_file_path) do |copy_file|
114
+ copy_recordset = RecordSet.new
115
+ copy_recordset.parse(copy_file)
116
+
117
+ copy_recordset.records.each do |record|
118
+ record.metadata['fingerprint'] = copy_file_path
119
+ # We need to see if the record exists in the master
120
+
121
+ if OPTIONS[:verbose]
122
+ $stderr.puts "Checking #{record.inspect}"
123
+ end
124
+
125
+ main_record = master_recordset.find_by_key(record)
126
+
127
+ # If we are scanning the same index, don't print out every file, just those that are duplicates within the single file.
128
+ if ignore_similar && main_record && (main_record.path == record.path)
129
+ main_record = nil
130
+ end
131
+
132
+ if main_record
133
+ record.metadata['original.path'] = main_record.path
134
+ record.metadata['original.fingerprint'] = master_file_path
135
+ results << record if !OPTIONS[:inverse]
136
+ else
137
+ results << record if OPTIONS[:inverse]
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ else
144
+ puts $options
145
+ end
@@ -0,0 +1,27 @@
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'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fingerprint"
8
+ spec.version = Fingerprint::VERSION
9
+ spec.authors = ["Samuel Williams"]
10
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
11
+ spec.description = <<-EOF
12
+ Fingerprint is a general purpose data integrity tool that uses cryptographic hashes to detect changes in files and directory trees. The fingerprint command scans a directory tree and generates a fingerprint file containing the names and cryptographic hashes of the files in the tree. This snapshot can be later used to generate a list of files that have been created, deleted or modified. If so much as a single bit in the file data has changed, Fingerprint will detect it.
13
+ EOF
14
+ spec.summary = "Fingerprint is a tool for creating checksums of entire directory structures, and comparing them for inconsistencies."
15
+ spec.homepage = "http://www.codeotaku.com/projects/fingerprint"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+
26
+ spec.add_dependency "lockfile"
27
+ end
@@ -18,6 +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
22
  require 'fingerprint/version'
22
23
  require 'fingerprint/scanner'
23
24
  require 'fingerprint/checker'
@@ -28,8 +29,8 @@ module Fingerprint
28
29
  master = Scanner.new([master_path])
29
30
  copy = Scanner.new([copy_path])
30
31
 
31
- master_recordset = Recordset.new
32
- copy_recordset = SparseRecordset.new(copy)
32
+ master_recordset = RecordSet.new
33
+ copy_recordset = SparseRecordSet.new(copy)
33
34
 
34
35
  master.scan(master_recordset)
35
36
 
@@ -45,7 +45,6 @@ module Fingerprint
45
45
  def check (&block)
46
46
  # For every file in the src, we check that it exists
47
47
  # in the destination:
48
-
49
48
  total_count = @master.records.count
50
49
  processed_size = 0
51
50
  total_size = @master.records.inject(0) { |count, record| count + (record['file.size'] || 0).to_i }
@@ -97,14 +96,14 @@ module Fingerprint
97
96
  attr :failures
98
97
 
99
98
  def self.check_files(master, copy, options = {}, &block)
100
- # New API that takes two Recordsets...
99
+ # New API that takes two RecordSets...
101
100
 
102
101
  File.open(master) do |master_file|
103
102
  File.open(copy) do |copy_file|
104
- master_recordset = Recordset.new
103
+ master_recordset = RecordSet.new
105
104
  master_recordset.parse(master_file)
106
105
 
107
- copy_recordset = Recordset.new
106
+ copy_recordset = RecordSet.new
108
107
  copy_recordset.parse(copy_file)
109
108
 
110
109
  verify(master_recordset, copy_recordset, options, &block)
@@ -116,9 +115,9 @@ module Fingerprint
116
115
  def self.verify(master, copy, options = {}, &block)
117
116
  error_count = 0
118
117
 
119
- errors = options.delete(:recordset) || Recordset.new
118
+ errors = options.delete(:recordset) || RecordSet.new
120
119
  if options[:output]
121
- errors = RecordsetPrinter.new(errors, options[:output])
120
+ errors = RecordSetPrinter.new(errors, options[:output])
122
121
  end
123
122
 
124
123
  checker = Checker.new(master, copy, options)
@@ -83,12 +83,12 @@ module Fingerprint
83
83
  end
84
84
  end
85
85
 
86
- class Recordset
86
+ class RecordSet
87
87
  def initialize
88
88
  @records = []
89
89
  @paths = {}
90
90
  @keys = {}
91
-
91
+
92
92
  @configuration = nil
93
93
 
94
94
  @callback = nil
@@ -107,8 +107,10 @@ module Fingerprint
107
107
  @configuration = record
108
108
  else
109
109
  @paths[record.path] = record
110
- record.keys.each do |key, value|
111
- @keys[key] = value
110
+ record.keys.each do |key|
111
+ @keys[key] ||= {}
112
+
113
+ @keys[key][record[key]] = record
112
114
  end
113
115
  end
114
116
  end
@@ -117,12 +119,10 @@ module Fingerprint
117
119
  return @paths[path]
118
120
  end
119
121
 
120
- def find(record)
121
- result = lookup(record.path)
122
-
123
- return result if result
124
-
125
- @record.keys.each do |key, value|
122
+ def find_by_key(record)
123
+ record.keys.each do |key|
124
+ value = record[key]
125
+
126
126
  result = @keys[key][value]
127
127
 
128
128
  return result if result
@@ -131,6 +131,14 @@ module Fingerprint
131
131
  return nil
132
132
  end
133
133
 
134
+ def find(record)
135
+ result = lookup(record.path)
136
+
137
+ return result if result
138
+
139
+ return find_by_key(record)
140
+ end
141
+
134
142
  def compare(other)
135
143
  main = lookup(other.path)
136
144
 
@@ -218,7 +226,7 @@ module Fingerprint
218
226
  end
219
227
 
220
228
  # This record set dynamically computes data from the disk as required.
221
- class SparseRecordset < Recordset
229
+ class SparseRecordSet < RecordSet
222
230
  def initialize(scanner)
223
231
  super()
224
232
 
@@ -234,7 +242,7 @@ module Fingerprint
234
242
  end
235
243
  end
236
244
 
237
- class RecordsetWrapper
245
+ class RecordSetWrapper
238
246
  def initialize(recordset)
239
247
  @recordset = recordset
240
248
  end
@@ -248,7 +256,7 @@ module Fingerprint
248
256
  end
249
257
  end
250
258
 
251
- class RecordsetPrinter < RecordsetWrapper
259
+ class RecordSetPrinter < RecordSetWrapper
252
260
  def initialize(recordset, output)
253
261
  super(recordset)
254
262
  @output = output
@@ -256,7 +264,7 @@ module Fingerprint
256
264
 
257
265
  def <<(record)
258
266
  record.write(@output)
259
- @recordset << record
267
+ @recordset << record if @recordset
260
268
  end
261
269
  end
262
270
  end
@@ -71,7 +71,7 @@ module Fingerprint
71
71
  'options.extended' => @options[:extended] == true,
72
72
  'options.checksums' => @options[:checksums].join(', '),
73
73
  'summary.time.start' => Time.now,
74
- 'fingerprint.version' => Fingerprint::VERSION::STRING
74
+ 'fingerprint.version' => Fingerprint::VERSION
75
75
  })
76
76
  end
77
77
 
@@ -282,7 +282,13 @@ module Fingerprint
282
282
  # A helper function to scan a set of directories.
283
283
  def self.scan_paths(paths, options = {})
284
284
  if options[:output]
285
- options[:recordset] = RecordsetPrinter.new(Recordset.new, options[:output])
285
+ if options.key? :recordset
286
+ recordset = options[:recordset]
287
+ else
288
+ recordset = RecordSet.new
289
+ end
290
+
291
+ options[:recordset] = RecordSetPrinter.new(recordset, options[:output])
286
292
  end
287
293
 
288
294
  scanner = Scanner.new(paths, options)
@@ -20,11 +20,5 @@
20
20
 
21
21
 
22
22
  module Fingerprint
23
- module VERSION
24
- MAJOR = 1
25
- MINOR = 3
26
- TINY = 3
27
-
28
- STRING = [MAJOR, MINOR, TINY].join('.')
29
- end
23
+ VERSION = "1.4.0"
30
24
  end
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2007, 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'rubygems'
24
+
25
+ require 'test/unit'
26
+ require 'fileutils'
27
+ require 'pathname'
28
+ require 'fingerprint'
29
+
30
+ require 'timeout'
31
+
32
+ class TestFingerprint < Test::Unit::TestCase
33
+ def test_analyze_verify
34
+ File.open("junk.txt", "w") { |fp| fp.write("foobar") }
35
+
36
+ result = system("fingerprint --analyze ./ -f")
37
+
38
+ File.open("junk.txt", "w") { |fp| fp.write("foobar") }
39
+
40
+ result = system("fingerprint --verify ./")
41
+
42
+ assert_equal true, result
43
+
44
+ File.open("junk.txt", "w") { |fp| fp.write("foobaz") }
45
+
46
+ result = system("fingerprint -X --verify ./")
47
+
48
+ assert_equal false, result
49
+ end
50
+
51
+ def test_check_paths
52
+ errors = 0
53
+ test_path = File.dirname(__FILE__)
54
+
55
+ Fingerprint::check_paths(test_path, test_path) do |record, result, message|
56
+ errors += 1
57
+ end
58
+
59
+ assert_equal errors, 0
60
+ end
61
+ end
metadata CHANGED
@@ -1,84 +1,107 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: fingerprint
3
- version: !ruby/object:Gem::Version
4
- hash: 29
5
- prerelease:
6
- segments:
7
- - 1
8
- - 3
9
- - 3
10
- version: 1.3.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Samuel Williams
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2011-10-06 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: lockfile
11
+ date: 2013-09-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
22
35
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: lockfile
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
32
48
  type: :runtime
33
- version_requirements: *id001
34
- description:
35
- email: samuel@oriontransfer.org
36
- executables:
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: "\t\tFingerprint is a general purpose data integrity tool that uses cryptographic
56
+ hashes to detect changes in files and directory trees. The fingerprint command scans
57
+ a directory tree and generates a fingerprint file containing the names and cryptographic
58
+ hashes of the files in the tree. This snapshot can be later used to generate a list
59
+ of files that have been created, deleted or modified. If so much as a single bit
60
+ in the file data has changed, Fingerprint will detect it.\n"
61
+ email:
62
+ - samuel.williams@oriontransfer.co.nz
63
+ executables:
37
64
  - fingerprint
65
+ - fingerprint-diff
38
66
  extensions: []
39
-
40
67
  extra_rdoc_files: []
41
-
42
- files:
68
+ files:
69
+ - Gemfile
70
+ - README.md
43
71
  - bin/fingerprint
72
+ - bin/fingerprint-diff
73
+ - fingerprint.gemspec
74
+ - lib/fingerprint.rb
44
75
  - lib/fingerprint/checker.rb
45
76
  - lib/fingerprint/record.rb
46
77
  - lib/fingerprint/scanner.rb
47
78
  - lib/fingerprint/version.rb
48
- - lib/fingerprint.rb
49
- - README.md
50
- homepage: http://www.oriontransfer.co.nz/projects/admin-toolbox/fingerprint
51
- licenses: []
52
-
79
+ - rakefile.rb
80
+ - test/test_fingerprint.rb
81
+ homepage: http://www.codeotaku.com/projects/fingerprint
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
53
85
  post_install_message:
54
86
  rdoc_options: []
55
-
56
- require_paths:
87
+ require_paths:
57
88
  - lib
58
- required_ruby_version: !ruby/object:Gem::Requirement
59
- none: false
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- hash: 3
64
- segments:
65
- - 0
66
- version: "0"
67
- required_rubygems_version: !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
- version: "0"
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
76
99
  requirements: []
77
-
78
100
  rubyforge_project:
79
- rubygems_version: 1.8.7
101
+ rubygems_version: 2.0.6
80
102
  signing_key:
81
- specification_version: 3
82
- summary: Fingerprint is a tool for creating checksums of entire directory structures, and comparing them for inconsistencies.
83
- test_files: []
84
-
103
+ specification_version: 4
104
+ summary: Fingerprint is a tool for creating checksums of entire directory structures,
105
+ and comparing them for inconsistencies.
106
+ test_files:
107
+ - test/test_fingerprint.rb