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