appmap 0.42.0 → 0.45.1
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/.releaserc.yml +11 -0
- data/.travis.yml +23 -2
- data/CHANGELOG.md +42 -0
- data/README.md +65 -6
- data/README_CI.md +29 -0
- data/Rakefile +4 -2
- data/appmap.gemspec +5 -3
- data/lib/appmap.rb +4 -7
- data/lib/appmap/class_map.rb +7 -10
- data/lib/appmap/command/record.rb +1 -1
- data/lib/appmap/config.rb +173 -67
- data/lib/appmap/cucumber.rb +1 -1
- data/lib/appmap/event.rb +18 -0
- data/lib/appmap/handler/function.rb +19 -0
- data/lib/appmap/handler/net_http.rb +107 -0
- data/lib/appmap/hook.rb +112 -56
- data/lib/appmap/hook/method.rb +5 -7
- data/lib/appmap/middleware/remote_recording.rb +1 -1
- data/lib/appmap/minitest.rb +22 -20
- data/lib/appmap/rails/request_handler.rb +30 -17
- data/lib/appmap/record.rb +1 -1
- data/lib/appmap/rspec.rb +23 -21
- data/lib/appmap/trace.rb +2 -1
- data/lib/appmap/util.rb +47 -2
- data/lib/appmap/version.rb +2 -2
- data/release.sh +17 -0
- data/spec/abstract_controller_base_spec.rb +77 -30
- data/spec/class_map_spec.rb +3 -11
- data/spec/config_spec.rb +33 -1
- data/spec/fixtures/hook/custom_instance_method.rb +11 -0
- data/spec/fixtures/hook/method_named_call.rb +11 -0
- data/spec/fixtures/rails5_users_app/Gemfile +7 -3
- data/spec/fixtures/rails5_users_app/app/controllers/api/users_controller.rb +2 -0
- data/spec/fixtures/rails5_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails5_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails5_users_app/create_app +8 -2
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_api_spec.rb +13 -0
- data/spec/fixtures/rails5_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails5_users_app/spec/rails_helper.rb +3 -9
- data/spec/fixtures/rails6_users_app/Gemfile +5 -4
- data/spec/fixtures/rails6_users_app/app/controllers/api/users_controller.rb +1 -0
- data/spec/fixtures/rails6_users_app/app/controllers/users_controller.rb +9 -1
- data/spec/fixtures/rails6_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails6_users_app/create_app +8 -2
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_api_spec.rb +13 -0
- data/spec/fixtures/rails6_users_app/spec/controllers/users_controller_spec.rb +2 -2
- data/spec/fixtures/rails6_users_app/spec/rails_helper.rb +3 -9
- data/spec/hook_spec.rb +141 -20
- data/spec/record_net_http_spec.rb +160 -0
- data/spec/record_sql_rails_pg_spec.rb +1 -1
- data/spec/spec_helper.rb +16 -0
- data/test/expectations/openssl_test_key_sign1.json +2 -4
- data/test/gem_test.rb +1 -1
- data/test/rspec_test.rb +0 -13
- metadata +17 -12
- data/exe/appmap +0 -154
- data/test/cli_test.rb +0 -116
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'diffy'
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/handler/webrick'
|
5
|
+
|
6
|
+
class HelloWorldApp
|
7
|
+
def call(env)
|
8
|
+
req = Rack::Request.new(env)
|
9
|
+
case req.path_info
|
10
|
+
when /hello/
|
11
|
+
[200, {"Content-Type" => "text/html"}, ["Hello World!"]]
|
12
|
+
when /goodbye/
|
13
|
+
[500, {"Content-Type" => "text/html"}, ["Goodbye Cruel World!"]]
|
14
|
+
else
|
15
|
+
[404, {"Content-Type" => "text/html"}, ["I'm Lost!"]]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'Net::HTTP handler' do
|
21
|
+
include_context 'collect events'
|
22
|
+
|
23
|
+
def get_hello(params: nil)
|
24
|
+
http = Net::HTTP.new('localhost', 19292)
|
25
|
+
http.get [ '/hello', params ].compact.join('?')
|
26
|
+
end
|
27
|
+
|
28
|
+
before(:all) do
|
29
|
+
@rack_thread = Thread.new do
|
30
|
+
Rack::Handler::WEBrick.run HelloWorldApp.new, Port: 19292
|
31
|
+
end
|
32
|
+
10.times do
|
33
|
+
sleep 0.1
|
34
|
+
break if get_hello.code.to_i == 200
|
35
|
+
end
|
36
|
+
raise "Web server didn't start" unless get_hello.code.to_i == 200
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:all) do
|
40
|
+
@rack_thread.kill
|
41
|
+
end
|
42
|
+
|
43
|
+
def start_recording
|
44
|
+
AppMap.configuration = configuration
|
45
|
+
AppMap::Hook.new(configuration).enable
|
46
|
+
|
47
|
+
@tracer = AppMap.tracing.trace
|
48
|
+
AppMap::Event.reset_id_counter
|
49
|
+
end
|
50
|
+
|
51
|
+
def record(&block)
|
52
|
+
start_recording
|
53
|
+
begin
|
54
|
+
yield
|
55
|
+
ensure
|
56
|
+
stop_recording
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def stop_recording
|
61
|
+
AppMap.tracing.delete(@tracer)
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with trace enabled' do
|
65
|
+
let(:configuration) { AppMap::Config.new('record_net_http_spec', []) }
|
66
|
+
|
67
|
+
after do
|
68
|
+
AppMap.configuration = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'GET request' do
|
72
|
+
it 'with a single query parameter' do
|
73
|
+
record do
|
74
|
+
get_hello(params: 'msg=hi')
|
75
|
+
end
|
76
|
+
|
77
|
+
events = collect_events(@tracer).to_yaml
|
78
|
+
expect(Diffy::Diff.new(<<~EVENTS, events).to_s).to eq('')
|
79
|
+
---
|
80
|
+
- :id: 1
|
81
|
+
:event: :call
|
82
|
+
:http_client_request:
|
83
|
+
:request_method: GET
|
84
|
+
:url: http://localhost:19292/hello
|
85
|
+
:headers:
|
86
|
+
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
87
|
+
Accept: "*/*"
|
88
|
+
User-Agent: Ruby
|
89
|
+
Connection: close
|
90
|
+
:message:
|
91
|
+
- :name: msg
|
92
|
+
:class: String
|
93
|
+
:value: hi
|
94
|
+
- :id: 2
|
95
|
+
:event: :return
|
96
|
+
:parent_id: 1
|
97
|
+
:http_client_response:
|
98
|
+
:status_code: 200
|
99
|
+
:headers:
|
100
|
+
Content-Type: text/html
|
101
|
+
Server: WEBrick
|
102
|
+
Date: "<instanceof date>"
|
103
|
+
Content-Length: '12'
|
104
|
+
Connection: close
|
105
|
+
EVENTS
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'with a multi-valued query parameter' do
|
109
|
+
record do
|
110
|
+
get_hello(params: 'ary[]=1&ary[]=2')
|
111
|
+
end
|
112
|
+
|
113
|
+
event = collect_events(@tracer).first.to_yaml
|
114
|
+
expect(Diffy::Diff.new(<<~EVENT, event).to_s).to eq('')
|
115
|
+
---
|
116
|
+
:id: 1
|
117
|
+
:event: :call
|
118
|
+
:http_client_request:
|
119
|
+
:request_method: GET
|
120
|
+
:url: http://localhost:19292/hello
|
121
|
+
:headers:
|
122
|
+
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
123
|
+
Accept: "*/*"
|
124
|
+
User-Agent: Ruby
|
125
|
+
Connection: close
|
126
|
+
:message:
|
127
|
+
- :name: ary
|
128
|
+
:class: Array
|
129
|
+
:value: '["1", "2"]'
|
130
|
+
EVENT
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'with a URL encoded query parameter' do
|
134
|
+
msg = 'foo/bar?baz'
|
135
|
+
record do
|
136
|
+
get_hello(params: "msg=#{CGI.escape msg}")
|
137
|
+
end
|
138
|
+
|
139
|
+
event = collect_events(@tracer).first.to_yaml
|
140
|
+
expect(Diffy::Diff.new(<<~EVENT, event).to_s).to eq('')
|
141
|
+
---
|
142
|
+
:id: 1
|
143
|
+
:event: :call
|
144
|
+
:http_client_request:
|
145
|
+
:request_method: GET
|
146
|
+
:url: http://localhost:19292/hello
|
147
|
+
:headers:
|
148
|
+
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
149
|
+
Accept: "*/*"
|
150
|
+
User-Agent: Ruby
|
151
|
+
Connection: close
|
152
|
+
:message:
|
153
|
+
- :name: msg
|
154
|
+
:class: String
|
155
|
+
:value: #{msg}
|
156
|
+
EVENT
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -61,7 +61,7 @@ describe 'SQL events' do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
context 'while listing records' do
|
64
|
-
let(:test_line_number) {
|
64
|
+
let(:test_line_number) { 29 }
|
65
65
|
let(:appmap_json) { File.join(tmpdir, 'appmap/rspec/Api_UsersController_GET_api_users_lists_the_users.appmap.json') }
|
66
66
|
|
67
67
|
context 'using Sequel ORM' do
|
data/spec/spec_helper.rb
CHANGED
@@ -14,3 +14,19 @@ require 'appmap'
|
|
14
14
|
RSpec.configure do |config|
|
15
15
|
config.example_status_persistence_file_path = "tmp/rspec_failed_examples.txt"
|
16
16
|
end
|
17
|
+
|
18
|
+
# Re-run the Rails specs without re-generating the data. This is useful for efficiently enhancing and
|
19
|
+
# debugging the test itself.
|
20
|
+
def use_existing_data?
|
21
|
+
ENV['USE_EXISTING_DATA'] == 'true'
|
22
|
+
end
|
23
|
+
|
24
|
+
shared_context 'collect events' do
|
25
|
+
def collect_events(tracer)
|
26
|
+
[].tap do |events|
|
27
|
+
while tracer.event?
|
28
|
+
events << tracer.next_event.to_h
|
29
|
+
end
|
30
|
+
end.map(&AppMap::Util.method(:sanitize_event))
|
31
|
+
end
|
32
|
+
end
|
@@ -11,8 +11,7 @@
|
|
11
11
|
"name": "sign",
|
12
12
|
"type": "function",
|
13
13
|
"location": "lib/openssl_key_sign.rb:10",
|
14
|
-
"static": true
|
15
|
-
"source": " def Example.sign\n key = OpenSSL::PKey::RSA.new 2048\n\n document = 'the document'\n\n digest = OpenSSL::Digest::SHA256.new\n key.sign digest, document\n end\n"
|
14
|
+
"static": true
|
16
15
|
}
|
17
16
|
]
|
18
17
|
}
|
@@ -40,8 +39,7 @@
|
|
40
39
|
"location": "OpenSSL::PKey::PKey#sign",
|
41
40
|
"static": false,
|
42
41
|
"labels": [
|
43
|
-
"
|
44
|
-
"crypto"
|
42
|
+
"crypto.pkey"
|
45
43
|
]
|
46
44
|
}
|
47
45
|
]
|
data/test/gem_test.rb
CHANGED
@@ -26,7 +26,7 @@ class MinitestTest < Minitest::Test
|
|
26
26
|
assert_equal 2, events.size
|
27
27
|
assert_equal 'call', events.first['event']
|
28
28
|
assert_equal 'default_parser', events.first['method_id']
|
29
|
-
|
29
|
+
assert_match /\lib\/parser\/base\.rb$/, events.first['path']
|
30
30
|
assert_equal 'return', events.second['event']
|
31
31
|
assert_equal 1, events.second['parent_id']
|
32
32
|
end
|
data/test/rspec_test.rb
CHANGED
@@ -18,19 +18,6 @@ class RSpecTest < Minitest::Test
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def test_inventory
|
22
|
-
perform_test 'plain_hello_spec' do
|
23
|
-
appmap_file = 'tmp/appmap/rspec/Inventory.appmap.json'
|
24
|
-
|
25
|
-
assert File.file?(appmap_file), 'appmap output file does not exist'
|
26
|
-
appmap = JSON.parse(File.read(appmap_file))
|
27
|
-
assert_equal AppMap::APPMAP_FORMAT_VERSION, appmap['version']
|
28
|
-
assert_includes appmap.keys, 'metadata'
|
29
|
-
metadata = appmap['metadata']
|
30
|
-
assert_equal 'Inventory', metadata['name']
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
21
|
def test_record_decorated_rspec
|
35
22
|
perform_test 'decorated_hello_spec' do
|
36
23
|
appmap_file = 'tmp/appmap/rspec/Hello_says_hello.appmap.json'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.45.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
|
-
autorequire:
|
9
|
-
bindir:
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -304,11 +304,10 @@ dependencies:
|
|
304
304
|
- - ">="
|
305
305
|
- !ruby/object:Gem::Version
|
306
306
|
version: '0'
|
307
|
-
description:
|
307
|
+
description:
|
308
308
|
email:
|
309
309
|
- kgilpin@gmail.com
|
310
|
-
executables:
|
311
|
-
- appmap
|
310
|
+
executables: []
|
312
311
|
extensions:
|
313
312
|
- ext/appmap/extconf.rb
|
314
313
|
extra_rdoc_files: []
|
@@ -316,6 +315,7 @@ files:
|
|
316
315
|
- ".dockerignore"
|
317
316
|
- ".gitignore"
|
318
317
|
- ".rbenv-gemsets"
|
318
|
+
- ".releaserc.yml"
|
319
319
|
- ".rubocop.yml"
|
320
320
|
- ".travis.yml"
|
321
321
|
- CHANGELOG.md
|
@@ -324,6 +324,7 @@ files:
|
|
324
324
|
- Gemfile
|
325
325
|
- LICENSE.txt
|
326
326
|
- README.md
|
327
|
+
- README_CI.md
|
327
328
|
- Rakefile
|
328
329
|
- appmap.gemspec
|
329
330
|
- appmap.yml
|
@@ -334,7 +335,6 @@ files:
|
|
334
335
|
- examples/mock_webapp/lib/mock_webapp/controller.rb
|
335
336
|
- examples/mock_webapp/lib/mock_webapp/request.rb
|
336
337
|
- examples/mock_webapp/lib/mock_webapp/user.rb
|
337
|
-
- exe/appmap
|
338
338
|
- ext/appmap/appmap.c
|
339
339
|
- ext/appmap/extconf.rb
|
340
340
|
- lib/appmap.rb
|
@@ -346,6 +346,8 @@ files:
|
|
346
346
|
- lib/appmap/config.rb
|
347
347
|
- lib/appmap/cucumber.rb
|
348
348
|
- lib/appmap/event.rb
|
349
|
+
- lib/appmap/handler/function.rb
|
350
|
+
- lib/appmap/handler/net_http.rb
|
349
351
|
- lib/appmap/hook.rb
|
350
352
|
- lib/appmap/hook/method.rb
|
351
353
|
- lib/appmap/metadata.rb
|
@@ -379,16 +381,19 @@ files:
|
|
379
381
|
- lore/public/stylesheets/style.css
|
380
382
|
- package-lock.json
|
381
383
|
- package.json
|
384
|
+
- release.sh
|
382
385
|
- spec/abstract_controller_base_spec.rb
|
383
386
|
- spec/class_map_spec.rb
|
384
387
|
- spec/config_spec.rb
|
385
388
|
- spec/fixtures/hook/attr_accessor.rb
|
386
389
|
- spec/fixtures/hook/compare.rb
|
387
390
|
- spec/fixtures/hook/constructor.rb
|
391
|
+
- spec/fixtures/hook/custom_instance_method.rb
|
388
392
|
- spec/fixtures/hook/exception_method.rb
|
389
393
|
- spec/fixtures/hook/exclude.rb
|
390
394
|
- spec/fixtures/hook/instance_method.rb
|
391
395
|
- spec/fixtures/hook/labels.rb
|
396
|
+
- spec/fixtures/hook/method_named_call.rb
|
392
397
|
- spec/fixtures/hook/singleton_method.rb
|
393
398
|
- spec/fixtures/rack_users_app/.dockerignore
|
394
399
|
- spec/fixtures/rack_users_app/.gitignore
|
@@ -546,11 +551,11 @@ files:
|
|
546
551
|
- spec/open_spec.rb
|
547
552
|
- spec/rails_spec_helper.rb
|
548
553
|
- spec/railtie_spec.rb
|
554
|
+
- spec/record_net_http_spec.rb
|
549
555
|
- spec/record_sql_rails_pg_spec.rb
|
550
556
|
- spec/remote_recording_spec.rb
|
551
557
|
- spec/spec_helper.rb
|
552
558
|
- spec/util_spec.rb
|
553
|
-
- test/cli_test.rb
|
554
559
|
- test/cucumber_test.rb
|
555
560
|
- test/expectations/openssl_test_key_sign1.json
|
556
561
|
- test/expectations/openssl_test_key_sign2.json
|
@@ -600,7 +605,7 @@ homepage: https://github.com/applandinc/appmap-ruby
|
|
600
605
|
licenses:
|
601
606
|
- MIT
|
602
607
|
metadata: {}
|
603
|
-
post_install_message:
|
608
|
+
post_install_message:
|
604
609
|
rdoc_options: []
|
605
610
|
require_paths:
|
606
611
|
- lib
|
@@ -615,8 +620,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
615
620
|
- !ruby/object:Gem::Version
|
616
621
|
version: '0'
|
617
622
|
requirements: []
|
618
|
-
rubygems_version: 3.0.
|
619
|
-
signing_key:
|
623
|
+
rubygems_version: 3.0.8
|
624
|
+
signing_key:
|
620
625
|
specification_version: 4
|
621
626
|
summary: Record the operation of a Ruby program, using the AppLand 'AppMap' format.
|
622
627
|
test_files: []
|
data/exe/appmap
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'gli'
|
5
|
-
|
6
|
-
ENV['APPMAP_INITIALIZE'] = 'false'
|
7
|
-
|
8
|
-
require 'appmap'
|
9
|
-
require 'appmap/version'
|
10
|
-
|
11
|
-
# AppMap CLI.
|
12
|
-
module AppMap
|
13
|
-
class App
|
14
|
-
extend GLI::App
|
15
|
-
|
16
|
-
program_desc 'AppMap client'
|
17
|
-
|
18
|
-
version AppMap::VERSION
|
19
|
-
|
20
|
-
subcommand_option_handling :normal
|
21
|
-
arguments :strict
|
22
|
-
preserve_argv true
|
23
|
-
|
24
|
-
class << self
|
25
|
-
protected
|
26
|
-
|
27
|
-
def default_appmap_file
|
28
|
-
ENV['APPMAP_FILE'] || 'appmap.json'
|
29
|
-
end
|
30
|
-
|
31
|
-
def output_file_flag(c, default_value: nil)
|
32
|
-
c.desc 'Name of the output file'
|
33
|
-
c.long_desc <<~DESC
|
34
|
-
Use a single dash '-' for stdout.
|
35
|
-
DESC
|
36
|
-
c.default_value default_value if default_value
|
37
|
-
c.arg_name 'filename'
|
38
|
-
c.flag %i[o output]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
desc 'AppMap configuration file name'
|
43
|
-
default_value ENV['APPMAP_CONFIG'] || 'appmap.yml'
|
44
|
-
arg_name 'filename'
|
45
|
-
flag %i[c config]
|
46
|
-
|
47
|
-
desc 'Record the execution of a program and generate an AppMap.'
|
48
|
-
arg_name 'program'
|
49
|
-
command :record do |c|
|
50
|
-
output_file_flag(c, default_value: default_appmap_file)
|
51
|
-
|
52
|
-
c.action do |_, _, args|
|
53
|
-
# My subcommand name
|
54
|
-
ARGV.shift
|
55
|
-
|
56
|
-
# Consume the :output option, if provided
|
57
|
-
if %w[-o --output].find { |arg_name| ARGV[0] == arg_name.to_s }
|
58
|
-
ARGV.shift
|
59
|
-
ARGV.shift
|
60
|
-
end
|
61
|
-
|
62
|
-
# Name of the program to execute. GLI will ensure that it's present.
|
63
|
-
program = args.shift or help_now!("'program' argument is required")
|
64
|
-
|
65
|
-
# Also pop the program name from ARGV, because the command will use raw ARGV
|
66
|
-
# to load the extra arguments into this Ruby process.
|
67
|
-
ARGV.shift
|
68
|
-
|
69
|
-
require 'appmap/command/record'
|
70
|
-
AppMap::Command::Record.new(@config, program).perform do |version, metadata, class_map, events|
|
71
|
-
@output_file.write JSON.generate(version: version,
|
72
|
-
metadata: metadata,
|
73
|
-
classMap: class_map,
|
74
|
-
events: events)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
desc 'Calculate and print statistics of scenario files.'
|
80
|
-
arg_name 'filename'
|
81
|
-
command :stats do |c|
|
82
|
-
output_file_flag(c, default_value: '-')
|
83
|
-
|
84
|
-
c.desc 'Display format for the result (text | json)'
|
85
|
-
c.default_value 'text'
|
86
|
-
c.flag %i[f format]
|
87
|
-
|
88
|
-
c.desc 'Maximum number of lines to display for each stat'
|
89
|
-
c.flag %i[l limit]
|
90
|
-
|
91
|
-
c.action do |_, options, args|
|
92
|
-
require 'appmap/command/stats'
|
93
|
-
|
94
|
-
limit = options[:limit].to_i if options[:limit]
|
95
|
-
|
96
|
-
# Name of the file to analyze. GLI will ensure that it's present.
|
97
|
-
filenames = args
|
98
|
-
help_now!("'filename' argument is required") if filenames.empty?
|
99
|
-
|
100
|
-
require 'appmap/algorithm/stats'
|
101
|
-
result = filenames.inject(::AppMap::Algorithm::Stats::Result.new([], [])) do |stats_result, filename|
|
102
|
-
appmap = begin
|
103
|
-
JSON.parse(File.read(filename))
|
104
|
-
rescue JSON::ParserError
|
105
|
-
STDERR.puts "#{filename} is not valid JSON : #{$!}"
|
106
|
-
nil
|
107
|
-
end
|
108
|
-
stats_result.tap do
|
109
|
-
if appmap
|
110
|
-
limit = options[:limit].to_i if options[:limit]
|
111
|
-
stats_for_file = AppMap::Command::Stats.new(appmap).perform(limit: limit)
|
112
|
-
stats_result.merge!(stats_for_file)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
result.sort!
|
118
|
-
result.limit!(limit) if limit
|
119
|
-
|
120
|
-
display = case options[:format]
|
121
|
-
when 'json'
|
122
|
-
JSON.pretty_generate(result.as_json)
|
123
|
-
else
|
124
|
-
result.as_text
|
125
|
-
end
|
126
|
-
@output_file.write display
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
pre do |global, _, options, _|
|
131
|
-
@config = interpret_config_option(global[:config])
|
132
|
-
@output_file = interpret_output_file_option(options[:output])
|
133
|
-
|
134
|
-
true
|
135
|
-
end
|
136
|
-
|
137
|
-
class << self
|
138
|
-
protected
|
139
|
-
|
140
|
-
def interpret_config_option(fname)
|
141
|
-
AppMap.initialize fname
|
142
|
-
end
|
143
|
-
|
144
|
-
def interpret_output_file_option(file_name)
|
145
|
-
Hash.new { |_, fname| -> { File.new(fname, 'w') } }.tap do |open_output_file|
|
146
|
-
open_output_file[nil] = -> { nil }
|
147
|
-
open_output_file['-'] = -> { $stdout }
|
148
|
-
end[file_name].call
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
exit AppMap::App.run(ARGV)
|