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,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>