Class: Fingerprint::Checker

Inherits:
Object
  • Object
show all
Defined in:
lib/fingerprint/checker.rb

Overview

Given two fingerprints (master and copy) ensures that the copy has at least everything contained in master: For every file in the master, a corresponding file must exist in the copy. This means that there may be extraneous files in the copy, but ensures that every file in the master has been replicated accurately.

At this time, this implementation may require a large amount of memory, proportional to the number of files being checked.

Master and copy are IO objects corresponding to the output produced by Fingerprint::Scanner.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(master, copy, **options) ⇒ Checker

Returns a new instance of Checker.



34
35
36
37
38
39
# File 'lib/fingerprint/checker.rb', line 34

def initialize(master, copy, **options)
	@master = master
	@copy = copy
	
	@options = options
end

Instance Attribute Details

#copyObject (readonly)

Returns the value of attribute copy.



42
43
44
# File 'lib/fingerprint/checker.rb', line 42

def copy
  @copy
end

#failuresObject (readonly)

A list of files which either did not exist in the copy, or had the wrong checksum.



96
97
98
# File 'lib/fingerprint/checker.rb', line 96

def failures
  @failures
end

#masterObject (readonly)

Returns the value of attribute master.



41
42
43
# File 'lib/fingerprint/checker.rb', line 41

def master
  @master
end

Class Method Details

.check_files(master, copy, **options, &block) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/fingerprint/checker.rb', line 98

def self.check_files(master, copy, **options, &block)
	# New API that takes two RecordSets...
	
	File.open(master) do |master_file|
		File.open(copy) do |copy_file|
			master_recordset = RecordSet.new
			master_recordset.parse(master_file)
			
			copy_recordset = RecordSet.new
			copy_recordset.parse(copy_file)

			verify(master_recordset, copy_recordset, **options, &block)
		end
	end
end

.verify(master, copy, **options, &block) ⇒ Object

Helper function to check two fingerprint files.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/fingerprint/checker.rb', line 115

def self.verify(master, copy, **options, &block)
	error_count = 0 

	errors = options.delete(:recordset) || RecordSet.new
	if options[:output]
		errors = RecordSetPrinter.new(errors, options[:output])
	end

	checker = Checker.new(master, copy, **options)

	checker.check do |record, result, message|
		error_count += 1

		 = {
			'error.code' => result,
			'error.message' => message
		}

		if result == :addition
			.merge!(record.)
			
			errors << Record.new(:warning, record.path, )
		elsif (copy = checker.copy.paths[record.path])
			changes = record.diff(copy)

			changes.each do |name|
				["changes.#{name}.old"] = record[name]
				["changes.#{name}.new"] = copy[name]
			end

			errors << Record.new(:warning, record.path, )
		else
			errors << Record.new(:warning, record.path, )
		end
	end

	if error_count
		summary_message = "#{error_count} error(s) detected."
	else
		summary_message = "No errors detected"
	end

	errors << Record.new(:summary, summary_message, {
		'error.count' => error_count
	})

	return error_count
end

Instance Method Details

#check(&block) ⇒ Object

Run the checking process.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/fingerprint/checker.rb', line 45

def check(&block)
	# For every file in the src, we check that it exists
	# in the destination:
	total_count = @master.records.count
	processed_size = 0
	total_size = @master.records.inject(0) { |count, record| count + (record['file.size'] || 0).to_i }
	
	if @options[:additions]
		copy_paths = @copy.paths.dup
	else
		copy_paths = {}
	end
	
	@master.records.each_with_index do |record, processed_count|
		copy_paths.delete(record.path)

		if @options[:progress]
			$stderr.puts "# Checking: #{record.path}"
		end

		next if record.mode != :file

		result, message = @copy.compare(record)
		if result != :valid
			yield record, result, message
		elsif @options[:extended]
			# Extended check compares other attributes such as user, group, file modes.
			changes = record.diff(copy.paths[record.path])
			
			if changes.size > 0
				yield record, :attribute_changed, "Attribute(s) #{changes.join(', ')} changed"
			end
		end
		
		if @options[:progress]
			$stderr.puts "# Progress: File #{processed_count} / #{total_count}; Byte #{processed_size} / #{total_size} = #{sprintf('%0.2f%', processed_size.to_f / total_size.to_f * 100.0)}"

			processed_size += (record['file.size'] || 0).to_i
		end
	end
	
	if @options[:additions]
		copy_paths.each do |path, record|
			next unless record.mode == :file || record.mode == :directory
			
			yield record, :addition, "File added"
		end
	end
end