haplo 2.5.1-java → 2.5.5-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/haplo.gemspec +2 -2
- data/lib/CertificateBundle.pem +1114 -1852
- data/lib/debuggers.rb +263 -0
- data/lib/notifications.rb +6 -0
- data/lib/plugin_tool.rb +31 -1
- data/lib/run.rb +1 -0
- data/lib/server.rb +8 -2
- data/lib/version.txt +1 -1
- metadata +4 -3
data/lib/debuggers.rb
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
# Haplo Plugin Tool http://docs.haplo.org/dev/tool/plugin
|
2
|
+
# (c) Haplo Services Ltd 2006 - 2016 http://www.haplo-services.com
|
3
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
4
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
5
|
+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
6
|
+
|
7
|
+
|
8
|
+
module PluginTool
|
9
|
+
|
10
|
+
@@profile_output = nil
|
11
|
+
|
12
|
+
def self.request_profile(options)
|
13
|
+
output_file = $stdout
|
14
|
+
close_output_file = false
|
15
|
+
if options.profile_file
|
16
|
+
output_file = File.open(options.profile_file, "a")
|
17
|
+
close_output_file = true
|
18
|
+
end
|
19
|
+
|
20
|
+
formatter = nil
|
21
|
+
case options.profile_format || 'tree'
|
22
|
+
when 'tree'
|
23
|
+
@@profile_output = ProfilerFormatterTree.new(output_file)
|
24
|
+
when 'raw'
|
25
|
+
@@profile_output = ProfilerFormatterRaw.new(output_file)
|
26
|
+
else
|
27
|
+
puts "Unknown profiler format: #{options.profile_format}"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
if 'OK' == PluginTool.post("/api/development-plugin-loader/debugger-profile-start", {:min => options.profile})
|
32
|
+
puts "JavaScript profiler started."
|
33
|
+
else
|
34
|
+
puts "Error starting JavaScript profiler."
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
at_exit do
|
38
|
+
puts
|
39
|
+
puts "Disabling JavaScript profiler..."
|
40
|
+
PluginTool.post("/api/development-plugin-loader/debugger-profile-stop")
|
41
|
+
puts "JavaScript profiler disabled."
|
42
|
+
output_file.close if close_output_file
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ProfilerFormatter
|
47
|
+
def initialize(output_file)
|
48
|
+
@output_file = output_file
|
49
|
+
end
|
50
|
+
def format(report)
|
51
|
+
_format(report, @output_file)
|
52
|
+
@output_file.flush
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class ProfilerFormatterRaw < ProfilerFormatter
|
57
|
+
def _format(report, output_file)
|
58
|
+
output_file.write(report)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class ProfilerFormatterTree < ProfilerFormatter
|
63
|
+
def _format(report, output_file)
|
64
|
+
report.split("\n").each do |line|
|
65
|
+
depth, time, percent, count, position = line.split("\t")
|
66
|
+
if depth == 'REPORT'
|
67
|
+
output_file.write("PROFILE -- #{Time.new(time)}\n")
|
68
|
+
elsif depth == 'OMIT'
|
69
|
+
output_file.write((" "*time.to_i)+"... children omitted\n")
|
70
|
+
else
|
71
|
+
output_file.write((" "*depth.to_i)+"#{percent} #{count} #{time.to_i / 1000000} #{position}\n")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.profiler_handle_report(report)
|
78
|
+
if @@profile_output
|
79
|
+
@@profile_output.format(report)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# -------------------------------------------------------------------------
|
84
|
+
|
85
|
+
def self.request_coverage(options)
|
86
|
+
|
87
|
+
format = options.coverage_format || 'raw'
|
88
|
+
if format != 'raw'
|
89
|
+
puts "Unknown coverage format: #{format}"
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
|
93
|
+
if 'OK' == PluginTool.post("/api/development-plugin-loader/debugger-coverage-start")
|
94
|
+
puts "Coverage capture started."
|
95
|
+
else
|
96
|
+
puts "Error starting coverage capture."
|
97
|
+
exit 1
|
98
|
+
end
|
99
|
+
|
100
|
+
at_exit do
|
101
|
+
coverage = PluginTool.post("/api/development-plugin-loader/debugger-coverage-stop")
|
102
|
+
# TODO: Check errors
|
103
|
+
File.open(options.coverage_file, "w") { |f| f.write coverage }
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
# -------------------------------------------------------------------------
|
111
|
+
|
112
|
+
module DebugAdapterProtocolTunnel
|
113
|
+
|
114
|
+
@@dap_plugins = nil
|
115
|
+
@@dap_debugger_option = nil
|
116
|
+
@@dap_server = nil
|
117
|
+
@@dap_connection = nil
|
118
|
+
|
119
|
+
def self.prepare(plugins, options)
|
120
|
+
@@dap_plugins = plugins
|
121
|
+
@@dap_debugger_option = options.debugger
|
122
|
+
raise "BAD DEBUGGER OPTION #{@@dap_debugger_option}" unless @@dap_debugger_option =~ /\A(\d+)\z/
|
123
|
+
@@dap_server = TCPServer.new("127.0.0.1", @@dap_debugger_option.to_i)
|
124
|
+
Thread.new do
|
125
|
+
while true
|
126
|
+
connection = @@dap_server.accept
|
127
|
+
if connection
|
128
|
+
if @@dap_connection
|
129
|
+
connection.close
|
130
|
+
else
|
131
|
+
@@dap_connection = DAPConnection.new(connection, @@dap_plugins)
|
132
|
+
Thread.new do
|
133
|
+
@@dap_connection.run
|
134
|
+
_stop_remote_debugger()
|
135
|
+
@@dap_connection = nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
rescue => e
|
141
|
+
# ignore
|
142
|
+
end
|
143
|
+
at_exit do
|
144
|
+
@@dap_server.close
|
145
|
+
@@dap_connection.close if @@dap_connection
|
146
|
+
_stop_remote_debugger()
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def self._stop_remote_debugger
|
151
|
+
puts "DEBUGGER: Stopping remote debugger..."
|
152
|
+
result = PluginTool.post("/api/development-plugin-loader/debugger-dap-stop")
|
153
|
+
if result == 'OK'
|
154
|
+
puts "DEBUGGER: Remote debugger stopped."
|
155
|
+
else
|
156
|
+
puts "DEBUGGER: Error stopping remote debugger, application server may be in non-functioning state."
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.log_message_from_server(text)
|
161
|
+
if @@dap_connection
|
162
|
+
@@dap_connection._write({
|
163
|
+
'type' => 'event',
|
164
|
+
'event' => 'output',
|
165
|
+
'body' => {
|
166
|
+
'category' => 'console',
|
167
|
+
'output' => text+"\n"
|
168
|
+
}
|
169
|
+
})
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.dap_message_from_server(json)
|
174
|
+
if @@dap_connection
|
175
|
+
@@dap_connection._write(JSON.parse(json))
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class DAPConnection
|
180
|
+
def initialize(connection, plugins)
|
181
|
+
@connection = connection
|
182
|
+
@plugins = plugins
|
183
|
+
@running = false
|
184
|
+
@next_seq = 1
|
185
|
+
@write_mutex = Mutex.new
|
186
|
+
@_dump_messages = (ENV['HAPLO_DAP_DEBUG'] == '1')
|
187
|
+
end
|
188
|
+
|
189
|
+
def close
|
190
|
+
begin
|
191
|
+
@connection.close
|
192
|
+
rescue => e
|
193
|
+
# ignore any errors
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def run
|
198
|
+
begin
|
199
|
+
run2
|
200
|
+
rescue => e
|
201
|
+
puts "DEBUGGER: Local connection closed"
|
202
|
+
end
|
203
|
+
self.close
|
204
|
+
end
|
205
|
+
|
206
|
+
def run2
|
207
|
+
@running = true
|
208
|
+
have_initialized = false
|
209
|
+
while @running
|
210
|
+
header = @connection.readline
|
211
|
+
blank = @connection.readline
|
212
|
+
if header =~ /\Acontent-length:\s+(\d+)\r\n\z/i && blank == "\r\n"
|
213
|
+
body = @connection.read($1.to_i)
|
214
|
+
message = JSON.parse(body)
|
215
|
+
puts "DAP READ: #{JSON.pretty_generate(message)}\n" if @_dump_messages
|
216
|
+
unless have_initialized
|
217
|
+
if message['type'] == 'request' && message['command'] == 'initialize'
|
218
|
+
puts "DEBUGGER: Local connection from #{message['arguments']['clientName']} (#{message['arguments']['clientID']})\nDEBUGGER: Starting remote debugger..."
|
219
|
+
plugin_locations = {}
|
220
|
+
@plugins.each { |p| plugin_locations[p.name] = p.plugin_dir }
|
221
|
+
start_response = PluginTool.post("/api/development-plugin-loader/debugger-dap-start", {
|
222
|
+
:plugin_locations => JSON.generate(plugin_locations)
|
223
|
+
})
|
224
|
+
unless start_response =~ /\ATOKEN: (.+)\z/
|
225
|
+
raise "Remote debugger failed to start"
|
226
|
+
end
|
227
|
+
@token = $1
|
228
|
+
puts "DEBUGGER: Remote debugger started."
|
229
|
+
have_initialized = true
|
230
|
+
else
|
231
|
+
raise "Expected initialize message after DAP connection"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
# TODO: Send messages in another thread, so that they can be batched together
|
235
|
+
message_response = PluginTool.post_with_json_response("/api/development-plugin-loader/debugger-dap-messages", {
|
236
|
+
:token => @token,
|
237
|
+
:messages => JSON.generate([message])
|
238
|
+
})
|
239
|
+
if message_response['error']
|
240
|
+
puts "DEBUGGER: Server responded with error: #{message_response['error']}"
|
241
|
+
else
|
242
|
+
message_response['messages'].each do |response|
|
243
|
+
_write(response) if response
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def _write(message)
|
251
|
+
@write_mutex.synchronize do
|
252
|
+
m = {'seq' => @next_seq}
|
253
|
+
@next_seq += 1
|
254
|
+
m.merge!(message)
|
255
|
+
puts "DAP WRITE: #{JSON.pretty_generate(m)}\n" if @_dump_messages
|
256
|
+
msg_json = JSON.generate(m)
|
257
|
+
@connection.write("Content-Length: #{msg_json.bytesize}\r\n\r\n")
|
258
|
+
@connection.write(msg_json)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
data/lib/notifications.rb
CHANGED
@@ -69,6 +69,12 @@ module PluginTool
|
|
69
69
|
when 'log '
|
70
70
|
# Output from console.log()
|
71
71
|
puts "LOG:#{data}"
|
72
|
+
DebugAdapterProtocolTunnel.log_message_from_server(data)
|
73
|
+
when 'DAP1'
|
74
|
+
DebugAdapterProtocolTunnel.dap_message_from_server(data)
|
75
|
+
when 'prof'
|
76
|
+
# Profiler report
|
77
|
+
PluginTool.profiler_handle_report(data)
|
72
78
|
when 'audt'
|
73
79
|
decoded = JSON.parse(data)
|
74
80
|
kind = decoded.find { |name,value| name == 'auditEntryType' }.last
|
data/lib/plugin_tool.rb
CHANGED
@@ -23,7 +23,7 @@ NO_DEPENDENCY_COMMANDS.delete('list')
|
|
23
23
|
PLUGIN_SEARCH_PATH = ['.']
|
24
24
|
|
25
25
|
# Options for passing to plugin objects
|
26
|
-
options = Struct.new(:output, :minimiser, :no_dependency, :with_dependency, :exclude_with_prefix, :no_console, :show_system_audit, :args, :force, :turbo, :server_substring, :restrict_to_app_id).new
|
26
|
+
options = Struct.new(:output, :minimiser, :no_dependency, :with_dependency, :exclude_with_prefix, :no_console, :show_system_audit, :args, :force, :turbo, :debugger, :profile, :profile_file, :profile_format, :coverage_file, :coverage_format, :server_substring, :restrict_to_app_id).new
|
27
27
|
|
28
28
|
# Parse arguments
|
29
29
|
show_help = false
|
@@ -37,6 +37,12 @@ opts = GetoptLong.new(
|
|
37
37
|
['--server', '-s', GetoptLong::REQUIRED_ARGUMENT],
|
38
38
|
['--force', GetoptLong::NO_ARGUMENT],
|
39
39
|
['--turbo', GetoptLong::NO_ARGUMENT],
|
40
|
+
['--debugger', GetoptLong::REQUIRED_ARGUMENT],
|
41
|
+
['--profile', GetoptLong::REQUIRED_ARGUMENT],
|
42
|
+
['--profile-file', GetoptLong::REQUIRED_ARGUMENT],
|
43
|
+
['--profile-format', GetoptLong::REQUIRED_ARGUMENT],
|
44
|
+
['--coverage-file', GetoptLong::REQUIRED_ARGUMENT],
|
45
|
+
['--coverage-format', GetoptLong::REQUIRED_ARGUMENT],
|
40
46
|
['--output', GetoptLong::REQUIRED_ARGUMENT],
|
41
47
|
['--pack-restrict-to-app-id', GetoptLong::REQUIRED_ARGUMENT],
|
42
48
|
['--no-console', '-n', GetoptLong::NO_ARGUMENT],
|
@@ -72,6 +78,18 @@ opts.each do |opt, argument|
|
|
72
78
|
options.force = true
|
73
79
|
when '--turbo'
|
74
80
|
options.turbo = true
|
81
|
+
when '--debugger'
|
82
|
+
options.debugger = argument
|
83
|
+
when '--profile'
|
84
|
+
options.profile = argument.to_f
|
85
|
+
when '--profile-file'
|
86
|
+
options.profile_file = argument
|
87
|
+
when '--profile-format'
|
88
|
+
options.profile_format = argument
|
89
|
+
when '--coverage-file'
|
90
|
+
options.coverage_file = argument
|
91
|
+
when '--coverage-format'
|
92
|
+
options.coverage_format = argument
|
75
93
|
end
|
76
94
|
end
|
77
95
|
# Handle rest of command line -- first arg is the command, the rest are passed on
|
@@ -325,6 +343,13 @@ end
|
|
325
343
|
unless LOCAL_ONLY_COMMANDS[PLUGIN_TOOL_COMMAND]
|
326
344
|
PluginTool.custom_behaviour.server_ready(plugins, PLUGIN_TOOL_COMMAND, options)
|
327
345
|
plugins.each { |p| p.setup_for_server }
|
346
|
+
|
347
|
+
if options.profile
|
348
|
+
PluginTool.request_profile(options)
|
349
|
+
end
|
350
|
+
if options.coverage_file
|
351
|
+
PluginTool.request_coverage(options)
|
352
|
+
end
|
328
353
|
end
|
329
354
|
|
330
355
|
# Run the command
|
@@ -343,6 +368,11 @@ PluginTool.start_syntax_check
|
|
343
368
|
# Notifications support (including console)
|
344
369
|
PluginTool.start_notifications(options) unless options.no_console
|
345
370
|
|
371
|
+
# If the debugger is requested, open the listening socket. Debugger initialised on connection.
|
372
|
+
if options.debugger
|
373
|
+
DebugAdapterProtocolTunnel.prepare(plugins, options)
|
374
|
+
end
|
375
|
+
|
346
376
|
# Open watcher
|
347
377
|
watcher = PluginTool.make_watcher(plugins.map { |p| p.plugin_dir })
|
348
378
|
|
data/lib/run.rb
CHANGED
@@ -65,6 +65,7 @@ require "#{PLUGIN_TOOL_ROOT_DIR}/lib/syntax_checking.rb"
|
|
65
65
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/notifications.rb"
|
66
66
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/plugin.rb"
|
67
67
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/new_plugin.rb"
|
68
|
+
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/debuggers.rb"
|
68
69
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/misc.rb"
|
69
70
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/watchers.rb"
|
70
71
|
require "#{PLUGIN_TOOL_ROOT_DIR}/lib/minimise.rb"
|
data/lib/server.rb
CHANGED
@@ -11,6 +11,7 @@ module PluginTool
|
|
11
11
|
@@server_hostname = hostname
|
12
12
|
@@server_port = port
|
13
13
|
@@server_key = key
|
14
|
+
@@request_mutex = Mutex.new
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.get_server_hostname
|
@@ -50,6 +51,7 @@ module PluginTool
|
|
50
51
|
http.use_ssl = true
|
51
52
|
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
52
53
|
http.cert_store = ssl_ca
|
54
|
+
http.read_timeout = 3600 # 1 hour, in case a test runs for a very long time
|
53
55
|
http.start
|
54
56
|
http
|
55
57
|
end
|
@@ -75,7 +77,9 @@ module PluginTool
|
|
75
77
|
http = get_http
|
76
78
|
request = Net::HTTP::Get.new(path)
|
77
79
|
setup_request(request)
|
78
|
-
|
80
|
+
@@request_mutex.synchronize do
|
81
|
+
http.request(request).body
|
82
|
+
end
|
79
83
|
end
|
80
84
|
|
81
85
|
def self.get_with_json_response(path)
|
@@ -116,7 +120,9 @@ EOF
|
|
116
120
|
body << "--#{boundary}--\r"
|
117
121
|
request.body = body
|
118
122
|
end
|
119
|
-
|
123
|
+
@@request_mutex.synchronize do
|
124
|
+
http.request(request).body
|
125
|
+
end
|
120
126
|
end
|
121
127
|
|
122
128
|
def self.post_with_json_response(path, params = nil, files = nil)
|
data/lib/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
64e61a4
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haplo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.5.
|
4
|
+
version: 2.5.5
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Haplo Services
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Development tools for developing Haplo plugins, see https://haplo.org
|
14
14
|
email: client.services@haplo-services.com
|
@@ -24,6 +24,7 @@ files:
|
|
24
24
|
- lib/auth.rb
|
25
25
|
- lib/check.rb
|
26
26
|
- lib/custom.rb
|
27
|
+
- lib/debuggers.rb
|
27
28
|
- lib/haplo-templates.jar
|
28
29
|
- lib/hmac.rb
|
29
30
|
- lib/hsvt_parser_config.rb
|
@@ -70,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
71
|
version: '0'
|
71
72
|
requirements: []
|
72
73
|
rubyforge_project:
|
73
|
-
rubygems_version: 2.7.
|
74
|
+
rubygems_version: 2.7.9
|
74
75
|
signing_key:
|
75
76
|
specification_version: 4
|
76
77
|
summary: Haplo Plugin Tool
|