fingerprint 1.4.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.travis.yml +23 -0
- data/GUIDE.md +233 -0
- data/Gemfile +1 -1
- data/README.md +113 -18
- data/Rakefile +6 -0
- data/bin/fingerprint +6 -197
- data/fingerprint.gemspec +8 -7
- data/lib/fingerprint.rb +16 -3
- data/lib/fingerprint/checker.rb +7 -7
- data/lib/fingerprint/checksums.rb +33 -0
- data/lib/fingerprint/command.rb +90 -0
- data/lib/fingerprint/command/analyze.rb +74 -0
- data/lib/fingerprint/command/compare.rb +55 -0
- data/lib/fingerprint/command/duplicates.rb +97 -0
- data/lib/fingerprint/command/scan.rb +61 -0
- data/lib/fingerprint/command/verify.rb +86 -0
- data/lib/fingerprint/find.rb +40 -0
- data/lib/fingerprint/record.rb +20 -1
- data/lib/fingerprint/scanner.rb +134 -91
- data/lib/fingerprint/version.rb +2 -3
- data/spec/fingerprint/command/analyze_spec.rb +48 -0
- data/spec/fingerprint/command/duplicates_spec.rb +53 -0
- data/spec/fingerprint/command/source_fingerprint.rb +32 -0
- data/spec/fingerprint/command/verify_spec.rb +39 -0
- data/spec/fingerprint/corpus/README.md +3 -0
- data/spec/fingerprint/scanner_spec.rb +67 -0
- data/{test/test_fingerprint.rb → spec/fingerprint_spec.rb} +8 -36
- data/spec/spec_helper.rb +31 -0
- metadata +88 -23
- data/bin/fingerprint-diff +0 -145
- data/rakefile.rb +0 -9
@@ -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,97 @@
|
|
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."
|
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
|
+
if copy_file_paths.size == 0
|
59
|
+
copy_file_paths = [master_file_path]
|
60
|
+
ignore_similar = true
|
61
|
+
end
|
62
|
+
|
63
|
+
copy_file_paths.each do |copy_file_path|
|
64
|
+
File.open(copy_file_path) do |copy_file|
|
65
|
+
copy_recordset = RecordSet.new
|
66
|
+
copy_recordset.parse(copy_file)
|
67
|
+
|
68
|
+
copy_recordset.records.each do |record|
|
69
|
+
record.metadata['fingerprint'] = copy_file_path
|
70
|
+
# We need to see if the record exists in the master
|
71
|
+
|
72
|
+
if @options[:verbose]
|
73
|
+
$stderr.puts "Checking #{record.inspect}"
|
74
|
+
end
|
75
|
+
|
76
|
+
main_record = master_recordset.find_by_key(record)
|
77
|
+
|
78
|
+
# If we are scanning the same index, don't print out every file, just those that are duplicates within the single file.
|
79
|
+
if ignore_similar && main_record && (main_record.path == record.path)
|
80
|
+
main_record = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
if main_record
|
84
|
+
record.metadata['original.path'] = main_record.path
|
85
|
+
record.metadata['original.fingerprint'] = master_file_path
|
86
|
+
results << record if !@options[:inverse]
|
87
|
+
else
|
88
|
+
results << record if @options[:inverse]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
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
|
@@ -0,0 +1,86 @@
|
|
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 '../checker'
|
28
|
+
require_relative '../record'
|
29
|
+
|
30
|
+
module Fingerprint
|
31
|
+
module Command
|
32
|
+
class Verify < Samovar::Command
|
33
|
+
self.description = "Check an existing fingerprint against the filesystem."
|
34
|
+
|
35
|
+
options do
|
36
|
+
option "-n/--name <name>", "The fingerprint file name.", default: INDEX_FINGERPRINT
|
37
|
+
|
38
|
+
option "-f/--force", "Force all operations to complete despite warnings."
|
39
|
+
option "-x/--extended", "Include extended information about files and directories."
|
40
|
+
|
41
|
+
option "-s/--checksums <SHA2.256>", "Specify what checksum algorithms to use (#{Fingerprint::CHECKSUMS.keys.join(', ')}).", default: Fingerprint::DEFAULT_CHECKSUMS
|
42
|
+
|
43
|
+
option "--progress", "Print structured progress to standard error."
|
44
|
+
option "--verbose", "Verbose fingerprint output, e.g. excluded paths."
|
45
|
+
|
46
|
+
option "--fail-on-errors", "Exit with non-zero status if errors are encountered."
|
47
|
+
end
|
48
|
+
|
49
|
+
many :paths, "Paths relative to the root to use for verification, or ./ if not specified.", default: ["./"]
|
50
|
+
|
51
|
+
attr :error_count
|
52
|
+
|
53
|
+
def call
|
54
|
+
input_file = @options[:name]
|
55
|
+
|
56
|
+
unless File.exist? input_file
|
57
|
+
abort "Can't find index #{input_file}. Aborting."
|
58
|
+
end
|
59
|
+
|
60
|
+
options = @options.dup
|
61
|
+
options[:output] = @parent.output
|
62
|
+
|
63
|
+
master = RecordSet.new
|
64
|
+
|
65
|
+
File.open(input_file, "r") do |io|
|
66
|
+
master.parse(io)
|
67
|
+
end
|
68
|
+
|
69
|
+
if master.configuration
|
70
|
+
options.merge!(master.configuration.options)
|
71
|
+
end
|
72
|
+
|
73
|
+
scanner = Scanner.new(@paths, options)
|
74
|
+
|
75
|
+
# We use a sparse record set here, so we can't check for additions.
|
76
|
+
copy = SparseRecordSet.new(scanner)
|
77
|
+
|
78
|
+
@error_count = Checker.verify(master, copy, **options)
|
79
|
+
|
80
|
+
if @options[:fail_on_errors]
|
81
|
+
abort "Data inconsistent, #{error_count} error(s) found!" if error_count != 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
+
require 'find'
|
22
|
+
require 'build/files/path'
|
23
|
+
require 'build/files/system'
|
24
|
+
|
25
|
+
module Fingerprint
|
26
|
+
module Find
|
27
|
+
def self.find(root)
|
28
|
+
# Ensure root is a directory:
|
29
|
+
root += File::SEPARATOR unless root.end_with?(File::SEPARATOR)
|
30
|
+
|
31
|
+
::Find.find(root) do |path|
|
32
|
+
yield Build::Files::Path.new(path, root)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.prune
|
37
|
+
::Find.prune
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/fingerprint/record.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright
|
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,6 +25,7 @@ module Fingerprint
|
|
25
25
|
MODES = {
|
26
26
|
:configuration => 'C',
|
27
27
|
:file => 'F',
|
28
|
+
:link => 'L',
|
28
29
|
:directory => 'D',
|
29
30
|
:summary => 'S',
|
30
31
|
:warning => 'W',
|
@@ -84,6 +85,16 @@ module Fingerprint
|
|
84
85
|
end
|
85
86
|
|
86
87
|
class RecordSet
|
88
|
+
def self.load_file(path)
|
89
|
+
File.open(path, "r") do |io|
|
90
|
+
self.load(io)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.load(io)
|
95
|
+
self.new.tap{|record_set| record_set.parse(io)}
|
96
|
+
end
|
97
|
+
|
87
98
|
def initialize
|
88
99
|
@records = []
|
89
100
|
@paths = {}
|
@@ -115,6 +126,14 @@ module Fingerprint
|
|
115
126
|
end
|
116
127
|
end
|
117
128
|
|
129
|
+
def include?(path)
|
130
|
+
@paths.include?(path)
|
131
|
+
end
|
132
|
+
|
133
|
+
def empty?
|
134
|
+
@paths.empty?
|
135
|
+
end
|
136
|
+
|
118
137
|
def lookup(path)
|
119
138
|
return @paths[path]
|
120
139
|
end
|