build-dependency 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
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
+ require_relative 'chain'
22
+
23
+ module Build
24
+ module Dependency
25
+ class Chain
26
+ def partial(provider)
27
+ PartialChain.expand(self, provider.dependencies)
28
+ end
29
+ end
30
+
31
+ class PartialChain < Resolver
32
+ # An `UnresolvedDependencyError` will be thrown if there are any unresolved dependencies.
33
+ def self.expand(*args)
34
+ chain = self.new(*args)
35
+
36
+ chain.freeze
37
+
38
+ return chain
39
+ end
40
+
41
+ def initialize(chain, dependencies)
42
+ super()
43
+
44
+ @chain = chain
45
+
46
+ # The list of dependencies that needs to be satisfied:
47
+ @dependencies = dependencies.collect{|dependency| Depends[dependency]}
48
+
49
+ expand_top
50
+ end
51
+
52
+ def selection
53
+ @chain.selection
54
+ end
55
+
56
+ attr :dependencies
57
+
58
+ def providers
59
+ @chain.providers
60
+ end
61
+
62
+ def freeze
63
+ return unless frozen?
64
+
65
+ @chain.freeze
66
+ @dependencies.freeze
67
+
68
+ super
69
+ end
70
+
71
+ protected
72
+
73
+ def expand_top
74
+ expand_nested(@dependencies, TOP)
75
+ end
76
+
77
+ def expand(dependency, parent)
78
+ unless @dependencies.include?(dependency)
79
+ return if dependency.private?
80
+ end
81
+
82
+ super(dependency, parent)
83
+ end
84
+
85
+ def find_provider(dependency, parent)
86
+ @chain.resolved[dependency]
87
+ end
88
+
89
+ def provision_for(provider, dependency)
90
+ # @chain.resolved[provider] does work, but it points to the most recently added provision, but we want the provision related to the specific dependency.
91
+ provider.provision_for(dependency)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,135 @@
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
+ require 'set'
22
+
23
+ module Build
24
+ module Dependency
25
+ def self.included(klass)
26
+ klass.include(Unit)
27
+ end
28
+
29
+ # A provision is a thing which satisfies a dependency.
30
+ Provision = Struct.new(:name, :provider, :value) do
31
+ def alias?
32
+ false
33
+ end
34
+ end
35
+
36
+ Alias = Struct.new(:name, :provider, :dependencies) do
37
+ def alias?
38
+ true
39
+ end
40
+ end
41
+
42
+ Resolution = Struct.new(:provider, :dependency) do
43
+ def name
44
+ dependency.name
45
+ end
46
+ end
47
+
48
+ Depends = Struct.new(:name) do
49
+ def initialize(name, **options)
50
+ super(name)
51
+
52
+ @options = options
53
+ end
54
+
55
+ attr :options
56
+
57
+ def private?
58
+ @options[:private]
59
+ end
60
+
61
+ def alias?
62
+ name.is_a?(Symbol)
63
+ end
64
+
65
+ def self.[] name_or_dependency
66
+ name_or_dependency.is_a?(self) ? name_or_dependency : self.new(name_or_dependency)
67
+ end
68
+ end
69
+
70
+ module Unit
71
+ def freeze
72
+ return unless frozen?
73
+
74
+ provisions.freeze
75
+ dependencies.freeze
76
+
77
+ super
78
+ end
79
+
80
+ # Assign a priority to this unit.
81
+ def priority= value
82
+ @priority = value
83
+ end
84
+
85
+ # The units default priority
86
+ def priority
87
+ @priority ||= 0
88
+ end
89
+
90
+ # @return Hash<String, Provision> a table of named provisions.
91
+ def provisions
92
+ @provisions ||= {}
93
+ end
94
+
95
+ # @return Set<Dependency>
96
+ def dependencies
97
+ @dependencies ||= Set.new
98
+ end
99
+
100
+ # Does this unit provide the named thing?
101
+ def provides?(dependency)
102
+ provisions.key?(dependency.name)
103
+ end
104
+
105
+ def provision_for(dependency)
106
+ provisions[dependency.name]
107
+ end
108
+
109
+ # Mark this unit as providing the named thing, with an optional block.
110
+ def provides(name_or_aliases, &block)
111
+ if String === name_or_aliases || Symbol === name_or_aliases
112
+ name = name_or_aliases
113
+
114
+ provisions[name] = Provision.new(name, self, block)
115
+ else
116
+ aliases = name_or_aliases
117
+
118
+ aliases.each do |name, dependencies|
119
+ provisions[name] = Alias.new(name, self, Array(dependencies))
120
+ end
121
+ end
122
+ end
123
+
124
+ def depends(*names, **options)
125
+ names.each do |name|
126
+ dependencies << Depends.new(name, **options)
127
+ end
128
+ end
129
+
130
+ def depends?(name)
131
+ dependencies.include?(name)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,25 @@
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
+ module Build
22
+ module Dependency
23
+ VERSION = "1.0.0"
24
+ end
25
+ end
@@ -0,0 +1,151 @@
1
+ # Copyright, 20127, 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
+ require 'graphviz'
22
+
23
+ module Build
24
+ module Dependency
25
+ class Visualization
26
+ def initialize
27
+ @base_attributes = {
28
+ :shape => 'box',
29
+ :style => 'filled',
30
+ :fillcolor => 'white',
31
+ :fontname => 'Monaco',
32
+ }
33
+
34
+ @provision_attributes = @base_attributes.dup
35
+
36
+ @alias_attributes = @base_attributes.merge(
37
+ :fillcolor => 'lightgrey',
38
+ )
39
+
40
+ @dependency_attributes = @base_attributes.merge(
41
+ :fillcolor => 'orange',
42
+ )
43
+
44
+ @selection_attributes = {
45
+ :fillcolor => 'lightbrown',
46
+ }
47
+
48
+ @private_edge_attributes = {
49
+ :arrowhead => 'empty',
50
+ :color => '#0000005f'
51
+ }
52
+
53
+ @provider_attributes = {
54
+ :fillcolor => 'lightblue',
55
+ }
56
+
57
+ @provider_edge_attributes = {
58
+ :arrowhead => 'none',
59
+ }
60
+ end
61
+
62
+ attr :base_attributes
63
+ attr :provision_attributes
64
+
65
+ attr :provider_attributes
66
+ attr :provider_edge_attributes
67
+
68
+ attr :alias_attributes
69
+
70
+ attr :dependency_attributes
71
+ attr :selection_attributes
72
+ attr :private_edge_attributes
73
+
74
+ def generate(chain)
75
+ graph = Graphviz::Graph.new
76
+ graph.attributes[:ratio] = :auto
77
+
78
+ chain.ordered.each do |resolution|
79
+ provider = resolution.provider
80
+ name = provider.name
81
+
82
+ # Provider is the dependency that provides the dependency referred to by name.
83
+ node = graph.add_node(name.to_s, @base_attributes.dup)
84
+
85
+ if chain.dependencies.include?(resolution.dependency)
86
+ node.attributes.update(@dependency_attributes)
87
+ elsif chain.selection.include?(provider.name)
88
+ node.attributes.update(@selection_attributes)
89
+ end
90
+
91
+ # A provision has dependencies...
92
+ provider.dependencies.each do |dependency|
93
+ if dependency_node = graph.nodes[dependency.name.to_s]
94
+ edge = node.connect(dependency_node)
95
+
96
+ if dependency.private?
97
+ edge.attributes.update(@private_edge_attributes)
98
+ end
99
+ end
100
+ end
101
+
102
+ # A provision provides other provisions...
103
+ provider.provisions.each do |provision_name, provision|
104
+ next if name == provision_name
105
+
106
+ provides_node = graph.nodes[provision_name.to_s] || graph.add_node(provision_name.to_s, @provision_attributes)
107
+
108
+ if provision.alias?
109
+ provides_node.attributes = @alias_attributes
110
+ end
111
+
112
+ node.attributes.update(@provider_attributes)
113
+
114
+ unless provides_node.connected?(node)
115
+ edge = provides_node.connect(node)
116
+
117
+ edge.attributes.update(@provider_edge_attributes)
118
+ end
119
+ end
120
+ end
121
+
122
+ chain.provisions.each do |provision|
123
+ node = graph.nodes[provision.name.to_s]
124
+
125
+ node.attributes.update(penwidth: 2.0)
126
+ end
127
+
128
+ # Put all dependencies at the same level so as to not make the graph too confusingraph.
129
+ done = Set.new
130
+ chain.ordered.each do |resolution|
131
+ provider = resolution.provider
132
+ name = "subgraph-#{provider.name}"
133
+
134
+ subgraph = graph.nodes[name] || graph.add_subgraph(name, :rank => :same)
135
+
136
+ provider.dependencies.each do |dependency|
137
+ next if done.include? dependency
138
+
139
+ done << dependency
140
+
141
+ if dependency_node = graph.nodes[dependency.name.to_s]
142
+ subgraph.add_node(dependency_node.name)
143
+ end
144
+ end
145
+ end
146
+
147
+ return graph
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,93 @@
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="465pt" height="332pt"
8
+ viewBox="0.00 0.00 465.00 332.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 328)">
10
+ <title>G</title>
11
+ <polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-328 461,-328 461,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="130,-36 4,-36 4,0 130,0 130,-36"/>
16
+ <text text-anchor="middle" x="67" 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="104.5,-108 29.5,-108 29.5,-72 104.5,-72 104.5,-108"/>
22
+ <text text-anchor="middle" x="67" 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="M67,-71.8314C67,-61 67,-47.2876 67,-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="134,-180 0,-180 0,-144 134,-144 134,-180"/>
33
+ <text text-anchor="middle" x="67" 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="M67,-143.8314C67,-136.131 67,-126.9743 67,-118.4166"/>
39
+ <polygon fill="#000000" stroke="#000000" points="70.5001,-118.4132 67,-108.4133 63.5001,-118.4133 70.5001,-118.4132"/>
40
+ </g>
41
+ <!-- platform -->
42
+ <g id="node4" class="node">
43
+ <title>platform</title>
44
+ <polygon fill="#d3d3d3" stroke="#000000" points="109,-252 25,-252 25,-216 109,-216 109,-252"/>
45
+ <text text-anchor="middle" x="67" 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="M67,-215.8314C67,-205 67,-191.2876 67,-180.4133"/>
51
+ </g>
52
+ <!-- lib -->
53
+ <g id="node5" class="node">
54
+ <title>lib</title>
55
+ <polygon fill="#ffa500" stroke="#000000" stroke-width="2" points="94,-324 40,-324 40,-288 94,-288 94,-324"/>
56
+ <text text-anchor="middle" x="67" y="-302.3" font-family="Monaco" font-size="14.00" fill="#000000">lib</text>
57
+ </g>
58
+ <!-- lib&#45;&gt;platform -->
59
+ <g id="edge4" class="edge">
60
+ <title>lib&#45;&gt;platform</title>
61
+ <path fill="none" stroke="#000000" stroke-opacity="0.372549" d="M67,-287.8314C67,-280.131 67,-270.9743 67,-262.4166"/>
62
+ <polygon fill="none" stroke="#000000" stroke-opacity="0.372549" points="70.5001,-262.4132 67,-252.4133 63.5001,-262.4133 70.5001,-262.4132"/>
63
+ </g>
64
+ <!-- Compiler/clang -->
65
+ <g id="node6" class="node">
66
+ <title>Compiler/clang</title>
67
+ <polygon fill="#add8e6" stroke="#000000" points="349,-180 215,-180 215,-144 349,-144 349,-180"/>
68
+ <text text-anchor="middle" x="282" y="-158.3" font-family="Monaco" font-size="14.00" fill="#000000">Compiler/clang</text>
69
+ </g>
70
+ <!-- Language/C++14 -->
71
+ <g id="node7" class="node">
72
+ <title>Language/C++14</title>
73
+ <polygon fill="#ffffff" stroke="#000000" stroke-width="2" points="305,-252 171,-252 171,-216 305,-216 305,-252"/>
74
+ <text text-anchor="middle" x="238" y="-230.3" font-family="Monaco" font-size="14.00" fill="#000000">Language/C++14</text>
75
+ </g>
76
+ <!-- Language/C++14&#45;&gt;Compiler/clang -->
77
+ <g id="edge5" class="edge">
78
+ <title>Language/C++14&#45;&gt;Compiler/clang</title>
79
+ <path fill="none" stroke="#000000" d="M249.1031,-215.8314C255.7222,-205 264.102,-191.2876 270.7474,-180.4133"/>
80
+ </g>
81
+ <!-- Language/C++17 -->
82
+ <g id="node8" class="node">
83
+ <title>Language/C++17</title>
84
+ <polygon fill="#ffffff" stroke="#000000" points="457,-252 323,-252 323,-216 457,-216 457,-252"/>
85
+ <text text-anchor="middle" x="390" y="-230.3" font-family="Monaco" font-size="14.00" fill="#000000">Language/C++17</text>
86
+ </g>
87
+ <!-- Language/C++17&#45;&gt;Compiler/clang -->
88
+ <g id="edge6" class="edge">
89
+ <title>Language/C++17&#45;&gt;Compiler/clang</title>
90
+ <path fill="none" stroke="#000000" d="M362.747,-215.8314C346.3751,-204.9167 325.6147,-191.0764 309.2442,-180.1628"/>
91
+ </g>
92
+ </g>
93
+ </svg>