build-dependency 1.0.0

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.
@@ -0,0 +1,202 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ RSpec.describe Build::Dependency do
22
+ describe "valid dependency resolution" do
23
+ let(:a) do
24
+ Package.new.tap do |package|
25
+ package.provides 'apple' do
26
+ fruit ['apple']
27
+ end
28
+ end
29
+ end
30
+
31
+ let(:b) do
32
+ Package.new.tap do |package|
33
+ package.provides 'orange' do
34
+ fruit ['orange']
35
+ end
36
+ end
37
+ end
38
+
39
+ let(:c) do
40
+ Package.new.tap do |package|
41
+ package.provides 'fruit-juice' do
42
+ juice ['ice', 'cold']
43
+ end
44
+
45
+ package.depends 'apple'
46
+ package.depends 'orange'
47
+ end
48
+ end
49
+
50
+ it "should resolve direct dependency chain" do
51
+ chain = Build::Dependency::Chain.expand(['fruit-juice'], [a, b, c])
52
+ expect(chain.ordered.collect(&:first)).to be == [a, b, c]
53
+ expect(chain.unresolved).to be == []
54
+ end
55
+
56
+ let(:d) do
57
+ Package.new.tap do |package|
58
+ package.provides 'pie'
59
+ package.depends 'apple'
60
+ end
61
+ end
62
+
63
+ it "shouldn't include unrelated units" do
64
+ chain = Build::Dependency::Chain.expand(['pie'], [a, b, c, d])
65
+
66
+ expect(chain.unresolved).to be == []
67
+ expect(chain.ordered.collect(&:first)).to be == [a, d]
68
+ end
69
+ end
70
+
71
+ describe "incomplete dependency resolution" do
72
+ it "should report conflicts" do
73
+ apple = Package.new('apple')
74
+ apple.provides 'apple'
75
+ apple.provides 'fruit'
76
+
77
+ bananna = Package.new('bananna')
78
+ bananna.provides 'fruit'
79
+
80
+ salad = Package.new('salad')
81
+ salad.depends 'fruit'
82
+ salad.provides 'salad'
83
+
84
+ chain = Build::Dependency::Chain.new(['salad'], [apple, bananna, salad])
85
+ expect(chain.unresolved.first).to be == [Build::Dependency::Depends.new("fruit"), salad]
86
+ expect(chain.conflicts).to be == {Build::Dependency::Depends.new("fruit") => [apple, bananna]}
87
+
88
+ chain = Build::Dependency::Chain.new(['salad'], [apple, bananna, salad], ['apple'])
89
+ expect(chain.unresolved).to be == []
90
+ expect(chain.conflicts).to be == {}
91
+ end
92
+ end
93
+
94
+ describe "multiple provisions" do
95
+ let(:fruit) do
96
+ Package.new('fruit').tap do |package|
97
+ package.provides 'apple' do
98
+ end
99
+
100
+ package.provides 'orange' do
101
+ end
102
+ end
103
+ end
104
+
105
+ let(:salad) do
106
+ Package.new('salad').tap do |package|
107
+ package.depends 'apple'
108
+ package.depends 'orange'
109
+ package.provides 'salad'
110
+ end
111
+ end
112
+
113
+ let(:lunch) do
114
+ Package.new('lunch').tap do |package|
115
+ package.depends 'apple'
116
+ package.depends 'salad'
117
+ package.provides 'lunch'
118
+ end
119
+ end
120
+
121
+ let(:chain) {Build::Dependency::Chain.new(['lunch'], [fruit, salad, lunch])}
122
+
123
+ it "should include both provisions" do
124
+ expect(chain.provisions.count).to be == 4
125
+ expect(chain.provisions.collect(&:name)).to be == ['apple', 'orange', 'salad', 'lunch']
126
+ end
127
+
128
+ it "should include both provisions in partial chain" do
129
+ partial_chain = chain.partial(lunch)
130
+ expect(partial_chain.provisions.count).to be == 3
131
+ expect(partial_chain.provisions.collect(&:name)).to be == ['apple', 'orange', 'salad']
132
+ end
133
+ end
134
+
135
+ it "should resolve aliases" do
136
+ apple = Package.new('apple')
137
+ apple.provides 'apple'
138
+ apple.provides :fruit => 'apple'
139
+
140
+ bananna = Package.new('bananna')
141
+ bananna.provides 'bananna'
142
+ bananna.provides :fruit => 'bananna'
143
+
144
+ salad = Package.new('salad')
145
+ salad.depends :fruit
146
+ salad.provides 'salad'
147
+
148
+ chain = Build::Dependency::Chain.expand(['salad'], [apple, bananna, salad], ['apple'])
149
+ expect(chain.unresolved).to be == []
150
+ expect(chain.conflicts).to be == {}
151
+
152
+ expect(chain.ordered.size).to be == 2
153
+ expect(chain.ordered[0]).to be == Build::Dependency::Resolution.new(apple, Build::Dependency::Depends.new("apple"))
154
+ expect(chain.ordered[1]).to be == Build::Dependency::Resolution.new(salad, Build::Dependency::Depends.new("salad"))
155
+ end
156
+
157
+ it "should select dependencies with high priority" do
158
+ bad_apple = Package.new('bad_apple')
159
+ bad_apple.provides 'apple'
160
+ bad_apple.priority = 20
161
+
162
+ good_apple = Package.new('good_apple')
163
+ good_apple.provides 'apple'
164
+ good_apple.priority = 40
165
+
166
+ chain = Build::Dependency::Chain.expand(['apple'], [bad_apple, good_apple])
167
+
168
+ expect(chain.unresolved).to be == []
169
+ expect(chain.conflicts).to be == {}
170
+
171
+ # Should select higher priority package by default:
172
+ expect(chain.ordered).to be == [Build::Dependency::Resolution.new(good_apple, Build::Dependency::Depends.new('apple'))]
173
+ end
174
+
175
+ it "should expose direct dependencies" do
176
+ system = Package.new('linux')
177
+ system.provides 'linux'
178
+ system.provides 'clang'
179
+ system.provides system: 'linux'
180
+ system.provides compiler: 'clang'
181
+
182
+ library = Package.new('library')
183
+ library.provides 'library'
184
+ library.depends :system
185
+ library.depends :compiler
186
+
187
+ application = Package.new('application')
188
+ application.provides 'application'
189
+ application.depends :compiler
190
+ application.depends 'library'
191
+
192
+ chain = Build::Dependency::Chain.expand(['application'], [system, library, application])
193
+
194
+ expect(chain.unresolved).to be == []
195
+ expect(chain.conflicts).to be == {}
196
+ expect(chain.ordered).to be == [
197
+ Build::Dependency::Resolution.new(system, Build::Dependency::Depends.new('clang')),
198
+ Build::Dependency::Resolution.new(library, Build::Dependency::Depends.new('library')),
199
+ Build::Dependency::Resolution.new(application, Build::Dependency::Depends.new('application')),
200
+ ]
201
+ end
202
+ end
@@ -0,0 +1,116 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ RSpec.describe Build::Dependency::PartialChain do
22
+ describe "app chain" do
23
+ include_context "app packages"
24
+
25
+ let(:chain) {Build::Dependency::Chain.expand(['app', 'lib'], packages)}
26
+
27
+ it "should generate full list of ordered providers" do
28
+ expect(chain.ordered).to be == [
29
+ Build::Dependency::Resolution.new(variant, Build::Dependency::Depends.new('Variant/debug')),
30
+ Build::Dependency::Resolution.new(platform, Build::Dependency::Depends.new('Platform/linux')),
31
+ Build::Dependency::Resolution.new(compiler, Build::Dependency::Depends.new("Language/C++17")),
32
+ Build::Dependency::Resolution.new(lib, Build::Dependency::Depends.new('lib')),
33
+ Build::Dependency::Resolution.new(app, Build::Dependency::Depends.new('app')),
34
+ ]
35
+ end
36
+
37
+ it "should generate a full list of provisions" do
38
+ expect(chain.provisions).to be == [
39
+ variant.provision_for(Build::Dependency::Depends['Variant/debug']),
40
+ platform.provision_for(Build::Dependency::Depends['Platform/linux']),
41
+ compiler.provision_for(Build::Dependency::Depends['Language/C++17']),
42
+ lib.provision_for(Build::Dependency::Depends.new('lib')),
43
+ compiler.provision_for(Build::Dependency::Depends['Language/C++14']),
44
+ app.provision_for(Build::Dependency::Depends.new('app')),
45
+ ]
46
+
47
+ graph = visualization.generate(chain)
48
+
49
+ Graphviz::output(graph, path: "full.svg")
50
+ end
51
+
52
+ subject {described_class.new(chain, app.dependencies)}
53
+
54
+ it "should select app packages" do
55
+ expect(subject.ordered).to be == [
56
+ Build::Dependency::Resolution.new(variant, Build::Dependency::Depends.new('Variant/debug')),
57
+ Build::Dependency::Resolution.new(platform, Build::Dependency::Depends.new('Platform/linux')),
58
+ Build::Dependency::Resolution.new(lib, Build::Dependency::Depends.new('lib')),
59
+ Build::Dependency::Resolution.new(compiler, Build::Dependency::Depends.new("Language/C++14")),
60
+ ]
61
+
62
+ graph = visualization.generate(subject)
63
+
64
+ Graphviz::output(graph, path: "partial.svg")
65
+ end
66
+ end
67
+
68
+ describe "private dependencies" do
69
+ let(:a) do
70
+ Package.new('a').tap do |package|
71
+ package.provides 'a'
72
+ end
73
+ end
74
+
75
+ let(:b) do
76
+ Package.new('b').tap do |package|
77
+ package.provides 'b'
78
+ package.depends 'a', private: true
79
+ end
80
+ end
81
+
82
+ let(:c) do
83
+ Package.new('c').tap do |package|
84
+ package.provides 'c'
85
+ package.depends 'b'
86
+ end
87
+ end
88
+
89
+ let(:d) do
90
+ Package.new('d').tap do |package|
91
+ package.provides 'd'
92
+ package.depends 'c'
93
+ end
94
+ end
95
+
96
+ let(:chain) {Build::Dependency::Chain.expand(['d'], [a, b, c, d])}
97
+
98
+ it "should include direct private dependencies" do
99
+ partial_chain = chain.partial(b)
100
+
101
+ expect(partial_chain.ordered.collect(&:first)).to be == [a]
102
+ end
103
+
104
+ it "shouldn't include nested private dependencies" do
105
+ partial_chain = chain.partial(c)
106
+
107
+ expect(partial_chain.ordered.collect(&:first)).to be == [b]
108
+ end
109
+
110
+ it "should follow non-private dependencies" do
111
+ partial_chain = chain.partial(d)
112
+
113
+ expect(partial_chain.ordered.collect(&:first)).to be == [b, c]
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ RSpec.describe Build::Dependency::Visualization do
22
+ include_context "app packages"
23
+
24
+ it "should visualize dependency chain" do
25
+ chain = Build::Dependency::Chain.expand(['app', 'tests'], packages)
26
+
27
+ graph = subject.generate(chain)
28
+
29
+ Graphviz::output(graph, path: "visualization.svg")
30
+ end
31
+ end
@@ -0,0 +1,97 @@
1
+
2
+ if ENV['COVERAGE']
3
+ begin
4
+ require 'simplecov'
5
+
6
+ SimpleCov.start do
7
+ add_filter "/spec/"
8
+ end
9
+
10
+ if ENV['TRAVIS']
11
+ require 'coveralls'
12
+ Coveralls.wear!
13
+ end
14
+ rescue LoadError
15
+ warn "Could not load simplecov: #{$!}"
16
+ end
17
+ end
18
+
19
+ require "bundler/setup"
20
+ require "build/dependency"
21
+
22
+ class Package
23
+ include Build::Dependency
24
+
25
+ def initialize(name = nil)
26
+ @name = name
27
+ end
28
+
29
+ attr :name
30
+
31
+ def inspect
32
+ "<Package:#{@name}>"
33
+ end
34
+ end
35
+
36
+ RSpec.shared_context "app packages" do
37
+ let(:app) do
38
+ Package.new('app').tap do |package|
39
+ package.provides 'app'
40
+ package.depends 'lib', private: true
41
+ package.depends :platform, private: true
42
+ package.depends 'Language/C++14', private: true
43
+ end
44
+ end
45
+
46
+ let(:tests) do
47
+ Package.new('tests').tap do |package|
48
+ package.provides 'tests'
49
+ package.depends 'lib', private: true
50
+ package.depends :platform, private: true
51
+ package.depends 'Language/C++17', private: true
52
+ end
53
+ end
54
+
55
+ let(:lib) do
56
+ Package.new('lib').tap do |package|
57
+ package.provides 'lib'
58
+ package.depends :platform, private: true
59
+ package.depends 'Language/C++17', private: true
60
+ end
61
+ end
62
+
63
+ let(:platform) do
64
+ Package.new('Platform/linux').tap do |package|
65
+ package.provides platform: 'Platform/linux'
66
+ package.provides 'Platform/linux'
67
+ package.depends :variant
68
+ end
69
+ end
70
+
71
+ let(:variant) do
72
+ Package.new('Variant/debug').tap do |package|
73
+ package.provides variant: 'Variant/debug'
74
+ package.provides 'Variant/debug'
75
+ end
76
+ end
77
+
78
+ let(:compiler) do
79
+ Package.new('Compiler/clang').tap do |package|
80
+ package.provides 'Language/C++14'
81
+ package.provides 'Language/C++17'
82
+ end
83
+ end
84
+
85
+ let(:packages) {[app, tests, lib, platform, variant, compiler]}
86
+
87
+ let(:visualization) {Build::Dependency::Visualization.new}
88
+ end
89
+
90
+ RSpec.configure do |config|
91
+ # Enable flags like --only-failures and --next-failure
92
+ config.example_status_persistence_file_path = ".rspec_status"
93
+
94
+ config.expect_with :rspec do |c|
95
+ c.syntax = :expect
96
+ end
97
+ end
@@ -0,0 +1,147 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <!-- Generated by graphviz version 2.40.1 (20161225.0304)
5
+ -->
6
+ <!-- Title: G Pages: 1 -->
7
+ <svg width="385pt" height="404pt"
8
+ viewBox="0.00 0.00 385.00 404.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9
+ <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 400)">
10
+ <title>G</title>
11
+ <polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-400 381,-400 381,4 -4,4"/>
12
+ <!-- Variant/debug -->
13
+ <g id="node1" class="node">
14
+ <title>Variant/debug</title>
15
+ <polygon fill="#add8e6" stroke="#000000" stroke-width="2" points="282,-36 156,-36 156,0 282,0 282,-36"/>
16
+ <text text-anchor="middle" x="219" y="-14.3" font-family="Monaco" font-size="14.00" fill="#000000">Variant/debug</text>
17
+ </g>
18
+ <!-- variant -->
19
+ <g id="node2" class="node">
20
+ <title>variant</title>
21
+ <polygon fill="#d3d3d3" stroke="#000000" points="256.5,-108 181.5,-108 181.5,-72 256.5,-72 256.5,-108"/>
22
+ <text text-anchor="middle" x="219" y="-86.3" font-family="Monaco" font-size="14.00" fill="#000000">variant</text>
23
+ </g>
24
+ <!-- variant&#45;&gt;Variant/debug -->
25
+ <g id="edge1" class="edge">
26
+ <title>variant&#45;&gt;Variant/debug</title>
27
+ <path fill="none" stroke="#000000" d="M219,-71.8314C219,-61 219,-47.2876 219,-36.4133"/>
28
+ </g>
29
+ <!-- Platform/linux -->
30
+ <g id="node3" class="node">
31
+ <title>Platform/linux</title>
32
+ <polygon fill="#add8e6" stroke="#000000" stroke-width="2" points="286,-180 152,-180 152,-144 286,-144 286,-180"/>
33
+ <text text-anchor="middle" x="219" y="-158.3" font-family="Monaco" font-size="14.00" fill="#000000">Platform/linux</text>
34
+ </g>
35
+ <!-- Platform/linux&#45;&gt;variant -->
36
+ <g id="edge2" class="edge">
37
+ <title>Platform/linux&#45;&gt;variant</title>
38
+ <path fill="none" stroke="#000000" d="M219,-143.8314C219,-136.131 219,-126.9743 219,-118.4166"/>
39
+ <polygon fill="#000000" stroke="#000000" points="222.5001,-118.4132 219,-108.4133 215.5001,-118.4133 222.5001,-118.4132"/>
40
+ </g>
41
+ <!-- platform -->
42
+ <g id="node4" class="node">
43
+ <title>platform</title>
44
+ <polygon fill="#d3d3d3" stroke="#000000" points="225,-252 141,-252 141,-216 225,-216 225,-252"/>
45
+ <text text-anchor="middle" x="183" y="-230.3" font-family="Monaco" font-size="14.00" fill="#000000">platform</text>
46
+ </g>
47
+ <!-- platform&#45;&gt;Platform/linux -->
48
+ <g id="edge3" class="edge">
49
+ <title>platform&#45;&gt;Platform/linux</title>
50
+ <path fill="none" stroke="#000000" d="M192.0843,-215.8314C197.5,-205 204.3562,-191.2876 209.7934,-180.4133"/>
51
+ </g>
52
+ <!-- Compiler/clang -->
53
+ <g id="node5" class="node">
54
+ <title>Compiler/clang</title>
55
+ <polygon fill="#add8e6" stroke="#000000" points="134,-180 0,-180 0,-144 134,-144 134,-180"/>
56
+ <text text-anchor="middle" x="67" y="-158.3" font-family="Monaco" font-size="14.00" fill="#000000">Compiler/clang</text>
57
+ </g>
58
+ <!-- Language/C++14 -->
59
+ <g id="node6" class="node">
60
+ <title>Language/C++14</title>
61
+ <polygon fill="#ffffff" stroke="#000000" stroke-width="2" points="134,-324 0,-324 0,-288 134,-288 134,-324"/>
62
+ <text text-anchor="middle" x="67" y="-302.3" font-family="Monaco" font-size="14.00" fill="#000000">Language/C++14</text>
63
+ </g>
64
+ <!-- Language/C++14&#45;&gt;Compiler/clang -->
65
+ <g id="edge4" class="edge">
66
+ <title>Language/C++14&#45;&gt;Compiler/clang</title>
67
+ <path fill="none" stroke="#000000" d="M67,-287.7623C67,-260.0633 67,-207.7005 67,-180.0896"/>
68
+ </g>
69
+ <!-- Language/C++17 -->
70
+ <g id="node7" class="node">
71
+ <title>Language/C++17</title>
72
+ <polygon fill="#ffffff" stroke="#000000" stroke-width="2" points="377,-252 243,-252 243,-216 377,-216 377,-252"/>
73
+ <text text-anchor="middle" x="310" y="-230.3" font-family="Monaco" font-size="14.00" fill="#000000">Language/C++17</text>
74
+ </g>
75
+ <!-- Language/C++17&#45;&gt;Compiler/clang -->
76
+ <g id="edge5" class="edge">
77
+ <title>Language/C++17&#45;&gt;Compiler/clang</title>
78
+ <path fill="none" stroke="#000000" d="M248.9945,-215.9243C212.0197,-204.9688 165.0099,-191.04 128.0306,-180.0831"/>
79
+ </g>
80
+ <!-- lib -->
81
+ <g id="node8" class="node">
82
+ <title>lib</title>
83
+ <polygon fill="#ffffff" stroke="#000000" stroke-width="2" points="282,-324 228,-324 228,-288 282,-288 282,-324"/>
84
+ <text text-anchor="middle" x="255" y="-302.3" font-family="Monaco" font-size="14.00" fill="#000000">lib</text>
85
+ </g>
86
+ <!-- lib&#45;&gt;platform -->
87
+ <g id="edge6" class="edge">
88
+ <title>lib&#45;&gt;platform</title>
89
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M236.8314,-287.8314C228.2848,-279.2848 217.9443,-268.9443 208.6198,-259.6198"/>
90
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="210.9592,-257.0095 201.4133,-252.4133 206.0095,-261.9592 210.9592,-257.0095"/>
91
+ </g>
92
+ <!-- lib&#45;&gt;Language/C++17 -->
93
+ <g id="edge7" class="edge">
94
+ <title>lib&#45;&gt;Language/C++17</title>
95
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M268.8788,-287.8314C275.2136,-279.5386 282.8384,-269.557 289.7926,-260.4533"/>
96
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="292.6452,-262.4847 295.9343,-252.4133 287.0825,-258.2353 292.6452,-262.4847"/>
97
+ </g>
98
+ <!-- app -->
99
+ <g id="node9" class="node">
100
+ <title>app</title>
101
+ <polygon fill="#ffa500" stroke="#000000" stroke-width="2" points="189,-396 135,-396 135,-360 189,-360 189,-396"/>
102
+ <text text-anchor="middle" x="162" y="-374.3" font-family="Monaco" font-size="14.00" fill="#000000">app</text>
103
+ </g>
104
+ <!-- app&#45;&gt;platform -->
105
+ <g id="edge9" class="edge">
106
+ <title>app&#45;&gt;platform</title>
107
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M164.6597,-359.7623C168.2415,-335.201 174.6514,-291.2474 178.865,-262.3541"/>
108
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="182.3821,-262.4901 180.3619,-252.0896 175.4554,-261.4798 182.3821,-262.4901"/>
109
+ </g>
110
+ <!-- app&#45;&gt;Language/C++14 -->
111
+ <g id="edge10" class="edge">
112
+ <title>app&#45;&gt;Language/C++14</title>
113
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M138.0275,-359.8314C126.2139,-350.8779 111.8028,-339.9558 99.0565,-330.2955"/>
114
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="101.0486,-327.4137 90.9648,-324.1628 96.8205,-332.9925 101.0486,-327.4137"/>
115
+ </g>
116
+ <!-- app&#45;&gt;lib -->
117
+ <g id="edge8" class="edge">
118
+ <title>app&#45;&gt;lib</title>
119
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M185.4678,-359.8314C197.0327,-350.8779 211.1404,-339.9558 223.6183,-330.2955"/>
120
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="225.775,-333.0521 231.5397,-324.1628 221.4898,-327.5171 225.775,-333.0521"/>
121
+ </g>
122
+ <!-- tests -->
123
+ <g id="node10" class="node">
124
+ <title>tests</title>
125
+ <polygon fill="#ffa500" stroke="#000000" stroke-width="2" points="284.5,-396 225.5,-396 225.5,-360 284.5,-360 284.5,-396"/>
126
+ <text text-anchor="middle" x="255" y="-374.3" font-family="Monaco" font-size="14.00" fill="#000000">tests</text>
127
+ </g>
128
+ <!-- tests&#45;&gt;platform -->
129
+ <g id="edge12" class="edge">
130
+ <title>tests&#45;&gt;platform</title>
131
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M241.3445,-359.5973C234.154,-349.4209 225.5044,-336.3651 219,-324 208.4065,-303.8615 198.9605,-279.8887 192.405,-261.7501"/>
132
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="195.6176,-260.3365 188.9822,-252.0768 189.0185,-262.6716 195.6176,-260.3365"/>
133
+ </g>
134
+ <!-- tests&#45;&gt;Language/C++17 -->
135
+ <g id="edge13" class="edge">
136
+ <title>tests&#45;&gt;Language/C++17</title>
137
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M269.8853,-359.5185C277.2462,-349.5296 285.672,-336.6716 291,-324 299.3306,-304.1876 304.1533,-280.3321 306.8541,-262.1605"/>
138
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="310.3302,-262.5721 308.2095,-252.1917 303.3941,-261.6289 310.3302,-262.5721"/>
139
+ </g>
140
+ <!-- tests&#45;&gt;lib -->
141
+ <g id="edge11" class="edge">
142
+ <title>tests&#45;&gt;lib</title>
143
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M255,-359.8314C255,-352.131 255,-342.9743 255,-334.4166"/>
144
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="258.5001,-334.4132 255,-324.4133 251.5001,-334.4133 258.5001,-334.4132"/>
145
+ </g>
146
+ </g>
147
+ </svg>