overrides_tracker 0.1.9 → 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,115 +1,353 @@
1
1
  class OverridesTracker::Comparer
2
2
  DO_BASE_DIR = File.join(Dir.pwd, "/overrides_tracker")
3
3
 
4
- def self.compare
5
- all_methods_collections = {}
6
- unified_methods_collections = {}
7
- report_files = Dir.entries(DO_BASE_DIR) - [".", ".."]
8
- report_files.each do |file_name|
9
- if file_name[-4..-1] == '.otf'
10
- all_methods_collections[file_name] = {}
11
- method_collection = OverridesTracker::MethodsCollector.instance.load_from_file(file_name)
12
- all_methods_collections[file_name] = method_collection
13
- unified_methods_collections = unified_methods_collections.deep_merge(method_collection)
14
- end
15
- end
16
-
4
+ def self.compare_builds(unified_methods_collections, all_methods_collections, working_directories, bundle_directories)
17
5
  same_source_count = 0
18
6
  errored_source_count = 0
19
7
  method_not_available_count = 0
20
8
  method_not_override_count = 0
21
9
  source_changed_count = 0
22
-
23
10
  methods_count = 0
24
11
  classes_count = 0
25
12
 
26
- unified_methods_collections.each do |unified_class_name, unified_class_hash|
13
+ results = []
14
+ added_method_results = []
27
15
 
28
- if unified_class_hash['instance_methods'].any? || unified_class_hash['singleton_methods'].any?
29
- classes_count +=1
30
- ['instance_methods', 'singleton_methods'].each do |method_type|
31
- unified_class_hash[method_type].each do |unified_method_name, unified_method_hash|
16
+ numbers = {}
17
+ numbers[:overrides] = {}
18
+ numbers[:overrides][:source_changed_count] = 0
19
+ numbers[:overrides][:override_changed_count] = 0
20
+ numbers[:overrides][:method_not_available_count] = 0
21
+ numbers[:overrides][:method_not_override_count] = 0
22
+ numbers[:overrides][:total] = 0
23
+
24
+ numbers[:added_methods] = {}
25
+ numbers[:added_methods][:source_changed_count] = 0
26
+ numbers[:added_methods][:override_changed_count] = 0
27
+ numbers[:added_methods][:method_not_available_count] = 0
28
+ numbers[:added_methods][:method_not_override_count] = 0
29
+ numbers[:added_methods][:total] = 0
30
+ numbers[:total] = {}
32
31
 
33
- methods_count += 1
34
- puts ""
35
- puts "==========================================================================================="
36
- puts ""
32
+
33
+ unified_methods_collections.each do |unified_class_name, unified_class_hash|
34
+ if unified_class_hash['instance_methods']&.any? || unified_class_hash['singleton_methods']&.any?
35
+ ['instance_methods', 'singleton_methods'].each do |method_type|
36
+ unified_class_hash[method_type]&.each do |unified_method_name, unified_method_hash|
37
37
  same_source_every_where = true
38
38
 
39
-
40
- all_methods_collections.each do |file_name, all_methods_hash|
41
- if all_methods_hash[unified_class_name].nil? || all_methods_hash[unified_class_name][method_type][unified_method_name].nil? || all_methods_hash[unified_class_name][method_type][unified_method_name]['sha'] != unified_method_hash['sha']
39
+ all_methods_collections.each do |build_id, all_methods_hash|
40
+ if all_methods_hash[unified_class_name].nil? ||
41
+ all_methods_hash[unified_class_name][method_type].nil? ||
42
+ all_methods_hash[unified_class_name][method_type][unified_method_name].nil? ||
43
+ all_methods_hash[unified_class_name][method_type][unified_method_name]['sha'] != unified_method_hash['sha'] ||
44
+ all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_sha'] != unified_method_hash['overriding_sha']
42
45
  same_source_every_where = false
43
46
  end
44
47
  end
45
48
 
