delfos 0.0.1.pre.rc1 → 0.0.1
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 +22 -78
- data/lib/delfos/call_stack.rb +39 -0
- data/lib/delfos/call_stack/stack.rb +59 -0
- data/lib/delfos/file_system/common_path.rb +62 -0
- data/lib/delfos/{distance/calculation.rb → file_system/distance_calculation.rb} +4 -15
- data/lib/delfos/file_system/path_determination.rb +37 -0
- data/lib/delfos/{distance → file_system}/relation.rb +1 -1
- data/lib/delfos/method_logging.rb +32 -49
- data/lib/delfos/method_logging/call_site_parsing.rb +74 -0
- data/lib/delfos/method_logging/code_location.rb +34 -98
- data/lib/delfos/method_logging/{args.rb → method_parameters.rb} +17 -18
- data/lib/delfos/neo4j.rb +58 -0
- data/lib/delfos/neo4j/batch/execution.rb +149 -0
- data/lib/delfos/neo4j/{execution_persistence.rb → call_stack_query.rb} +12 -22
- data/lib/delfos/neo4j/distance/call_site_fetcher.rb +19 -0
- data/lib/delfos/neo4j/distance/update.rb +50 -0
- data/lib/delfos/neo4j/informer.rb +62 -34
- data/lib/delfos/neo4j/query_execution/errors.rb +30 -0
- data/lib/delfos/neo4j/query_execution/http.rb +61 -0
- data/lib/delfos/neo4j/query_execution/http_query.rb +67 -0
- data/lib/delfos/neo4j/query_execution/sync.rb +35 -0
- data/lib/delfos/neo4j/query_execution/transactional.rb +68 -0
- data/lib/delfos/neo4j/schema.rb +73 -0
- data/lib/delfos/patching/basic_object.rb +1 -5
- data/lib/delfos/patching/method_cache.rb +83 -0
- data/lib/delfos/patching/method_override.rb +76 -66
- data/lib/delfos/patching/module_defining_methods.rb +105 -0
- data/lib/delfos/patching/unstubber.rb +34 -0
- data/lib/delfos/setup.rb +88 -0
- metadata +42 -15
- data/lib/delfos/common_path.rb +0 -58
- data/lib/delfos/execution_chain.rb +0 -75
- data/lib/delfos/method_logging/added_methods.rb +0 -67
- data/lib/delfos/neo4j/distance_update.rb +0 -73
- data/lib/delfos/neo4j/query_execution.rb +0 -79
- data/lib/delfos/patching/unstubbing_spec_helper.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87475ed3a25d014e199e651988f4d3183561816a
|
4
|
+
data.tar.gz: 0c2441e45f0dfbe6b272e0904654907fba9f53d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84f4de34ff44908ce8794643553ece54cd9914cc519502d3bfb3adfc3caa0e97effbefa65aba573f1ade386839798c496bd7adf10822ff9ff3c9734459ec1bcc
|
7
|
+
data.tar.gz: 9fd34ca930e93e73a5e16294a6fc4a94464accd3f8b91353a9a8c94d99a418ef7494855b79f064334ed102a70107a9049f3e1e554f37e4c88e5681392cd7d85d
|
data/lib/delfos.rb
CHANGED
@@ -1,100 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "delfos/
|
2
|
+
require "delfos/setup"
|
3
3
|
|
4
4
|
module Delfos
|
5
5
|
class << self
|
6
|
-
|
6
|
+
attr_accessor :application_directories
|
7
|
+
attr_writer :logger, :neo4j
|
7
8
|
|
8
|
-
def
|
9
|
-
|
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)
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
13
|
-
Delfos.
|
14
|
-
|
15
|
-
require "delfos/neo4j/query_execution"
|
16
|
-
Delfos::Neo4j::QueryExecution.execute <<-QUERY
|
17
|
-
MATCH (m)-[rel]->(n)
|
18
|
-
DELETE m,rel,n
|
19
|
-
QUERY
|
14
|
+
def call_site_logger
|
15
|
+
Delfos::Setup.call_site_logger
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
|
24
|
-
@method_logging = nil
|
25
|
-
@neo4j = nil
|
26
|
-
@logger = nil
|
27
|
-
|
28
|
-
if defined? Delfos::ExecutionChain
|
29
|
-
Delfos::ExecutionChain.reset!
|
30
|
-
end
|
31
|
-
|
32
|
-
# unstubbing depends upon AddedMethods being still defined
|
33
|
-
# so this order is important
|
34
|
-
unstub_all!
|
35
|
-
remove_added_methods!
|
36
|
-
|
37
|
-
remove_patching!
|
18
|
+
def call_site_logger=(call_site_logger)
|
19
|
+
Delfos::Setup.call_site_logger = call_site_logger
|
38
20
|
end
|
39
21
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
if Delfos::Patching::MethodOverride.respond_to?(:unstub_all!)
|
44
|
-
Delfos::Patching::MethodOverride.unstub_all!
|
45
|
-
end
|
46
|
-
end
|
22
|
+
def logger
|
23
|
+
@logger ||= default_logger
|
47
24
|
end
|
48
25
|
|
49
|
-
def
|
50
|
-
|
51
|
-
Delfos::MethodLogging::AddedMethods.instance_eval { @instance = nil }
|
52
|
-
end
|
26
|
+
def neo4j
|
27
|
+
setup_neo4j!
|
53
28
|
end
|
54
29
|
|
55
|
-
def
|
56
|
-
|
30
|
+
def setup_neo4j!
|
31
|
+
require "delfos/neo4j"
|
32
|
+
@neo4j ||= Delfos::Neo4j.config
|
57
33
|
end
|
58
34
|
|
59
|
-
def
|
60
|
-
|
61
|
-
neo4j_username: nil,
|
62
|
-
neo4j_password: nil,
|
63
|
-
application_directories: nil)
|
64
|
-
application_directories ||= %w(app lib)
|
65
|
-
|
66
|
-
@application_directories = if application_directories.is_a?(Proc)
|
67
|
-
application_directories
|
68
|
-
else
|
69
|
-
Array(application_directories).map { |f| Pathname.new(File.expand_path(f.to_s)) }
|
70
|
-
end
|
71
|
-
|
72
|
-
@logger = logger
|
73
|
-
|
74
|
-
setup_neo4j!(neo4j_url, neo4j_username, neo4j_password)
|
75
|
-
|
76
|
-
perform_patching!
|
77
|
-
end
|
78
|
-
|
79
|
-
def setup_neo4j!(url = nil, username = nil, password = nil)
|
80
|
-
url ||= ENV["NEO4J_URL"] || "http://localhost:7474"
|
81
|
-
username ||= ENV["NEO4J_USERNAME"] || "neo4j"
|
82
|
-
password ||= ENV["NEO4J_PASSWORD"] || "password"
|
83
|
-
@neo4j = Neo4jOptions.new(url, username, password)
|
84
|
-
end
|
85
|
-
|
86
|
-
def perform_patching!
|
87
|
-
load "delfos/patching/basic_object.rb"
|
35
|
+
def reset!
|
36
|
+
Delfos::Setup.reset!
|
88
37
|
end
|
89
38
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
def to_s
|
94
|
-
" url: #{url}\n username: #{username}\n password: #{password}"
|
95
|
-
end
|
39
|
+
def default_logger
|
40
|
+
require "logger"
|
41
|
+
Logger.new(STDOUT)
|
96
42
|
end
|
97
|
-
|
98
|
-
attr_reader :application_directories, :neo4j_host, :neo4j_username, :neo4j_password
|
99
43
|
end
|
100
44
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "neo4j"
|
3
|
+
require_relative "neo4j/call_stack_query"
|
4
|
+
require_relative "call_stack/stack"
|
5
|
+
|
6
|
+
module Delfos
|
7
|
+
module CallStack
|
8
|
+
CALL_STACK_MUTEX = Mutex.new
|
9
|
+
extend self
|
10
|
+
|
11
|
+
def reset!
|
12
|
+
CALL_STACK_MUTEX.synchronize do
|
13
|
+
Thread.current[:_delfos__call_stack] = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def stack
|
18
|
+
CALL_STACK_MUTEX.synchronize do
|
19
|
+
Thread.current[:_delfos__call_stack] ||= Stack.new(on_empty: method(:save!))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def push(method_object)
|
24
|
+
stack.push(method_object)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop
|
28
|
+
stack.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
def pop_until_top!
|
32
|
+
stack.pop_until_top!
|
33
|
+
end
|
34
|
+
|
35
|
+
def save!(call_sites, execution_number)
|
36
|
+
Delfos::MethodLogging.save_call_stack(call_sites, execution_number)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module CallStack
|
4
|
+
class Stack
|
5
|
+
def initialize(on_empty: nil)
|
6
|
+
@on_empty = on_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
def push(method_object)
|
10
|
+
call_sites.push(method_object)
|
11
|
+
self.stack_depth += 1
|
12
|
+
|
13
|
+
self.execution_count += self.stack_depth == 1 ? 1 : 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def pop
|
17
|
+
popping_empty_stack! if self.stack_depth.zero?
|
18
|
+
|
19
|
+
self.stack_depth -= 1
|
20
|
+
|
21
|
+
if stack_depth.zero? && call_sites.length.positive?
|
22
|
+
@on_empty&.call(call_sites, execution_count)
|
23
|
+
self.call_sites = []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def pop_until_top!
|
28
|
+
pop while self.stack_depth.positive?
|
29
|
+
end
|
30
|
+
|
31
|
+
def stack_depth
|
32
|
+
@stack_depth ||= 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def execution_count
|
36
|
+
@execution_count ||= 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def call_sites
|
40
|
+
@call_sites ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def step_count
|
44
|
+
call_sites.length
|
45
|
+
end
|
46
|
+
|
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
|
54
|
+
end
|
55
|
+
|
56
|
+
class PoppingEmptyStackError < StandardError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module Delfos
|
5
|
+
module FileSystem
|
6
|
+
module CommonPath
|
7
|
+
class << self
|
8
|
+
SEPARATOR = "/"
|
9
|
+
|
10
|
+
def included_in?(p1, paths)
|
11
|
+
paths.any? do |p2|
|
12
|
+
common = common_parent(p1, p2)
|
13
|
+
common.to_s.length >= p2.to_s.length
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def common_parent(path_a, path_b)
|
18
|
+
dirs = [
|
19
|
+
File.expand_path(path_a.to_s),
|
20
|
+
File.expand_path(path_b.to_s),
|
21
|
+
]
|
22
|
+
|
23
|
+
dir1, dir2 = dirs.minmax.map { |dir| dir.split(SEPARATOR) }
|
24
|
+
|
25
|
+
path_from(dir1, dir2, path_a, path_b)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def path_from(dir1, dir2, path_a, path_b)
|
31
|
+
common_path = common_path(dir1, dir2)
|
32
|
+
common_path, path_a, path_b = append_trailing_slashes!(common_path, path_a, path_b)
|
33
|
+
|
34
|
+
Pathname.new(common_path) if valid_length?(common_path, path_a, path_b)
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid_length?(common_path, path_a, path_b)
|
38
|
+
l = common_path.to_s.length
|
39
|
+
(l <= path_a.to_s.length) || (l <= path_b.to_s.length)
|
40
|
+
end
|
41
|
+
|
42
|
+
def common_path(dir1, dir2)
|
43
|
+
dir1.
|
44
|
+
zip(dir2).
|
45
|
+
take_while { |dn1, dn2| dn1 == dn2 }.
|
46
|
+
map(&:first).
|
47
|
+
join(SEPARATOR)
|
48
|
+
end
|
49
|
+
|
50
|
+
def append_trailing_slashes!(*paths)
|
51
|
+
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
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_relative "relation"
|
3
|
+
require_relative "path_determination"
|
3
4
|
|
4
5
|
module Delfos
|
5
|
-
module
|
6
|
-
class
|
6
|
+
module FileSystem
|
7
|
+
class DistanceCalculation
|
7
8
|
attr_reader :path_a, :path_b
|
8
9
|
|
9
10
|
def initialize(path_a, path_b)
|
10
|
-
@path_a = path_a
|
11
|
-
@path_b = path_b
|
11
|
+
@path_a, @path_b = PathDetermination.for(path_a, path_b)
|
12
12
|
end
|
13
13
|
|
14
14
|
attr_reader :traversal_a, :traversal_b
|
@@ -42,17 +42,6 @@ module Delfos
|
|
42
42
|
siblings(path).select { |f| File.directory?(f) }
|
43
43
|
end
|
44
44
|
|
45
|
-
def in_start_directory?(path)
|
46
|
-
return false if path.directory?
|
47
|
-
path_a.dirname == path
|
48
|
-
end
|
49
|
-
|
50
|
-
def in_finish_directory?(path)
|
51
|
-
return false if path.directory?
|
52
|
-
|
53
|
-
path_b.dirname == path
|
54
|
-
end
|
55
|
-
|
56
45
|
def traversal_path
|
57
46
|
TraversalPathCalculator.new(path_a, path_b).path
|
58
47
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Delfos
|
3
|
+
module FileSystem
|
4
|
+
class PathDetermination
|
5
|
+
def self.for(*files)
|
6
|
+
files.map { |f| new(f).full_path }
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = Pathname.new(strip_block_message(file))
|
11
|
+
end
|
12
|
+
|
13
|
+
def full_path
|
14
|
+
return @file.realpath if File.exist?(@file)
|
15
|
+
|
16
|
+
Delfos.application_directories.map do |d|
|
17
|
+
path = try_path { d + @file }
|
18
|
+
|
19
|
+
path || try_path do
|
20
|
+
Pathname.new(d + @file.to_s.gsub(%r{[^/]*/}, ""))
|
21
|
+
end
|
22
|
+
end.compact.first
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def strip_block_message(f)
|
28
|
+
f.to_s.split(" in block").first
|
29
|
+
end
|
30
|
+
|
31
|
+
def try_path
|
32
|
+
path = yield
|
33
|
+
path if path.exist?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,69 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "
|
3
|
-
|
4
|
-
require "binding_of_caller"
|
5
|
-
require_relative "common_path"
|
2
|
+
require "delfos/file_system/common_path"
|
3
|
+
|
6
4
|
require_relative "method_logging/code_location"
|
7
|
-
require_relative "method_logging/
|
8
|
-
require_relative "execution_chain"
|
5
|
+
require_relative "method_logging/method_parameters"
|
9
6
|
|
10
7
|
module Delfos
|
11
|
-
|
12
|
-
|
13
|
-
attr_writer :method_logging
|
8
|
+
module MethodLogging
|
9
|
+
extend self
|
14
10
|
|
15
|
-
def
|
16
|
-
|
11
|
+
def save_call_stack(call_sites, execution_number)
|
12
|
+
Delfos.call_site_logger.save_call_stack(call_sites, execution_number)
|
17
13
|
end
|
18
|
-
end
|
19
14
|
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
def log(call_site, called_object, called_method, class_method, parameters)
|
16
|
+
called_code = CodeLocation.from_called(called_object, called_method, class_method)
|
17
|
+
|
18
|
+
Delfos.call_site_logger.log(parameters, call_site, called_code)
|
23
19
|
end
|
24
|
-
end
|
25
20
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise Delfos::ApplicationDirectoriesNotDefined unless Delfos.application_directories
|
30
|
-
end
|
21
|
+
def exclude?(method)
|
22
|
+
file, = method.source_location
|
23
|
+
return true unless file
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
arguments = Args.new(arguments)
|
35
|
-
called_code = CodeLocation.from_called(called_object, called_method, class_method)
|
25
|
+
exclude_file?(File.expand_path(file))
|
26
|
+
end
|
36
27
|
|
37
|
-
|
38
|
-
|
28
|
+
def include_file?(file)
|
29
|
+
!exclude_file?(file)
|
30
|
+
end
|
39
31
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
32
|
+
def exclude_file?(file)
|
33
|
+
with_cache(file) do
|
34
|
+
!FileSystem::CommonPath.included_in?(File.expand_path(file), Delfos.application_directories)
|
44
35
|
end
|
36
|
+
end
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
exclude_file_from_logging?(File.expand_path(file))
|
51
|
-
end
|
38
|
+
def reset!
|
39
|
+
@cache = nil
|
40
|
+
end
|
52
41
|
|
53
|
-
|
54
|
-
!exclude_file_from_logging?(file)
|
55
|
-
end
|
42
|
+
private
|
56
43
|
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
def with_cache(key)
|
45
|
+
cache.include?(key) ? cache[key] : cache[key] = yield
|
46
|
+
end
|
60
47
|
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
!CommonPath.included_in?(path, Delfos.application_directories)
|
65
|
-
end
|
66
|
-
end
|
48
|
+
def cache
|
49
|
+
@cache ||= {}
|
67
50
|
end
|
68
51
|
end
|
69
52
|
end
|