delfos 0.0.1 → 0.0.2.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/delfos.rb +72 -13
  3. data/lib/delfos/call_stack.rb +9 -9
  4. data/lib/delfos/call_stack/stack.rb +18 -18
  5. data/lib/delfos/file_system.rb +16 -0
  6. data/lib/delfos/file_system/app_directories.rb +42 -0
  7. data/lib/delfos/file_system/common_path.rb +17 -11
  8. data/lib/delfos/file_system/distance_calculation.rb +12 -3
  9. data/lib/delfos/file_system/path_determination.rb +4 -1
  10. data/lib/delfos/file_system/relation.rb +1 -0
  11. data/lib/delfos/method_trace.rb +59 -0
  12. data/lib/delfos/method_trace/call_handler.rb +48 -0
  13. data/lib/delfos/method_trace/code_location.rb +35 -0
  14. data/lib/delfos/method_trace/code_location/call_site.rb +38 -0
  15. data/lib/delfos/method_trace/code_location/container_method_factory.rb +71 -0
  16. data/lib/delfos/method_trace/code_location/eval_in_caller.rb +17 -0
  17. data/lib/delfos/method_trace/code_location/filename_helpers.rb +46 -0
  18. data/lib/delfos/method_trace/code_location/method.rb +58 -0
  19. data/lib/delfos/neo4j.rb +4 -4
  20. data/lib/delfos/neo4j/batch/execution.rb +30 -88
  21. data/lib/delfos/neo4j/batch/retryable.rb +101 -0
  22. data/lib/delfos/neo4j/call_site_query.rb +89 -0
  23. data/lib/delfos/neo4j/distance/call_site_fetcher.rb +1 -0
  24. data/lib/delfos/neo4j/distance/update.rb +22 -5
  25. data/lib/delfos/neo4j/live/call_site_logger.rb +17 -0
  26. data/lib/delfos/neo4j/offline/call_site_logger.rb +39 -0
  27. data/lib/delfos/neo4j/offline/importer.rb +68 -0
  28. data/lib/delfos/neo4j/query_execution/errors.rb +13 -3
  29. data/lib/delfos/neo4j/query_execution/http.rb +1 -0
  30. data/lib/delfos/neo4j/query_execution/http_query.rb +20 -15
  31. data/lib/delfos/neo4j/query_execution/sync.rb +1 -0
  32. data/lib/delfos/neo4j/query_execution/transactional.rb +24 -13
  33. data/lib/delfos/neo4j/schema.rb +5 -19
  34. data/lib/delfos/setup.rb +76 -44
  35. metadata +77 -18
  36. data/lib/delfos/method_logging.rb +0 -52
  37. data/lib/delfos/method_logging/call_site_parsing.rb +0 -74
  38. data/lib/delfos/method_logging/code_location.rb +0 -89
  39. data/lib/delfos/method_logging/method_parameters.rb +0 -53
  40. data/lib/delfos/neo4j/call_stack_query.rb +0 -88
  41. data/lib/delfos/neo4j/informer.rb +0 -128
  42. data/lib/delfos/patching/basic_object.rb +0 -14
  43. data/lib/delfos/patching/basic_object_remove.rb +0 -7
  44. data/lib/delfos/patching/method_cache.rb +0 -83
  45. data/lib/delfos/patching/method_override.rb +0 -148
  46. data/lib/delfos/patching/module_defining_methods.rb +0 -105
  47. data/lib/delfos/patching/unstubber.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87475ed3a25d014e199e651988f4d3183561816a
4
- data.tar.gz: 0c2441e45f0dfbe6b272e0904654907fba9f53d2
3
+ metadata.gz: d7fee8925fceb4563ffc7f5895a63c2d3e372c06
4
+ data.tar.gz: 444793d867d93a22502053420bec22c7c14cef79
5
5
  SHA512:
6
- metadata.gz: 84f4de34ff44908ce8794643553ece54cd9914cc519502d3bfb3adfc3caa0e97effbefa65aba573f1ade386839798c496bd7adf10822ff9ff3c9734459ec1bcc
7
- data.tar.gz: 9fd34ca930e93e73a5e16294a6fc4a94464accd3f8b91353a9a8c94d99a418ef7494855b79f064334ed102a70107a9049f3e1e554f37e4c88e5681392cd7d85d
6
+ metadata.gz: 9424c15ce219468cadb02be9e35ce932bbba9cb103416dbb0eda9115b61943955e2eae1c5464296a255aa83ad7a8de9b985240c298d4d953009829696ab577b4
7
+ data.tar.gz: ceb9b9bc4d27a011d46785b92a3d1c62294f0abce4f95e5d69fa1d8aadeee9178bf8abd971c3e8b71c0111005046f7758d92840d0dcae48db80481ea54eeae3f
@@ -1,22 +1,58 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "delfos/setup"
3
4
 