49
+ method_result_hash = {class_name: unified_class_name, method_name: unified_method_name, builds: {}, method_type: method_type, changes_detected: false}
50
+
46
51
  if same_source_every_where
47
- puts "#{methods_count}) #{unified_class_name}##{unified_method_name}: No Changes".green.bold
48
- same_source_count += 1
52
+ results << method_result_hash
49
53
  else
50
- errored_output = nil
54
+ method_result_hash[:changes_detected] = true
55
+ method_result_hash[:builds] ||= {}
56
+
57
+ is_source_changed_flag = false
58
+ is_override_changed_flag = false
59
+ all_methods_collections.each do |build_id, all_methods_hash|
60
+
61
+ method_result_hash[:builds][build_id] ||= {}
62
+
63
+ if all_methods_hash[unified_class_name].nil?
51
64
 
52
- puts "#{methods_count}) #{unified_class_name}##{unified_method_name}: Changes between files".red.bold
65
+ method_result_hash[:builds][build_id] = {result: 'method_not_available'}
66
+ numbers[:overrides][:method_not_available_count] +=1
67
+
68
+ elsif all_methods_hash[unified_class_name][method_type].nil?
69
+ if all_methods_hash[unified_class_name]["added_#{method_type}"]
70
+ if all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name]
71
+ method_result_hash[:builds][build_id] = {result: 'method_not_override', data: all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name]}
72
+ numbers[:overrides][:method_not_override_count] +=1
73
+ end
74
+ end
75
+ elsif !all_methods_hash[unified_class_name][method_type][unified_method_name].nil?
76
+ if all_methods_hash[unified_class_name][method_type][unified_method_name]['sha'] != unified_method_hash['sha']
77
+ method_result_hash[:builds][build_id] = {result: 'source_has_changed'}
78
+ method_result_hash[:builds][build_id][:original_body] = all_methods_hash[unified_class_name][method_type][unified_method_name]['body']
79
+ method_result_hash[:builds][build_id][:original_sha] = all_methods_hash[unified_class_name][method_type][unified_method_name]['sha']
80
+ method_result_hash[:builds][build_id][:original_location] = all_methods_hash[unified_class_name][method_type][unified_method_name]['location']
81
+ method_result_hash[:builds][build_id][:overriding_body] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_body']
82
+ method_result_hash[:builds][build_id][:overriding_location] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_location']
83
+ method_result_hash[:builds][build_id][:overriding_sha] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_sha']
84
+ method_result_hash[:builds][build_id][:is_part_of_app] = all_methods_hash[unified_class_name][method_type][unified_method_name]['is_part_of_app'] || all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_is_part_of_app']
85
+ mask_path(method_result_hash[:builds][build_id], working_directories[build_id], bundle_directories[build_id])
86
+
87
+ numbers[:overrides][:source_changed_count] += 1
88
+ is_source_changed_flag = true
89
+ is_override_changed_flag = false
90
+ else
91
+ method_result_hash[:builds][build_id] = {result: 'override_has_changed'}
92
+ method_result_hash[:builds][build_id][:original_body] = all_methods_hash[unified_class_name][method_type][unified_method_name]['body']
93
+ method_result_hash[:builds][build_id][:original_sha] = all_methods_hash[unified_class_name][method_type][unified_method_name]['sha']
94
+ method_result_hash[:builds][build_id][:original_location] = all_methods_hash[unified_class_name][method_type][unified_method_name]['location']
95
+ method_result_hash[:builds][build_id][:overriding_body] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_body']
96
+ method_result_hash[:builds][build_id][:overriding_location] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_location']
97
+ method_result_hash[:builds][build_id][:overriding_sha] = all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_sha']
98
+ method_result_hash[:builds][build_id][:is_part_of_app] = all_methods_hash[unified_class_name][method_type][unified_method_name]['is_part_of_app'] || all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_is_part_of_app']
99
+
100
+ mask_path(method_result_hash[:builds][build_id], working_directories[build_id], bundle_directories[build_id])
101
+
102
+ numbers[:overrides][:override_changed_count] += 1
103
+ is_override_changed_flag = true
104
+ end
105
+ else
106
+ method_result_hash[:builds][build_id] = {result: 'method_not_available'}
107
+ numbers[:overrides][:method_not_available_count] +=1
108
+ end
109
+ end
110
+
111
+ if is_source_changed_flag
112
+ line_differerence_array = []
113
+ all_methods_collections.each do |build_id, all_methods_hash|
114
+ begin
115
+ line_differerence_array << method_result_hash[:builds][build_id][:original_body].split(/\n/)
116
+ rescue
117
+
118
+ end
119
+ if method_result_hash[:builds][build_id][:result] == 'override_has_changed'
120
+ numbers[:overrides][:override_changed_count] -= 1
121
+ numbers[:overrides][:source_changed_count] += 1
122
+ end
123
+ method_result_hash[:builds][build_id][:result] = 'source_has_changed'
124
+ end
125
+
126
+ max_length = line_differerence_array.map(&:length).max
127
+ transposed_array = line_differerence_array.map{|e| e.values_at(0...max_length)}.transpose
128
+ method_result_hash[:mark_lines] = transposed_array.map.with_index{|val, index| val.uniq.size > 1 ? index : nil}.compact
129
+ is_override_changed_flag = false
130
+ end
131
+
132
+ if is_override_changed_flag
133
+ line_differerence_array = []
134
+ begin
135
+ begin
136
+ all_methods_collections.each do |build_id, all_methods_hash|
137
+ line_differerence_array << method_result_hash[:builds][build_id][:overriding_body].split(/\n/)
138
+ end
139
+ rescue
140
+
141
+ end
142
+ max_length = line_differerence_array.map(&:length).max
143
+ transposed_array = line_differerence_array.map{|e| e.values_at(0...max_length)}.transpose
144
+ method_result_hash[:overriding_mark_lines] = transposed_array.map.with_index{|val, index| val.uniq.size > 1 ? index : nil}.compact
145
+ rescue => exception
146
+
147
+ end
148
+
149
+ end
150
+
151
+ method_result_hash[:is_part_of_app] = method_result_hash[:builds].select{|bu, bu_val| bu_val[:is_part_of_app] }.any?
152
+
153
+ results << method_result_hash
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+
160
+ if unified_class_hash['added_instance_methods']&.any? || unified_class_hash['added_singleton_methods']&.any?
161
+
162
+ ['added_instance_methods', 'added_singleton_methods'].each do |method_type|
163
+ unified_class_hash[method_type]&.each do |unified_method_name, unified_method_hash|
164
+
165
+ same_source_every_where = true
166
+
167
+ is_added_source_has_changed_flag = false
168
+
169
+ all_methods_collections.each do |build_id, all_methods_hash|
170
+ unless (all_methods_hash[unified_class_name] != nil) && (all_methods_hash[unified_class_name][method_type] != nil) && (all_methods_hash[unified_class_name][method_type][unified_method_name] != nil ) && (all_methods_hash[unified_class_name][method_type][unified_method_name]['sha'] == unified_method_hash['sha'])
171
+ same_source_every_where = false
172
+ end
173
+ end
174
+
175
+ method_result_hash = {class_name: unified_class_name, method_name: unified_method_name, builds: {}, method_type: method_type, changes_detected: false}
176
+
177
+ if same_source_every_where
178
+ added_method_results << method_result_hash
179
+ else
180
+ method_result_hash[:changes_detected] = true
181
+ method_result_hash[:builds] ||= {}
53
182
 
