diver_down 0.0.1.alpha14 → 0.0.1.alpha15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/diver_down_web +2 -3
- data/lib/diver_down/version.rb +1 -1
- data/lib/diver_down/web/action.rb +92 -105
- data/lib/diver_down/web/definition_filter.rb +112 -0
- data/lib/diver_down/web/definition_module_dependencies.rb +79 -0
- data/lib/diver_down/web/definition_to_dot.rb +50 -105
- data/lib/diver_down/web/metadata/source_metadata.rb +14 -13
- data/lib/diver_down/web/metadata.rb +6 -1
- data/lib/diver_down/web.rb +44 -29
- data/web/assets/DyDCovOQ.css +1 -0
- data/web/assets/bundle.js +127 -134
- data/web/index.html +1 -1
- metadata +6 -5
- data/lib/diver_down/web/module_sources_filter.rb +0 -54
- data/web/assets/CFQbqqGu.css +0 -1
@@ -7,7 +7,6 @@ module DiverDown
|
|
7
7
|
class Web
|
8
8
|
class DefinitionToDot
|
9
9
|
ATTRIBUTE_DELIMITER = ' '
|
10
|
-
MODULE_DELIMITER = '::'
|
11
10
|
|
12
11
|
# Between modules is prominently distanced
|
13
12
|
MODULE_MINLEN = 3
|
@@ -31,18 +30,12 @@ module DiverDown
|
|
31
30
|
private
|
32
31
|
|
33
32
|
def source_to_h
|
34
|
-
modules = metadata.source(data.source_name).modules.map do
|
35
|
-
{
|
36
|
-
module_name: _1,
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
33
|
{
|
41
34
|
id:,
|
42
35
|
type: 'source',
|
43
36
|
source_name: data.source_name,
|
44
37
|
memo: metadata.source(data.source_name).memo,
|
45
|
-
|
38
|
+
module: metadata.source(data.source_name).module,
|
46
39
|
}
|
47
40
|
end
|
48
41
|
|
@@ -68,11 +61,7 @@ module DiverDown
|
|
68
61
|
{
|
69
62
|
id:,
|
70
63
|
type: 'module',
|
71
|
-
|
72
|
-
{
|
73
|
-
module_name: _1,
|
74
|
-
}
|
75
|
-
end,
|
64
|
+
module: data,
|
76
65
|
}
|
77
66
|
end
|
78
67
|
end
|
@@ -100,13 +89,13 @@ module DiverDown
|
|
100
89
|
|
101
90
|
# @param module_names [Array<String>]
|
102
91
|
# @return [String]
|
103
|
-
def
|
104
|
-
issued_metadata = @to_h.values.find { _1.type == :module && _1.data ==
|
92
|
+
def issue_module_id(modulee)
|
93
|
+
issued_metadata = @to_h.values.find { _1.type == :module && _1.data == modulee }
|
105
94
|
|
106
95
|
if issued_metadata
|
107
96
|
issued_metadata.id
|
108
97
|
else
|
109
|
-
build_dot_metadata_and_return_id(:module,
|
98
|
+
build_dot_metadata_and_return_id(:module, modulee)
|
110
99
|
end
|
111
100
|
end
|
112
101
|
|
@@ -186,60 +175,45 @@ module DiverDown
|
|
186
175
|
dependency_map = Hash.new { |h, k| h[k] = Hash.new { |hi, ki| hi[ki] = [] } }
|
187
176
|
|
188
177
|
definition.sources.sort_by(&:source_name).each do |source|
|
189
|
-
|
190
|
-
next if
|
178
|
+
source_module = metadata.source(source.source_name).module
|
179
|
+
next if source_module.nil?
|
191
180
|
|
192
181
|
source.dependencies.each do |dependency|
|
193
|
-
|
194
|
-
next if
|
182
|
+
dependency_module = metadata.source(dependency.source_name).module
|
183
|
+
next if dependency_module.nil?
|
195
184
|
|
196
|
-
dependency_map[
|
185
|
+
dependency_map[source_module][dependency_module].push(dependency)
|
197
186
|
end
|
198
187
|
end
|
199
188
|
|
200
189
|
# Remove duplicated prefix modules
|
201
|
-
|
202
|
-
uniq_modules
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
indexes = (0..(specific_module_names.length - 1)).to_a
|
211
|
-
|
212
|
-
chain_yield(indexes) do |index, next_proc|
|
213
|
-
module_names = specific_module_names[0..index]
|
214
|
-
module_name = specific_module_names[index]
|
215
|
-
|
216
|
-
io.puts %(subgraph "#{escape_quote(module_label(module_names))}" {)
|
217
|
-
io.indented do
|
218
|
-
io.puts %(id="#{@dot_metadata_store.issue_modules_id(module_names)}")
|
219
|
-
io.puts %(label="#{escape_quote(module_name)}")
|
220
|
-
io.puts %("#{escape_quote(module_name)}" #{build_attributes(label: module_name, id: @dot_metadata_store.issue_modules_id(module_names))})
|
221
|
-
|
222
|
-
next_proc&.call
|
223
|
-
end
|
224
|
-
io.puts '}'
|
225
|
-
end
|
190
|
+
uniq_modules = [*dependency_map.keys, *dependency_map.values.map(&:keys).flatten].uniq.sort
|
191
|
+
uniq_modules.reject!(&:nil?)
|
192
|
+
|
193
|
+
uniq_modules.each do |modulee|
|
194
|
+
io.puts %(subgraph "#{escape_quote(module_label(modulee))}" {)
|
195
|
+
io.indented do
|
196
|
+
io.puts %(id="#{@dot_metadata_store.issue_module_id(modulee)}")
|
197
|
+
io.puts %(label="#{escape_quote(modulee)}")
|
198
|
+
io.puts %("#{escape_quote(modulee)}" #{build_attributes(label: modulee, id: @dot_metadata_store.issue_module_id(modulee))})
|
226
199
|
end
|
227
|
-
|
228
|
-
io.write buf.string
|
200
|
+
io.puts '}'
|
229
201
|
end
|
230
202
|
|
231
|
-
dependency_map.each do |
|
232
|
-
|
203
|
+
dependency_map.keys.sort_by(&:to_s).each do |from_module|
|
204
|
+
dependency_map.fetch(from_module).keys.sort_by(&:to_s).each do |to_module|
|
205
|
+
all_dependencies = dependency_map.fetch(from_module).fetch(to_module)
|
206
|
+
|
233
207
|
# Do not render standalone source
|
234
208
|
# Do not render self-dependency
|
235
|
-
next if
|
209
|
+
next if from_module.nil? || to_module.empty? || from_module == to_module
|
236
210
|
|
237
211
|
dependencies = DiverDown::Definition::Dependency.combine(*all_dependencies)
|
238
212
|
|
239
213
|
dependencies.each do
|
240
214
|
attributes = {}
|
241
|
-
ltail = module_label(
|
242
|
-
lhead = module_label(
|
215
|
+
ltail = module_label(from_module)
|
216
|
+
lhead = module_label(to_module)
|
243
217
|
|
244
218
|
# Already rendered dependencies between modules
|
245
219
|
# Add the dependency to the edge of the compound
|
@@ -259,7 +233,7 @@ module DiverDown
|
|
259
233
|
minlen: MODULE_MINLEN
|
260
234
|
)
|
261
235
|
|
262
|
-
io.write(%("#{escape_quote(
|
236
|
+
io.write(%("#{escape_quote(from_module)}" -> "#{escape_quote(to_module)}"))
|
263
237
|
io.write(%( #{build_attributes(**attributes)}), indent: false) unless attributes.empty?
|
264
238
|
io.write("\n")
|
265
239
|
end
|
@@ -268,46 +242,38 @@ module DiverDown
|
|
268
242
|
end
|
269
243
|
|
270
244
|
def render_sources
|
271
|
-
# Hash{
|
272
|
-
# Hash{
|
273
|
-
|
274
|
-
metadata.source(source.source_name).
|
245
|
+
# Hash{ module => sources }
|
246
|
+
# Hash{ String => Array<DiverDown::Definition::Source> }
|
247
|
+
by_module = definition.sources.group_by do |source|
|
248
|
+
metadata.source(source.source_name).module
|
275
249
|
end
|
276
250
|
|
277
251
|
# Render subgraph for each module and its sources second
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
# Render dependencies last
|
282
|
-
definition.sources.sort_by(&:source_name).each do |source|
|
283
|
-
insert_dependencies(source)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
def render_nested_modules_sources(by_modules, nested_modules, prefix = [])
|
288
|
-
nested_modules.each do |module_name, next_nested_modules|
|
289
|
-
module_names = prefix + [module_name].compact
|
290
|
-
sources = (by_modules[module_names] || []).sort_by(&:source_name)
|
252
|
+
by_module.keys.sort_by(&:to_s).each do |modulee|
|
253
|
+
sources = by_module.fetch(modulee).sort_by(&:source_name)
|
291
254
|
|
292
|
-
if
|
255
|
+
if modulee.nil?
|
293
256
|
sources.each do |source|
|
294
257
|
io.puts build_source_node(source)
|
295
258
|
end
|
296
259
|
else
|
297
|
-
io.puts %(subgraph "#{escape_quote(module_label(
|
260
|
+
io.puts %(subgraph "#{escape_quote(module_label(modulee))}" {)
|
298
261
|
io.indented do
|
299
|
-
io.puts %(id="#{@dot_metadata_store.
|
300
|
-
io.puts %(label="#{escape_quote(
|
262
|
+
io.puts %(id="#{@dot_metadata_store.issue_module_id(modulee)}")
|
263
|
+
io.puts %(label="#{escape_quote(modulee)}")
|
301
264
|
|
302
265
|
sources.each do |source|
|
303
266
|
io.puts build_source_node(source)
|
304
267
|
end
|
305
|
-
|
306
|
-
render_nested_modules_sources(by_modules, next_nested_modules, module_names)
|
307
268
|
end
|
308
269
|
io.puts '}'
|
309
270
|
end
|
310
271
|
end
|
272
|
+
|
273
|
+
# Render dependencies last
|
274
|
+
definition.sources.sort_by(&:source_name).each do |source|
|
275
|
+
insert_dependencies(source)
|
276
|
+
end
|
311
277
|
end
|
312
278
|
|
313
279
|
def build_source_node(source)
|
@@ -317,8 +283,8 @@ module DiverDown
|
|
317
283
|
def insert_dependencies(source)
|
318
284
|
source.dependencies.each do
|
319
285
|
attributes = {}
|
320
|
-
ltail = module_label(
|
321
|
-
lhead = module_label(
|
286
|
+
ltail = module_label(metadata.source(source.source_name).module)
|
287
|
+
lhead = module_label(metadata.source(_1.source_name).module)
|
322
288
|
|
323
289
|
if @compound && (ltail || lhead)
|
324
290
|
# Rendering of dependencies between modules is done only once
|
@@ -343,7 +309,8 @@ module DiverDown
|
|
343
309
|
)
|
344
310
|
else
|
345
311
|
attributes.merge!(
|
346
|
-
id: @dot_metadata_store.issue_dependency_id(_1)
|
312
|
+
id: @dot_metadata_store.issue_dependency_id(_1),
|
313
|
+
minlen: MODULE_MINLEN
|
347
314
|
)
|
348
315
|
end
|
349
316
|
|
@@ -401,37 +368,15 @@ module DiverDown
|
|
401
368
|
@io = old_io
|
402
369
|
end
|
403
370
|
|
404
|
-
def module_label(
|
405
|
-
return if
|
371
|
+
def module_label(modulee)
|
372
|
+
return if modulee.nil?
|
406
373
|
|
407
|
-
"cluster_#{
|
374
|
+
"cluster_#{modulee}"
|
408
375
|
end
|
409
376
|
|
410
377
|
def escape_quote(string)
|
411
378
|
string.to_s.gsub(/"/, '\"')
|
412
379
|
end
|
413
|
-
|
414
|
-
# from [["A"], ["A", "B"], ["A", "C"], ["D"]] to { "A" => { "B" => {}, "C" => {} }, "D" => {} }
|
415
|
-
def array_to_hash(array)
|
416
|
-
hash = {}
|
417
|
-
array.each do |sub_array|
|
418
|
-
current_hash = hash
|
419
|
-
|
420
|
-
if sub_array.empty?
|
421
|
-
current_hash[nil] = {}
|
422
|
-
else
|
423
|
-
sub_array.each_with_index do |element, index|
|
424
|
-
if index == sub_array.length - 1
|
425
|
-
current_hash[element] = {}
|
426
|
-
else
|
427
|
-
current_hash[element] ||= {}
|
428
|
-
current_hash = current_hash[element]
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
end
|
433
|
-
hash
|
434
|
-
end
|
435
380
|
end
|
436
381
|
end
|
437
382
|
end
|
@@ -6,17 +6,16 @@ module DiverDown
|
|
6
6
|
class SourceMetadata
|
7
7
|
BLANK_MEMO = ''
|
8
8
|
BLANK_RE = /\A\s*\z/
|
9
|
-
BLANK_ARRAY = [].freeze
|
10
9
|
private_constant(:BLANK_MEMO)
|
11
10
|
private_constant(:BLANK_RE)
|
12
|
-
private_constant(:BLANK_ARRAY)
|
13
11
|
|
14
|
-
attr_reader :memo, :
|
12
|
+
attr_reader :memo, :module
|
15
13
|
|
16
14
|
# @param source_name [String]
|
17
|
-
|
15
|
+
# NOTE: `module` is a reserved keyword in Ruby
|
16
|
+
def initialize(memo: BLANK_MEMO, modulee: nil)
|
18
17
|
@memo = memo
|
19
|
-
@
|
18
|
+
@module = modulee
|
20
19
|
end
|
21
20
|
|
22
21
|
# @param memo [String]
|
@@ -25,17 +24,19 @@ module DiverDown
|
|
25
24
|
@memo = memo.strip
|
26
25
|
end
|
27
26
|
|
28
|
-
# @param
|
27
|
+
# @param modulee [String, nil]
|
29
28
|
# @return [void]
|
30
|
-
def
|
31
|
-
@
|
32
|
-
|
33
|
-
|
29
|
+
def module=(modulee)
|
30
|
+
@module = if modulee.nil? || BLANK_RE.match?(modulee)
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
modulee.strip
|
34
|
+
end
|
34
35
|
end
|
35
36
|
|
36
37
|
# @return [Boolean]
|
37
|
-
def
|
38
|
-
|
38
|
+
def module?
|
39
|
+
!@module.nil?
|
39
40
|
end
|
40
41
|
|
41
42
|
# @return [Hash]
|
@@ -43,7 +44,7 @@ module DiverDown
|
|
43
44
|
hash = {}
|
44
45
|
|
45
46
|
hash[:memo] = memo unless memo == BLANK_MEMO
|
46
|
-
hash[:
|
47
|
+
hash[:module] = @module unless @module.nil?
|
47
48
|
|
48
49
|
hash
|
49
50
|
end
|
@@ -54,7 +54,12 @@ module DiverDown
|
|
54
54
|
# NOTE: This is for backward compatibility. It will be removed in the future.
|
55
55
|
(loaded[:sources] || loaded || []).each do |source_name, source_hash|
|
56
56
|
source(source_name).memo = source_hash[:memo] if source_hash[:memo]
|
57
|
-
|
57
|
+
|
58
|
+
if source_hash[:modules].is_a?(Array)
|
59
|
+
source(source_name).module = source_hash[:modules][0]
|
60
|
+
elsif source_hash[:module]
|
61
|
+
source(source_name).module = source_hash[:module]
|
62
|
+
end
|
58
63
|
end
|
59
64
|
|
60
65
|
loaded[:source_alias]&.each do |alias_name, source_names|
|
data/lib/diver_down/web.rb
CHANGED
@@ -15,22 +15,28 @@ module DiverDown
|
|
15
15
|
require 'diver_down/web/indented_string_io'
|
16
16
|
require 'diver_down/web/definition_store'
|
17
17
|
require 'diver_down/web/definition_loader'
|
18
|
+
require 'diver_down/web/definition_module_dependencies'
|
18
19
|
require 'diver_down/web/source_alias_resolver'
|
19
|
-
require 'diver_down/web/
|
20
|
+
require 'diver_down/web/definition_filter'
|
20
21
|
|
21
22
|
# For development
|
22
23
|
autoload :DevServerMiddleware, 'diver_down/web/dev_server_middleware'
|
23
24
|
|
25
|
+
# @return [DiverDown::Web::DefinitionStore]
|
26
|
+
def self.store
|
27
|
+
@store ||= DiverDown::Web::DefinitionStore.new
|
28
|
+
end
|
29
|
+
|
24
30
|
# @param definition_dir [String]
|
25
31
|
# @param metadata [DiverDown::Web::Metadata]
|
26
32
|
# @param store [DiverDown::Web::DefinitionStore]
|
27
|
-
def initialize(definition_dir:, metadata
|
28
|
-
@store = store
|
33
|
+
def initialize(definition_dir:, metadata:)
|
29
34
|
@metadata = metadata
|
30
35
|
@files_server = Rack::Files.new(File.join(WEB_DIR))
|
31
36
|
|
32
37
|
definition_files = ::Dir["#{definition_dir}/**/*.{yml,yaml,msgpack,json}"].sort
|
33
38
|
@total_definition_files_size = definition_files.size
|
39
|
+
@action = nil
|
34
40
|
|
35
41
|
load_definition_files_on_thread(definition_files)
|
36
42
|
end
|
@@ -39,11 +45,14 @@ module DiverDown
|
|
39
45
|
# @return [Array[Integer, Hash, Array]]
|
40
46
|
def call(env)
|
41
47
|
request = Rack::Request.new(env)
|
42
|
-
|
48
|
+
|
49
|
+
if @action&.store.object_id != self.class.store.object_id
|
50
|
+
@action = DiverDown::Web::Action.new(store: self.class.store, metadata: @metadata)
|
51
|
+
end
|
43
52
|
|
44
53
|
case [request.request_method, request.path]
|
45
54
|
in ['GET', %r{\A/api/definitions\.json\z}]
|
46
|
-
action.definitions(
|
55
|
+
@action.definitions(
|
47
56
|
page: request.params['page']&.to_i || 1,
|
48
57
|
per: request.params['per']&.to_i || 100,
|
49
58
|
title: request.params['title'] || '',
|
@@ -51,51 +60,48 @@ module DiverDown
|
|
51
60
|
definition_group: request.params['definition_group'] || ''
|
52
61
|
)
|
53
62
|
in ['GET', %r{\A/api/sources\.json\z}]
|
54
|
-
action.sources
|
63
|
+
@action.sources
|
55
64
|
in ['GET', %r{\A/api/modules\.json\z}]
|
56
|
-
action.modules
|
57
|
-
in ['GET', %r{\A/api/modules/(?<
|
58
|
-
|
59
|
-
action.module(
|
60
|
-
in ['GET', %r{\A/api/module_definitions/(?<modules>.+)\.json\z}]
|
61
|
-
modules = CGI.unescape(Regexp.last_match[:modules]).split('/')
|
62
|
-
compound = request.params['compound'] == '1'
|
63
|
-
concentrate = request.params['concentrate'] == '1'
|
64
|
-
only_module = request.params['only_module'] == '1'
|
65
|
-
action.module_definition(compound, concentrate, only_module, modules)
|
65
|
+
@action.modules
|
66
|
+
in ['GET', %r{\A/api/modules/(?<modulee>[^/]+)\.json\z}]
|
67
|
+
modulee = CGI.unescape(Regexp.last_match[:modulee])
|
68
|
+
@action.module(modulee)
|
66
69
|
in ['GET', %r{\A/api/definitions/(?<bit_id>\d+)\.json\z}]
|
67
70
|
bit_id = Regexp.last_match[:bit_id].to_i
|
68
71
|
compound = request.params['compound'] == '1'
|
69
72
|
concentrate = request.params['concentrate'] == '1'
|
70
73
|
only_module = request.params['only_module'] == '1'
|
71
|
-
|
74
|
+
remove_internal_sources = request.params['remove_internal_sources'] == '1'
|
75
|
+
focus_modules = request.params['focus_modules'] || []
|
76
|
+
modules = request.params['modules'] || []
|
77
|
+
@action.combine_definitions(bit_id, compound, concentrate, only_module, remove_internal_sources, focus_modules, modules)
|
72
78
|
in ['GET', %r{\A/api/sources/(?<source>[^/]+)\.json\z}]
|
73
79
|
source = Regexp.last_match[:source]
|
74
|
-
action.source(source)
|
75
|
-
in ['POST', %r{\A/api/sources/(?<source>[^/]+)/
|
80
|
+
@action.source(source)
|
81
|
+
in ['POST', %r{\A/api/sources/(?<source>[^/]+)/module.json\z}]
|
76
82
|
source = Regexp.last_match[:source]
|
77
|
-
|
78
|
-
action.
|
83
|
+
modulee = request.params['module'] || ''
|
84
|
+
@action.set_module(source, modulee)
|
79
85
|
in ['POST', %r{\A/api/sources/(?<source>[^/]+)/memo.json\z}]
|
80
86
|
source = Regexp.last_match[:source]
|
81
87
|
memo = request.params['memo'] || ''
|
82
|
-
action.set_memo(source, memo)
|
88
|
+
@action.set_memo(source, memo)
|
83
89
|
in ['GET', %r{\A/api/pid\.json\z}]
|
84
|
-
action.pid
|
90
|
+
@action.pid
|
85
91
|
in ['GET', %r{\A/api/initialization_status\.json\z}]
|
86
|
-
action.initialization_status(@total_definition_files_size)
|
92
|
+
@action.initialization_status(@total_definition_files_size)
|
87
93
|
in ['GET', %r{\A/api/source_aliases\.json\z}]
|
88
|
-
action.source_aliases
|
94
|
+
@action.source_aliases
|
89
95
|
in ['POST', %r{\A/api/source_aliases\.json\z}]
|
90
96
|
alias_name = request.params['alias_name']
|
91
97
|
old_alias_name = request.params['old_alias_name'] # NOTE: nillable
|
92
98
|
source_names = request.params['source_names'] || []
|
93
99
|
|
94
|
-
action.update_source_alias(alias_name, old_alias_name, source_names)
|
100
|
+
@action.update_source_alias(alias_name, old_alias_name, source_names)
|
95
101
|
in ['GET', %r{\A/assets/}]
|
96
102
|
@files_server.call(env)
|
97
103
|
in ['GET', /\.json\z/], ['POST', /\.json\z/]
|
98
|
-
action.not_found
|
104
|
+
@action.not_found
|
99
105
|
else
|
100
106
|
@files_server.call(env.merge('PATH_INFO' => '/index.html'))
|
101
107
|
end
|
@@ -105,20 +111,29 @@ module DiverDown
|
|
105
111
|
|
106
112
|
def load_definition_files_on_thread(definition_files)
|
107
113
|
definition_loader = DiverDown::Web::DefinitionLoader.new
|
114
|
+
store = self.class.store
|
108
115
|
|
109
116
|
Thread.new do
|
110
117
|
loop do
|
111
118
|
break if definition_files.empty?
|
112
119
|
|
120
|
+
# If store is changed in test, stop loading.
|
121
|
+
break if store != self.class.store
|
122
|
+
|
113
123
|
definition_file = definition_files.shift
|
114
124
|
definition = definition_loader.load_file(definition_file)
|
115
125
|
|
116
126
|
# No needed to synchronize because this is executed on a single thread.
|
117
|
-
|
127
|
+
store.set(definition)
|
118
128
|
end
|
119
129
|
|
120
130
|
# Cache combined_definition
|
121
|
-
|
131
|
+
store.combined_definition
|
132
|
+
|
133
|
+
# For development
|
134
|
+
if ENV['DIVER_DOWN_DIR']
|
135
|
+
File.write(File.expand_path('../../tmp/combined_definition.yml', __dir__), store.combined_definition.to_h.to_yaml)
|
136
|
+
end
|
122
137
|
end
|
123
138
|
end
|
124
139
|
end
|