4
5
  module Delfos
5
6
  class << self
6
- attr_accessor :application_directories
7
- attr_writer :logger, :neo4j
7
+ attr_accessor :application_directories,
8
+ :offline_query_saving,
9
+ :offline_query_filename
10
+
11
+ attr_writer :logger, :neo4j, :batch_size, :max_query_size
12
+
13
+ # rubocop:disable Metrics/ParameterLists
14
+ def setup!(
15
+ logger: nil,
16
+ call_site_logger: nil,
17
+ application_directories: nil,
18
+ batch_size: nil,
19
+ max_query_size: nil,
20
+ offline_query_saving: nil
21
+ )
22
+ # rubocop:enable Metrics/ParameterLists
23
+ self.logger = logger
24
+ self.batch_size = batch_size
25
+ self.max_query_size = max_query_size
8
26
 
9
- def setup!(logger: nil, call_site_logger: nil, application_directories: nil)
10
- self.logger = logger if logger
11
- Delfos::Setup.perform!(call_site_logger: call_site_logger, application_directories: application_directories)
27
+ Setup.perform!(
28
+ call_site_logger: call_site_logger,
29
+ application_directories: application_directories,
30
+ offline_query_saving: offline_query_saving,
31
+ )
12
32
  end
13
33
 
14
- def call_site_logger
15
- Delfos::Setup.call_site_logger
34
+ def import_offline_queries(filename)
35
+ require "delfos/neo4j/offline/importer"
36
+ Neo4j::Offline::Importer.new(filename).perform
37
+ end
38
+
39
+ def batch_size
40
+ @batch_size ||= 100
16
41
  end
17
42
 
18
- def call_site_logger=(call_site_logger)
19
- Delfos::Setup.call_site_logger = call_site_logger
43
+ def max_query_size
44
+ @max_query_size ||= 10_000
45
+ end
46
+
47
+ def include_file?(file)
48
+ require "delfos/file_system"
49
+ FileSystem.include_file?(file)
50
+ end
51
+
52
+ attr_writer :call_site_logger
53
+
54
+ def call_site_logger
55
+ @call_site_logger ||= Delfos::Setup.default_call_site_logger
20
56
  end
21
57
 
22
58
  def logger
@@ -29,16 +65,39 @@ module Delfos
29
65
 
30
66
  def setup_neo4j!
31
67
  require "delfos/neo4j"
32
- @neo4j ||= Delfos::Neo4j.config
68
+ @neo4j ||= Neo4j.config
69
+ end
70
+
71
+ def finish!
72
+ if offline_query_saving
73
+ Delfos.call_site_logger.finish!
74
+ else
75
+ flush!
76
+ update_distance!
77
+ disable!
78
+ end
79
+ end
80
+
81
+ def update_distance!
82
+ require "delfos/neo4j"
83
+ Neo4j.update_distance!
33
84
  end
34
85
 
35
- def reset!
36
- Delfos::Setup.reset!
86
+ def flush!
87
+ require "delfos/neo4j"
88
+ Neo4j.flush!
89
+ end
90
+
91
+ def disable!
92
+ Setup.disable!
37
93
  end
38
94
 
39
95
  def default_logger
40
96
  require "logger"
41
- Logger.new(STDOUT)
97
+
98
+ Logger.new(STDOUT).tap do |l|
99
+ l.level = Logger::ERROR
100
+ end
42
101
  end
43
102
  end
44
103
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require_relative "neo4j"
3
- require_relative "neo4j/call_stack_query"
2
+
4
3
  require_relative "call_stack/stack"
5
4
 
6
5
  module Delfos
@@ -16,24 +15,25 @@ module Delfos
16
15
 
17
16
  def stack
18
17
  CALL_STACK_MUTEX.synchronize do
19
- Thread.current[:_delfos__call_stack] ||= Stack.new(on_empty: method(:save!))
18
+ Thread.current[:_delfos__call_stack] ||= Stack.new(on_empty: method(:reset!))
20
19
  end
21
20
  end
22
21
 
23
- def push(method_object)
24
- stack.push(method_object)
22
+ def push(call_site)
23
+ stack.push(call_site)
24
+ Delfos.call_site_logger.log(call_site, stack.uuid, stack.step_count)
25
25
  end
26
26
 
27
27
  def pop
28
28
  stack.pop
29
29
  end
30
30
 