54
- all_methods_collections.each do |file_name, all_methods_hash|
55
- puts ""
56
- puts ("in: "+file_name).bold
183
+ all_methods_collections.each do |build_id, all_methods_hash|
184
+
185
+ method_result_hash[:builds][build_id] ||= {}
57
186
 
58
- if all_methods_hash[unified_class_name].nil?
59
- puts "#{unified_class_name}##{unified_method_name}: method is not in codebase"
60
- method_not_available_count +=1
187
+ if all_methods_hash[unified_class_name].nil?
188
+ method_result_hash[:builds][build_id] = {result: 'added_method_not_available'}
189
+ numbers[:added_methods][:method_not_available_count] +=1
190
+ elsif all_methods_hash[unified_class_name][method_type].nil?
191
+ method_result_hash[:builds][build_id] = {result: 'added_method_not_available'}
192
+ numbers[:added_methods][:method_not_available_count] +=1
61
193
  elsif !all_methods_hash[unified_class_name][method_type][unified_method_name].nil?
62
- puts "#{unified_class_name}##{unified_method_name}:"
63
- puts ""
64
- puts "Source:".bold
65
- puts "#{all_methods_hash[unified_class_name][method_type][unified_method_name]['body']}"
66
- puts ""
67
- puts "#{all_methods_hash[unified_class_name][method_type][unified_method_name]['location'][0]}:#{all_methods_hash[unified_class_name][method_type][unified_method_name]['location'][1]}".italic
68
-
69
- puts ""
70
- puts "Override:".bold
71
- puts "#{all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_body']}"
72
- puts ""
73
- puts "#{all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_location'][0]}:#{all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_location'][1]}".italic
74
-
75
- source_changed_count +=1
76
- elsif !all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name].nil?
77
- puts "#{unified_class_name}##{unified_method_name}: method is not an override"
78
- method_not_override_count +=1
79
-
80
- puts ""
81
- puts "Code:".bold
82
- puts "#{all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name]['body']}"
83
- puts ""
84
- # puts "#{all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name]['location'][0]}:#{all_methods_hash[unified_class_name][method_type][unified_method_name]['location'][1]}".italic
85
-
86
- elsif all_methods_hash[unified_class_name]["added_#{method_type}"][unified_method_name].nil?
87
- puts "#{unified_class_name}##{unified_method_name}: method is not in codebase"
88
- method_not_available_count +=1
194
+ method_result_hash[:builds][build_id] = {result: 'added_source_has_changed'}
195
+ method_result_hash[:builds][build_id][:original_body] = all_methods_hash[unified_class_name][method_type][unified_method_name]['body']
196
+ method_result_hash[:builds][build_id][:original_location] = all_methods_hash[unified_class_name][method_type][unified_method_name]['location']
197
+ method_result_hash[:builds][build_id][:is_part_of_app] = all_methods_hash[unified_class_name][method_type][unified_method_name]['is_part_of_app'] || all_methods_hash[unified_class_name][method_type][unified_method_name]['overriding_is_part_of_app']
198
+
199
+ mask_path(method_result_hash[:builds][build_id], working_directories[build_id], bundle_directories[build_id])
200
+
201
+ numbers[:added_methods][:source_changed_count] += 1
202
+ is_added_source_has_changed_flag = true
203
+ elsif all_methods_hash[unified_class_name][method_type][unified_method_name].nil?
204
+ method_result_hash[:builds][build_id] = {result: 'added_method_not_available'}
205
+ numbers[:added_methods][:method_not_available_count] +=1
89
206
  else
