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.
- checksums.yaml +4 -4
- data/lib/delfos.rb +72 -13
- data/lib/delfos/call_stack.rb +9 -9
- data/lib/delfos/call_stack/stack.rb +18 -18
- data/lib/delfos/file_system.rb +16 -0
- data/lib/delfos/file_system/app_directories.rb +42 -0
- data/lib/delfos/file_system/common_path.rb +17 -11
- data/lib/delfos/file_system/distance_calculation.rb +12 -3
- data/lib/delfos/file_system/path_determination.rb +4 -1
- data/lib/delfos/file_system/relation.rb +1 -0
- data/lib/delfos/method_trace.rb +59 -0
- data/lib/delfos/method_trace/call_handler.rb +48 -0
- data/lib/delfos/method_trace/code_location.rb +35 -0
- data/lib/delfos/method_trace/code_location/call_site.rb +38 -0
- data/lib/delfos/method_trace/code_location/container_method_factory.rb +71 -0
- data/lib/delfos/method_trace/code_location/eval_in_caller.rb +17 -0
- data/lib/delfos/method_trace/code_location/filename_helpers.rb +46 -0
- data/lib/delfos/method_trace/code_location/method.rb +58 -0
- data/lib/delfos/neo4j.rb +4 -4
- data/lib/delfos/neo4j/batch/execution.rb +30 -88
- data/lib/delfos/neo4j/batch/retryable.rb +101 -0
- data/lib/delfos/neo4j/call_site_query.rb +89 -0
- data/lib/delfos/neo4j/distance/call_site_fetcher.rb +1 -0
- data/lib/delfos/neo4j/distance/update.rb +22 -5
- data/lib/delfos/neo4j/live/call_site_logger.rb +17 -0
- data/lib/delfos/neo4j/offline/call_site_logger.rb +39 -0
- data/lib/delfos/neo4j/offline/importer.rb +68 -0
- data/lib/delfos/neo4j/query_execution/errors.rb +13 -3
- data/lib/delfos/neo4j/query_execution/http.rb +1 -0
- data/lib/delfos/neo4j/query_execution/http_query.rb +20 -15
- data/lib/delfos/neo4j/query_execution/sync.rb +1 -0
- data/lib/delfos/neo4j/query_execution/transactional.rb +24 -13
- data/lib/delfos/neo4j/schema.rb +5 -19
- data/lib/delfos/setup.rb +76 -44
- metadata +77 -18
- data/lib/delfos/method_logging.rb +0 -52
- data/lib/delfos/method_logging/call_site_parsing.rb +0 -74
- data/lib/delfos/method_logging/code_location.rb +0 -89
- data/lib/delfos/method_logging/method_parameters.rb +0 -53
- data/lib/delfos/neo4j/call_stack_query.rb +0 -88
- data/lib/delfos/neo4j/informer.rb +0 -128
- data/lib/delfos/patching/basic_object.rb +0 -14
- data/lib/delfos/patching/basic_object_remove.rb +0 -7
- data/lib/delfos/patching/method_cache.rb +0 -83
- data/lib/delfos/patching/method_override.rb +0 -148
- data/lib/delfos/patching/module_defining_methods.rb +0 -105
- data/lib/delfos/patching/unstubber.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7fee8925fceb4563ffc7f5895a63c2d3e372c06
|
4
|
+
data.tar.gz: 444793d867d93a22502053420bec22c7c14cef79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9424c15ce219468cadb02be9e35ce932bbba9cb103416dbb0eda9115b61943955e2eae1c5464296a255aa83ad7a8de9b985240c298d4d953009829696ab577b4
|
7
|
+
data.tar.gz: ceb9b9bc4d27a011d46785b92a3d1c62294f0abce4f95e5d69fa1d8aadeee9178bf8abd971c3e8b71c0111005046f7758d92840d0dcae48db80481ea54eeae3f
|
data/lib/delfos.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
15
|
-
|
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
|
19
|
-
|
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 ||=
|
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
|
36
|
-
|
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
|
-
|
97
|
+
|
98
|
+
Logger.new(STDOUT).tap do |l|
|
99
|
+
l.level = Logger::ERROR
|
100
|
+
end
|
42
101
|
end
|
43
102
|
end
|
44
103
|
end
|
data/lib/delfos/call_stack.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
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(:
|
18
|
+
Thread.current[:_delfos__call_stack] ||= Stack.new(on_empty: method(:reset!))
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
23
|
-
def push(
|
24
|
-
stack.push(
|
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
|
32
|
-
stack.
|
31
|
+
def height
|
32
|
+
stack.height
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
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.
|
17
|
+
self.height += 1
|
12
18
|
|
13
|
-
self.execution_count += self.
|
19
|
+
self.execution_count += self.height == 1 ? 1 : 0
|
14
20
|
end
|
15
21
|
|
16
22
|
def pop
|
17
|
-
|
23
|
+
raise PoppingEmptyStackError if self.height.zero?
|
24
|
+
|
25
|
+
self.height -= 1
|
18
26
|
|
19
|
-
|
27
|
+
return unless height.zero? && call_sites.length.positive?
|
20
28
|
|
21
|
-
|
22
|
-
|
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.
|
34
|
+
pop while self.height.positive?
|
29
35
|
end
|
30
36
|
|
31
|
-
def
|
32
|
-
@
|
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 :
|
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
|
-
|
20
|
-
|
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.
|
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
|
-
|
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.
|
43
|
+
traversals.sum(&:distance)
|
35
44
|
end
|
36
45
|
|
37
46
|
def sum_possible_traversals
|
38
|
-
traversals.
|
47
|
+
traversals.sum(&:possible_length)
|
39
48
|
end
|
40
49
|
|
41
50
|
def sibling_directories(path)
|
42
|
-
siblings(path).select { |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
|
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 }
|
@@ -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
|