31
- def pop_until_top!
32
- stack.pop_until_top!
31
+ def height
32
+ stack.height
33
33
  end
34
34
 
35
- def save!(call_sites, execution_number)
36
- Delfos::MethodLogging.save_call_stack(call_sites, execution_number)
35
+ def pop_until_top!
36
+ stack.pop_until_top!
37
37
  end
38
38
  end
39
39
  end
@@ -1,35 +1,41 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
2
5
  module Delfos
3
6
  module CallStack
4
7
  class Stack
8
+ attr_reader :uuid
9
+
5
10
  def initialize(on_empty: nil)
6
11
  @on_empty = on_empty
12
+ @uuid = SecureRandom.uuid
7
13
  end
8
14
 
9
15
  def push(method_object)
10
16
  call_sites.push(method_object)
11
- self.stack_depth += 1
17
+ self.height += 1
12
18
 
13
- self.execution_count += self.stack_depth == 1 ? 1 : 0
19
+ self.execution_count += self.height == 1 ? 1 : 0
14
20
  end
15
21
 
16
22
  def pop
17
- popping_empty_stack! if self.stack_depth.zero?
23
+ raise PoppingEmptyStackError if self.height.zero?
24
+
25
+ self.height -= 1
18
26
 
19
- self.stack_depth -= 1
27
+ return unless height.zero? && call_sites.length.positive?
20
28
 
21
- if stack_depth.zero? && call_sites.length.positive?
22
- @on_empty&.call(call_sites, execution_count)
23
- self.call_sites = []
24
- end
29
+ @on_empty&.call
30
+ self.call_sites = []
25
31
  end
26
32
 
27
33
  def pop_until_top!
28
- pop while self.stack_depth.positive?
34
+ pop while self.height.positive?
29
35
  end
30
36
 
31
- def stack_depth
32
- @stack_depth ||= 0
37
+ def height
38
+ @height ||= 0
33
39
  end
34
40
 
35
41
  def execution_count
@@ -44,13 +50,7 @@ module Delfos
44
50
  call_sites.length
45
51
  end
46
52
 
47
- attr_writer :stack_depth, :step_count, :execution_count, :call_sites
48
-
49
- private
50
-
51
- def popping_empty_stack!
52
- raise PoppingEmptyStackError
53
- end
53
+ attr_writer :height, :step_count, :execution_count, :call_sites
54
54
  end
55
55
 
56
56
  class PoppingEmptyStackError < StandardError
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "file_system/distance_calculation"
4
+ require_relative "file_system/app_directories"
5
+
6
+ module Delfos
7
+ module FileSystem
8
+ def self.distance_calculation(start_file, finish_file)
9
+ DistanceCalculation.new(start_file, finish_file)
10
+ end
11
+
12
+ def self.include_file?(file)
13
+ FileSystem::AppDirectories.include_file?(file)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "common_path"
4
+
5
+ module Delfos
6
+ module FileSystem
7
+ module AppDirectories
8
+ extend self
9
+
10
+ def exclude_file?(file)
11
+ !include_file?(file)
12
+ end
13
+
14
+ def include_file?(file)
15
+ return false if file.nil?
16
+ with_cache(file) { should_include?(file) }
17
+ end
18
+
19
+ def reset!
20
+ @cache = nil
21
+ end
22
+
23
+ private
24
+
25
+ def should_include?(file)
26
+ CommonPath.included_in?(expand_path(file), Delfos.application_directories)
27
+ end
28
+
29
+ def expand_path(f)
30
+ Pathname.new(f).expand_path
31
+ end
32
+
33
+ def with_cache(key)
34
+ cache.include?(key) ? cache[key] : cache[key] = yield
35
+ end
36
+
37
+ def cache
38
+ @cache ||= {}
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require "pathname"
3
2
 
4
3
  module Delfos
5
4
  module FileSystem
@@ -8,6 +7,8 @@ module Delfos
8
7
  SEPARATOR = "/"
9
8
 
10
9
  def included_in?(p1, paths)
10
+ return false if paths.nil?
11
+
11
12
  paths.any? do |p2|
12
13
  common = common_parent(p1, p2)
13
14
  common.to_s.length >= p2.to_s.length
@@ -16,13 +17,12 @@ module Delfos
16
17
 
17
18
  def common_parent(path_a, path_b)
18
19
  dirs = [
19
- File.expand_path(path_a.to_s),
20
- File.expand_path(path_b.to_s),
20
+ Pathname.new(path_a.to_s).expand_path,
21
+ Pathname.new(path_b.to_s).expand_path,
21
22
  ]
22
23
 
