fingerprint 1.3.0 → 1.3.1
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.
- data/README.md +2 -1
- data/bin/fingerprint +58 -12
- data/lib/fingerprint/record.rb +1 -1
- data/lib/fingerprint/scanner.rb +30 -7
- data/lib/fingerprint/version.rb +1 -1
- metadata +19 -6
data/README.md
CHANGED
@@ -26,6 +26,7 @@ Todo
|
|
26
26
|
* Supporting tools for signing fingerprints easily.
|
27
27
|
* Support indexing specific files as well as whole directories (maybe?).
|
28
28
|
* 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
|
+
* 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.
|
29
30
|
|
30
31
|
License
|
31
32
|
-------
|
@@ -48,4 +49,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
48
49
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
49
50
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
50
51
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
51
|
-
THE SOFTWARE.
|
52
|
+
THE SOFTWARE.
|
data/bin/fingerprint
CHANGED
@@ -23,6 +23,8 @@
|
|
23
23
|
require 'optparse'
|
24
24
|
require 'pathname'
|
25
25
|
require 'fingerprint'
|
26
|
+
require 'lockfile'
|
27
|
+
require 'fileutils'
|
26
28
|
|
27
29
|
OPTIONS = {
|
28
30
|
:root => "./",
|
@@ -30,9 +32,10 @@ OPTIONS = {
|
|
30
32
|
:output => $stdout,
|
31
33
|
:verbose => false,
|
32
34
|
:force => false,
|
33
|
-
:name => ".
|
35
|
+
:name => "index.fingerprint",
|
34
36
|
:extended => false,
|
35
37
|
:checksums => Fingerprint::DEFAULT_CHECKSUMS,
|
38
|
+
:lockfile => true
|
36
39
|
}
|
37
40
|
|
38
41
|
ARGV.options do |o|
|
@@ -80,6 +83,10 @@ ARGV.options do |o|
|
|
80
83
|
o.on("--progress", "Print percentage progress to standard error.") do
|
81
84
|
OPTIONS[:progress] = true
|
82
85
|
end
|
86
|
+
|
87
|
+
o.on("--no-lockfile", "Don't use a lockfile to validate access to the fingerprint.") do
|
88
|
+
OPTIONS[:lockfile] = false
|
89
|
+
end
|
83
90
|
|
84
91
|
o.separator ""
|
85
92
|
|
@@ -116,22 +123,61 @@ if OPTIONS[:checksums].size == 0
|
|
116
123
|
OPTIONS[:checksums] = ['MD5', 'SHA2.256']
|
117
124
|
end
|
118
125
|
|
126
|
+
# Run some block with the given lock, if requested.
|
127
|
+
def with_lock
|
128
|
+
lockfile_path = nil
|
129
|
+
if OPTIONS[:lockfile] == true
|
130
|
+
lockfile_path = Pathname.new(OPTIONS[:root]) + (OPTIONS[:name] + ".lock")
|
131
|
+
elsif OPTION[:lockfile] != false
|
132
|
+
lockfile_path = OPTIONS[:lockfile]
|
133
|
+
end
|
134
|
+
|
135
|
+
if lockfile_path
|
136
|
+
begin
|
137
|
+
Lockfile.new(lockfile_path, :retries => 0) do
|
138
|
+
yield
|
139
|
+
end
|
140
|
+
rescue Lockfile::MaxTriesLockError
|
141
|
+
$stderr.puts "Could not acquire lock #{lockfile_path}."
|
142
|
+
|
143
|
+
return false
|
144
|
+
end
|
145
|
+
else
|
146
|
+
yield
|
147
|
+
end
|
148
|
+
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
|
119
152
|
case (OPTIONS[:mode])
|
120
153
|
when :analyze
|
121
|
-
|
122
|
-
|
123
|
-
if output_file.exist? && !OPTIONS[:force]
|
124
|
-
$stderr.puts "Output file #{output_file} already exists. Aborting."
|
125
|
-
exit(2)
|
126
|
-
end
|
154
|
+
result = with_lock do
|
155
|
+
output_file = Pathname.new(OPTIONS[:root]) + OPTIONS[:name]
|
127
156
|
|
128
|
-
|
129
|
-
|
157
|
+
if output_file.exist? && !OPTIONS[:force]
|
158
|
+
$stderr.puts "Output file #{output_file} already exists. Aborting."
|
159
|
+
exit(2)
|
160
|
+
end
|
130
161
|
|
131
|
-
|
132
|
-
options[:
|
162
|
+
options = OPTIONS.dup
|
163
|
+
options[:excludes] = [OPTIONS[:name]]
|
133
164
|
|
134
|
-
|
165
|
+
finished = false
|
166
|
+
begin
|
167
|
+
File.open(output_file, "w") do |io|
|
168
|
+
options[:output] = io
|
169
|
+
|
170
|
+
Fingerprint::Scanner.scan_paths([OPTIONS[:root]], options)
|
171
|
+
end
|
172
|
+
finished = true
|
173
|
+
ensure
|
174
|
+
FileUtils.rm(output_file) unless finished
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
unless result
|
179
|
+
# Lockfile failure
|
180
|
+
exit(4)
|
135
181
|
end
|
136
182
|
when :verify
|
137
183
|
error_count = 0
|
data/lib/fingerprint/record.rb
CHANGED
data/lib/fingerprint/scanner.rb
CHANGED
@@ -46,7 +46,9 @@ module Fingerprint
|
|
46
46
|
@options = options
|
47
47
|
|
48
48
|
@digests = {}
|
49
|
-
|
49
|
+
|
50
|
+
@progress = nil
|
51
|
+
|
50
52
|
unless @options[:checksums] and @options[:checksums].size > 0
|
51
53
|
@options[:checksums] = DEFAULT_CHECKSUMS
|
52
54
|
end
|
@@ -75,6 +77,8 @@ module Fingerprint
|
|
75
77
|
|
76
78
|
# This code won't handle multiple threads..
|
77
79
|
def digests_for(path)
|
80
|
+
total = 0
|
81
|
+
|
78
82
|
@digests.each do |key, digest|
|
79
83
|
digest.reset
|
80
84
|
end
|
@@ -82,6 +86,10 @@ module Fingerprint
|
|
82
86
|
File.open(path, "rb") do |file|
|
83
87
|
buf = ""
|
84
88
|
while file.read(1024 * 1024 * 10, buf)
|
89
|
+
total += buf.size
|
90
|
+
|
91
|
+
@progress.call(total) if @progress
|
92
|
+
|
85
93
|
@digests.each do |key, digest|
|
86
94
|
digest << buf
|
87
95
|
end
|
@@ -104,6 +112,7 @@ module Fingerprint
|
|
104
112
|
if type == :file
|
105
113
|
metadata['file.size'] = stat.size
|
106
114
|
digests = digests_for(path)
|
115
|
+
metadata.merge!(digests)
|
107
116
|
end
|
108
117
|
|
109
118
|
# Extended information
|
@@ -129,7 +138,9 @@ module Fingerprint
|
|
129
138
|
# Output a file and associated metadata.
|
130
139
|
def file_record_for(path)
|
131
140
|
metadata = metadata_for(:file, path)
|
132
|
-
|
141
|
+
|
142
|
+
# Should this be here or in metadata_for?
|
143
|
+
# metadata.merge!(digests_for(path))
|
133
144
|
|
134
145
|
Record.new(:file, path, metadata)
|
135
146
|
end
|
@@ -183,6 +194,10 @@ module Fingerprint
|
|
183
194
|
@roots.each do |root|
|
184
195
|
Dir.chdir(root) do
|
185
196
|
Find.find("./") do |path|
|
197
|
+
if @options[:progress]
|
198
|
+
$stderr.puts "# Scanning: #{path}"
|
199
|
+
end
|
200
|
+
|
186
201
|
if File.directory?(path)
|
187
202
|
if excluded?(path)
|
188
203
|
Find.prune # Ignore this directory
|
@@ -199,11 +214,21 @@ module Fingerprint
|
|
199
214
|
end
|
200
215
|
end
|
201
216
|
|
217
|
+
if @options[:progress]
|
218
|
+
@progress = lambda do |read_size|
|
219
|
+
$stderr.puts "# Progress: File #{processed_count} / #{total_count}; Byte #{processed_size + read_size} / #{total_size} = #{sprintf('%0.3f%', (processed_size + read_size).to_f / total_size.to_f * 100.0)} (#{read_size}, #{processed_size}, #{total_size})"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
202
223
|
@roots.each do |root|
|
203
224
|
Dir.chdir(root) do
|
204
225
|
recordset << header_for(root)
|
205
226
|
|
206
227
|
Find.find("./") do |path|
|
228
|
+
if @options[:progress]
|
229
|
+
$stderr.puts "# Path: #{path}"
|
230
|
+
end
|
231
|
+
|
207
232
|
if File.directory?(path)
|
208
233
|
if excluded?(path)
|
209
234
|
excluded_count += 1
|
@@ -221,10 +246,10 @@ module Fingerprint
|
|
221
246
|
else
|
222
247
|
# Skip anything that isn't a valid file (e.g. pipes, sockets, symlinks).
|
223
248
|
if valid_file?(path)
|
249
|
+
recordset << file_record_for(path)
|
250
|
+
|
224
251
|
processed_count += 1
|
225
252
|
processed_size += File.size(path)
|
226
|
-
|
227
|
-
recordset << file_record_for(path)
|
228
253
|
else
|
229
254
|
excluded_count += 1
|
230
255
|
|
@@ -235,9 +260,7 @@ module Fingerprint
|
|
235
260
|
end
|
236
261
|
|
237
262
|
# Print out a progress summary if requested
|
238
|
-
if @
|
239
|
-
$stderr.puts "# Progress: File #{processed_count} / #{total_count} = #{sprintf('%0.2f%', processed_count.to_f / total_count.to_f * 100.0)}; Byte #{processed_size} / #{total_size} = #{sprintf('%0.2f%', processed_size.to_f / total_size.to_f * 100.0)}"
|
240
|
-
end
|
263
|
+
@progress.call(0) if @progress
|
241
264
|
end
|
242
265
|
end
|
243
266
|
end
|
data/lib/fingerprint/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fingerprint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 1
|
10
|
+
version: 1.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Samuel Williams
|
@@ -15,9 +15,22 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
dependencies:
|
20
|
-
|
18
|
+
date: 2011-10-05 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: lockfile
|
22
|
+
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"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
21
34
|
description:
|
22
35
|
email: samuel@oriontransfer.org
|
23
36
|
executables:
|