delfos 0.0.1 → 0.0.2.pre.rc2

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