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