overrides_tracker 0.1.9 → 0.1.13

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