23
- dir1, dir2 = dirs.minmax.map { |dir| dir.split(SEPARATOR) }
24
-
25
- path_from(dir1, dir2, path_a, path_b)
24
+ dir1, dir2 = dirs.sort.map { |dir| dir.to_s.split(SEPARATOR) }
25
+ append_trailing_slash!(path_from(dir1, dir2, path_a, path_b).to_s)
26
26
  end
27
27
 
28
28
  private
@@ -47,13 +47,19 @@ module Delfos
47
47
  join(SEPARATOR)
48
48
  end
49
49
 
50
+ def append_trailing_slash!(path)
51
+ path = path.to_s
52
+
53
+ if Pathname.new(path).directory?
54
+ path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
55
+ end
56
+
57
+ path
58
+ end
59
+
50
60
  def append_trailing_slashes!(*paths)
51
61
  paths.map do |path|
52
- if Pathname.new(path).directory?
53
- path += SEPARATOR if path && path.to_s[-1] != SEPARATOR
54
- end
55
-
56
- path
62
+ append_trailing_slash!(path)
57
63
  end
58
64
  end
59
65
  end
@@ -1,14 +1,23 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "relation"
3
4
  require_relative "path_determination"
4
5
 
5
6
  module Delfos
6
7
  module FileSystem
8
+ Error = Class.new(::StandardError)
9
+
7
10
  class DistanceCalculation
8
11
  attr_reader :path_a, :path_b
9
12
 
13
+ PathNotFound = Class.new(Error)
14
+
10
15
  def initialize(path_a, path_b)
11
16
  @path_a, @path_b = PathDetermination.for(path_a, path_b)
17
+
18
+ return if @path_a && @path_b
19
+
20
+ raise PathNotFound, "path_a: #{path_a} -> #{@path_a.inspect}, path_b: #{path_b} -> #{@path_b.inspect}"
12
21
  end
13
22
 
14
23
  attr_reader :traversal_a, :traversal_b
@@ -31,15 +40,15 @@ module Delfos
31
40
  end
32
41
 
33
42
  def sum_traversals
34
- traversals.inject(0) { |a, e| a + e.distance }
43
+ traversals.sum(&:distance)
35
44
  end
36
45
 
37
46
  def sum_possible_traversals
38
- traversals.inject(0) { |a, e| a + e.possible_length }
47
+ traversals.sum(&:possible_length)
39
48
  end
40
49
 
41
50
  def sibling_directories(path)
42
- siblings(path).select { |f| File.directory?(f) }
51
+ siblings(path).select { |f| Pathname.new(f).directory?(f) }
43
52
  end
44
53
 
45
54
  def traversal_path
@@ -1,4 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
2
5
  module Delfos
3
6
  module FileSystem
4
7
  class PathDetermination
@@ -11,7 +14,7 @@ module Delfos
11
14
  end
12
15
 
13
16
  def full_path
14
- return @file.realpath if File.exist?(@file)
17
+ return @file.realpath if Pathname.new(@file).exist?
15
18
 
16
19
  Delfos.application_directories.map do |d|
17
20
  path = try_path { d + @file }
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Delfos
3
4
  module FileSystem
4
5
  class Relation
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "method_trace/call_handler"
4
+ require_relative "call_stack"
5
+
6
+ module Delfos
7
+ module MethodTrace
8
+ class << self
9
+ def trace!
10
+ on_call.enable
11
+ on_return.enable
12
+ @last_returned = nil
13
+ end
14
+
15
+ def disable!
16
+ @on_call&.disable
17
+ @on_call = nil
18
+
19
+ @on_return&.disable
20
+ @on_return = nil
21
+
22
+ @last_returned = nil
23
+ end
24
+
25
+ def on_call
26
+ @on_call ||= setup_trace_point(:call) do |tp|
27
+ CallHandler.new(tp).perform
28
+ end
29
+ end
30
+
31
+ def on_return
32
+ @on_return ||= setup_trace_point(:return) do |tp|
33
+ next if check_for_bug!(tp)
34
+
35
+ CallStack.pop
36
+
37
+ @last_returned = tp
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # FIXME: There seems to be a bug where the last TracePoint in a chain
44
+ # when returning to (main) is duplicated. Can't get to the source of
45
+ # this. But the only effect seems to be popping the stacking beyond the
46
+ # end so this is a workaround
47
+ def check_for_bug!(tp)
48
+ (@last_returned == tp) && CallStack.height.zero?
49
+ end
50
+
51
+ def setup_trace_point(type)
52
+ TracePoint.new(type) do |tp|
53
+ next unless Delfos.include_file?(tp.path)
54
+ yield tp
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end