90
- puts "#{unified_class_name}##{unified_method_name}: #{all_methods_hash[unified_class_name][method_type][unified_method_name]}"
207
+ method_result_hash[:builds][build_id] = {result: 'error'}
91
208
  end
92
- puts ""
93
-
94
209
  end
95
- errored_source_count += 1
210
+
211
+ if is_added_source_has_changed_flag
212
+ begin
213
+
214
+ line_differerence_array = []
215
+ all_methods_collections.each do |build_id, all_methods_hash|
216
+ line_differerence_array << method_result_hash[:builds][build_id][:original_body].split(/\n/)
217
+ end
218
+
219
+ max_length = line_differerence_array.map(&:length).max
220
+ transposed_array = line_differerence_array.map{|e| e.values_at(0...max_length)}.transpose
221
+ method_result_hash[:mark_added_method_lines] = transposed_array.map.with_index{|val, index| val.uniq.size > 1 ? index : nil}.compact
222
+ rescue
223
+
224
+ end
225
+ end
226
+
227
+ method_result_hash[:is_part_of_app] = method_result_hash[:builds].select{|bu, bu_val| bu_val[:is_part_of_app] }.any?
228
+ added_method_results << method_result_hash
229
+
96
230
  end
97
231
  end
98
- end
232
+ end
233
+ end
234
+ end
235
+
236
+ numbers[:overrides][:total] = numbers[:overrides][:method_not_override_count] + numbers[:overrides][:method_not_available_count] + numbers[:overrides][:source_changed_count] + numbers[:overrides][:override_changed_count]
237
+ numbers[:added_methods][:total] = numbers[:added_methods][:method_not_available_count] + numbers[:added_methods][:source_changed_count]
238
+ numbers[:total] = numbers[:overrides][:total] + numbers[:added_methods][:total]
239
+
240
+ {results: {override_results: results, added_method_results: added_method_results}, numbers: numbers}
241
+ end
242
+
243
+ def self.mask_path(build_hash, working_directory, bundle_directory)
244
+ if build_hash[:original_location]
245
+ build_hash[:original_location][0].gsub!(working_directory, 'APP_PATH')
246
+ build_hash[:original_location][0].gsub!(bundle_directory, 'BUNDLE_PATH')
247
+ end
248
+
249
+ if build_hash[:overriding_location]
250
+ build_hash[:overriding_location][0].gsub!(working_directory, 'APP_PATH')
251
+ build_hash[:overriding_location][0].gsub!(bundle_directory, 'BUNDLE_PATH')
252
+ end
253
+ end
254
+
255
+ def self.compare
256
+ all_methods_collections = {}
257
+ unified_methods_collections = {}
258
+ working_directories = {}
259
+ bundle_directories = {}
260
+
261
+ all_methods_collections = {}
262
+ unified_methods_collections = {}
263
+ report_files = Dir.entries(DO_BASE_DIR) - [".", ".."]
264
+ report_files.each do |file_name|
265
+ if file_name[-4..-1] == '.otf'
266
+ all_methods_collections[file_name] = {}
267
+ result_file_data = OverridesTracker::MethodsCollector.instance.load_from_file(file_name)
268
+ result_file_data.deep_stringify_keys!
269
+ methods_collection = result_file_data['methods_collection']
270
+ all_methods_collections[file_name] = methods_collection
271
+ working_directories[file_name] = result_file_data['working_directory']
272
+ bundle_directories[file_name] = result_file_data['bundle_path']
273
+ unified_methods_collections = unified_methods_collections.deep_merge(methods_collection)
274
+ end
275
+ end
276
+
277
+ comparison = compare_builds(unified_methods_collections, all_methods_collections, working_directories, bundle_directories)
278
+ methods_count = 0
279
+
280
+ comparison[:results].each do |result_type, result_array|
281
+ result_array.each do |method_hash|
282
+ if method_hash[:builds] != {}
283
+ methods_count += 1
284
+ puts ""
285
+ puts "==========================================================================================="
286
+ puts ""
287
+ if result_type == :override_results
288
+ puts "#{methods_count}) Override: #{method_hash[:class_name]}##{method_hash[:method_name]}".bold
289
+ else
290
+ puts "#{methods_count}) Added Method: #{method_hash[:class_name]}##{method_hash[:method_name]}".bold
291
+ end
292
+
293
+ method_hash[:builds].each do |build_id, build_result|
294
+ puts ''
295
+ puts "..........................................................................................."
296
+ puts ''
297
+ puts build_id
298
+ if build_result[:result] == 'source_has_changed'
299
+ puts ""
300
+ elsif build_result[:result] == 'method_not_override'
301
+ puts "Method not override".italic.yellow
302
+ elsif build_result[:result] == 'method_not_available'
303
+ puts "Method not available".italic.yellow
304
+ elsif build_result[:result] == 'added_method_not_available'
305
+ puts "Added method not available".italic.yellow
306
+ elsif build_result[:result] == 'added_source_has_changed'
307
+ puts ''
308
+ end
309
+
310
+
311
+ unless build_result[:original_body].nil?
312
+ puts "-------------------------------------------------------------------------------------------".pink
313
+ puts ''
314
+ puts 'Original:'.italic
315
+ puts ''
316
+ puts "#{build_result[:original_body]}".pink
317
+ puts ''
318
+ puts "in #{build_result[:original_location][0]}:#{build_result[:original_location][1]}".italic
319
+ end
320
+ puts ''
321
+ puts ''
322
+ unless build_result[:overriding_body].nil?
323
+ puts "-------------------------------------------------------------------------------------------".blue
324
+ puts ''
325
+ puts 'Override:'.italic
326
+ puts ''
327
+ puts "#{build_result[:overriding_body]}".blue
328
+ puts ''
329
+ puts "in: #{build_result[:overriding_location][0]}:#{build_result[:overriding_location][1]}".italic
330
+ end
331
+
332
+ puts ''
333
+ puts ''
334
+ end
335
+ end
99
336
  end
100
337
  end
101
338
 
339
+
102
340
  puts ""
103
341
  puts "==========================================================================================="
104
342
  puts ""
105
343
  puts "Summary:".bold
106
- puts "Found #{methods_count} distinct overridden methods in #{classes_count} Files"
107
- puts "#{same_source_count} overridden methods have not changed"
108
- puts "#{errored_source_count} overridden methods have changed"
109
- puts "#{method_not_override_count} where method is not an override"
110
- puts "#{method_not_available_count} where method is not in codebase"
111
- source_changed_count = errored_source_count - method_not_available_count
112
- puts "#{source_changed_count} source method bodies have changed"
344
+ puts ""
345
+ puts "Investigated methods: #{comparison[:numbers][:total]/2}"
346
+ puts "Diffences on overrides: #{comparison[:numbers][:overrides][:total]/2}"
347
+ puts "Diffences on added methods: #{comparison[:numbers][:added_methods][:total]/2}"
348
+
349
+ comparison
113
350
  end
351
+
114
352
  end
115
353
 
@@ -7,4 +7,4 @@ module OverridesTracker::FileObserver
7
7
  end
8
8
  end
9
9
  end
10
- end
10
+ end
@@ -0,0 +1,41 @@
1
+ # Adding deep merge functionality
2
+ Hash.class_eval do
3
+ def deep_merge(other_hash, &block)
4
+ dup.deep_merge!(other_hash, &block)
5
+ end
6
+
7
+ def deep_merge!(other_hash, &block)
8
+ merge!(other_hash) do |key, this_val, other_val|
9
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
10
+ this_val.deep_merge(other_val, &block)
11
+ elsif block_given?
12
+ block.call(key, this_val, other_val)
13
+ else
14
+ other_val
15
+ end
16
+ end
17
+ end
18
+
19
+ def deep_stringify_keys!
20
+ deep_transform_keys!(&:to_s)
21
+ end
22
+
23
+ def deep_transform_keys!(&block)
24
+ _deep_transform_keys_in_object!(self, &block)
25
+ end
26
+
27
+ def _deep_transform_keys_in_object!(object, &block)
28
+ case object
29
+ when Hash
30
+ object.keys.each do |key|
31
+ value = object.delete(key)
32
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
33
+ end
34
+ object
35
+ when Array
36
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
37
+ else
38
+ object
39
+ end
40
+ end
41
+ end