build-dependency 1.5.1 → 1.6.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/build/dependency/chain.rb +13 -22
- data/lib/build/dependency/partial_chain.rb +18 -21
- data/lib/build/dependency/provider.rb +28 -27
- data/lib/build/dependency/resolver.rb +12 -21
- data/lib/build/dependency/set.rb +27 -20
- data/lib/build/dependency/version.rb +7 -20
- data/lib/build/dependency/visualization.rb +58 -122
- data/lib/build/dependency.rb +9 -24
- data/license.md +21 -0
- data/readme.md +64 -0
- data/releases.md +5 -0
- data/test/build/dependency/chain.rb +223 -0
- data/test/build/dependency/partial_chain.rb +121 -0
- data/test/build/dependency/provider.rb +189 -0
- data/test/build/dependency/set.rb +122 -0
- data/test/build/dependency/visualization.rb +21 -0
- data/test/build/dependency/wildcard.rb +38 -0
- data.tar.gz.sig +1 -0
- metadata +49 -113
- metadata.gz.sig +0 -0
- data/.gitignore +0 -23
- data/.rspec +0 -4
- data/.travis.yml +0 -17
- data/Gemfile +0 -14
- data/Guardfile +0 -9
- data/README.md +0 -214
- data/Rakefile +0 -8
- data/build-dependency.gemspec +0 -24
- data/build_system_rules_and_algorithms.pdf +0 -0
- data/full.svg +0 -123
- data/partial.svg +0 -93
- data/spec/build/dependency/chain_spec.rb +0 -218
- data/spec/build/dependency/package.rb +0 -89
- data/spec/build/dependency/partial_chain_spec.rb +0 -119
- data/spec/build/dependency/provider_spec.rb +0 -123
- data/spec/build/dependency/set_spec.rb +0 -87
- data/spec/build/dependency/visualization_spec.rb +0 -33
- data/spec/build/dependency/wildcard_spec.rb +0 -45
- data/spec/spec_helper.rb +0 -12
- data/visualization.svg +0 -147
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22b38e2f183e26fb4db1cfc6e53c91c2cc3fd5efd026b3eb8dd62f225d309bdf
|
|
4
|
+
data.tar.gz: 2594cc69f37835c318a69e058de3b5875be3485f8edd47ba86713c8e316e4ce0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca056c3755bde6ba73c490ea7af08e600c51068220d71fe84ace34d430a4ff996b922c25942cc3eb27809f1fe366c78d9ca2e8685d10407546674ab4ac7e7f86
|
|
7
|
+
data.tar.gz: 851a466463008e0e27abe6b576d3e0f9cf0bbe2c33ad5f46a6eb186f73c2cb0131f46b2063dd0fab4725d8f49208538946be712004d419c2f5e7fbbd440a7aec
|
checksums.yaml.gz.sig
ADDED
|
Binary file
|
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
22
5
|
|
|
23
|
-
|
|
6
|
+
require_relative "resolver"
|
|
7
|
+
|
|
8
|
+
require "set"
|
|
24
9
|
|
|
25
10
|
module Build
|
|
26
11
|
module Dependency
|
|
12
|
+
# A chain of dependencies that are resolved from a set of providers.
|
|
27
13
|
class Chain < Resolver
|
|
28
14
|
# An `UnresolvedDependencyError` will be thrown if there are any unresolved dependencies.
|
|
29
15
|
def self.expand(*args)
|
|
@@ -38,6 +24,10 @@ module Build
|
|
|
38
24
|
return chain
|
|
39
25
|
end
|
|
40
26
|
|
|
27
|
+
# Initialize a dependency chain.
|
|
28
|
+
# @parameter dependencies [Array<String, Depends>] The dependencies to resolve.
|
|
29
|
+
# @parameter providers [Array<Provider>] The providers to use for resolution.
|
|
30
|
+
# @parameter selection [Array<String>] Explicitly selected dependencies for resolving ambiguity.
|
|
41
31
|
def initialize(dependencies, providers, selection = [])
|
|
42
32
|
super()
|
|
43
33
|
|
|
@@ -57,8 +47,9 @@ module Build
|
|
|
57
47
|
# @attr [Array] The available providers which will be used to satisfy he required dependencies.
|
|
58
48
|
attr :providers
|
|
59
49
|
|
|
50
|
+
# Freeze the chain and all its dependencies.
|
|
60
51
|
def freeze
|
|
61
|
-
return
|
|
52
|
+
return self if frozen?
|
|
62
53
|
|
|
63
54
|
@selection.freeze
|
|
64
55
|
@dependencies.freeze
|
|
@@ -1,33 +1,22 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require_relative "chain"
|
|
22
7
|
|
|
23
8
|
module Build
|
|
24
9
|
module Dependency
|
|
25
10
|
class Chain
|
|
11
|
+
# Create a partial chain for a specific provider.
|
|
12
|
+
# @parameter provider [Provider] The provider to create a partial chain for.
|
|
13
|
+
# @returns [PartialChain] A partial chain containing only the provider's dependencies.
|
|
26
14
|
def partial(provider)
|
|
27
15
|
PartialChain.expand(self, provider.dependencies)
|
|
28
16
|
end
|
|
29
17
|
end
|
|
30
18
|
|
|
19
|
+
# A partial dependency chain that resolves only a subset of dependencies.
|
|
31
20
|
class PartialChain < Resolver
|
|
32
21
|
# An `UnresolvedDependencyError` will be thrown if there are any unresolved dependencies.
|
|
33
22
|
def self.expand(*args)
|
|
@@ -38,6 +27,9 @@ module Build
|
|
|
38
27
|
return chain
|
|
39
28
|
end
|
|
40
29
|
|
|
30
|
+
# Initialize a partial chain.
|
|
31
|
+
# @parameter chain [Chain] The parent chain to use for resolution.
|
|
32
|
+
# @parameter dependencies [Array<Depends>] The dependencies to resolve.
|
|
41
33
|
def initialize(chain, dependencies)
|
|
42
34
|
super()
|
|
43
35
|
|
|
@@ -48,6 +40,8 @@ module Build
|
|
|
48
40
|
expand_top
|
|
49
41
|
end
|
|
50
42
|
|
|
43
|
+
# Get the selection from the parent chain.
|
|
44
|
+
# @returns [Set<String>] The explicitly selected dependencies.
|
|
51
45
|
def selection
|
|
52
46
|
@chain.selection
|
|
53
47
|
end
|
|
@@ -55,12 +49,15 @@ module Build
|
|
|
55
49
|
# @attr [Array<Depends>] The list of dependencies that needs to be satisfied.
|
|
56
50
|
attr :dependencies
|
|
57
51
|
|
|
52
|
+
# Get the providers from the parent chain.
|
|
53
|
+
# @returns [Array<Provider>] The available providers.
|
|
58
54
|
def providers
|
|
59
55
|
@chain.providers
|
|
60
56
|
end
|
|
61
57
|
|
|
58
|
+
# Freeze the partial chain.
|
|
62
59
|
def freeze
|
|
63
|
-
return
|
|
60
|
+
return self if frozen?
|
|
64
61
|
|
|
65
62
|
@chain.freeze
|
|
66
63
|
@dependencies.freeze
|
|
@@ -1,27 +1,14 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require_relative "set"
|
|
22
7
|
|
|
23
8
|
module Build
|
|
24
9
|
module Dependency
|
|
10
|
+
# Include the Provider module when Build::Dependency is included in a class.
|
|
11
|
+
# @parameter klass [Class] The class that is including Build::Dependency.
|
|
25
12
|
def self.included(klass)
|
|
26
13
|
klass.include(Provider)
|
|
27
14
|
end
|
|
@@ -79,7 +66,7 @@ module Build
|
|
|
79
66
|
end
|
|
80
67
|
|
|
81
68
|
def wildcard?
|
|
82
|
-
self.name.is_a?(String) and self.name.include?(
|
|
69
|
+
self.name.is_a?(String) and self.name.include?("*")
|
|
83
70
|
end
|
|
84
71
|
|
|
85
72
|
def match?(name)
|
|
@@ -119,9 +106,11 @@ module Build
|
|
|
119
106
|
end
|
|
120
107
|
end
|
|
121
108
|
|
|
109
|
+
# A provider that can satisfy dependencies by providing named provisions.
|
|
122
110
|
module Provider
|
|
111
|
+
# Freeze the provider and all its provisions and dependencies.
|
|
123
112
|
def freeze
|
|
124
|
-
return
|
|
113
|
+
return self if frozen?
|
|
125
114
|
|
|
126
115
|
provisions.freeze
|
|
127
116
|
dependencies.freeze
|
|
@@ -139,16 +128,19 @@ module Build
|
|
|
139
128
|
@priority ||= 0
|
|
140
129
|
end
|
|
141
130
|
|
|
142
|
-
# @
|
|
131
|
+
# @returns Hash<String, Provision> a table of named provisions.
|
|
143
132
|
def provisions
|
|
144
133
|
@provisions ||= {}
|
|
145
134
|
end
|
|
146
135
|
|
|
147
|
-
# @
|
|
136
|
+
# @returns [IdentitySet<Dependency>]
|
|
148
137
|
def dependencies
|
|
149
138
|
@dependencies ||= Set.new
|
|
150
139
|
end
|
|
151
140
|
|
|
141
|
+
# Filter provisions that match a given dependency.
|
|
142
|
+
# @parameter dependency [Depends] The dependency to match against.
|
|
143
|
+
# @returns [Hash<String, Provision>] Provisions that match the dependency.
|
|
152
144
|
def filter(dependency)
|
|
153
145
|
provisions.select{|name, provision| dependency.match?(name)}
|
|
154
146
|
end
|
|
@@ -158,17 +150,23 @@ module Build
|
|
|
158
150
|
provisions.key?(dependency.name)
|
|
159
151
|
end
|
|
160
152
|
|
|
153
|
+
# Get the provision for a given dependency.
|
|
154
|
+
# @parameter dependency [Depends] The dependency to get the provision for.
|
|
155
|
+
# @returns [Provision, nil] The provision, or nil if not found.
|
|
161
156
|
def provision_for(dependency)
|
|
162
157
|
return provisions[dependency.name]
|
|
163
158
|
end
|
|
164
159
|
|
|
160
|
+
# Get a resolution for a given dependency.
|
|
161
|
+
# @parameter dependency [Depends] The dependency to get the resolution for.
|
|
162
|
+
# @returns [Resolution] The resolution combining the provision and dependency.
|
|
165
163
|
def resolution_for(dependency)
|
|
166
164
|
return Resolution.new(provision_for(dependency), dependency)
|
|
167
165
|
end
|
|
168
166
|
|
|
169
167
|
# Add one or more provisions to the provider.
|
|
170
|
-
# @
|
|
171
|
-
# @
|
|
168
|
+
# @parameter names [Array<String>] the named provisions to add.
|
|
169
|
+
# @parameter aliases [Hash<Symbol, Array>] the aliases to add.
|
|
172
170
|
# @example A named provision.
|
|
173
171
|
# target.provides "Compiler/clang" do
|
|
174
172
|
# cxx "clang"
|
|
@@ -186,7 +184,7 @@ module Build
|
|
|
186
184
|
end
|
|
187
185
|
|
|
188
186
|
# Add one or more dependencies to the provider.
|
|
189
|
-
# @
|
|
187
|
+
# @parameter names [Array<String>] the dependency names to add.
|
|
190
188
|
# @example A named dependency.
|
|
191
189
|
# target.depends "Compiler/clang"
|
|
192
190
|
# @example A symbolic dependency.
|
|
@@ -197,6 +195,9 @@ module Build
|
|
|
197
195
|
end
|
|
198
196
|
end
|
|
199
197
|
|
|
198
|
+
# Check if this provider depends on a given name.
|
|
199
|
+
# @parameter name [String] The name to check.
|
|
200
|
+
# @returns [Boolean] True if this provider depends on the given name.
|
|
200
201
|
def depends?(name)
|
|
201
202
|
dependencies.include?(name)
|
|
202
203
|
end
|
|
@@ -1,28 +1,16 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "set"
|
|
22
7
|
|
|
23
8
|
module Build
|
|
24
9
|
module Dependency
|
|
10
|
+
# An error raised when dependencies cannot be resolved.
|
|
25
11
|
class UnresolvedDependencyError < StandardError
|
|
12
|
+
# Initialize the error with the unresolved chain.
|
|
13
|
+
# @parameter chain [Chain] The chain with unresolved dependencies.
|
|
26
14
|
def initialize(chain)
|
|
27
15
|
super "Unresolved dependency chain: #{chain.unresolved.inspect}!"
|
|
28
16
|
|
|
@@ -34,7 +22,9 @@ module Build
|
|
|
34
22
|
|
|
35
23
|
TOP = Depends.new("<top>").freeze
|
|
36
24
|
|
|
25
|
+
# Base class for resolving dependencies.
|
|
37
26
|
class Resolver
|
|
27
|
+
# Initialize an empty resolver.
|
|
38
28
|
def initialize
|
|
39
29
|
@resolved = {}
|
|
40
30
|
@ordered = []
|
|
@@ -49,8 +39,9 @@ module Build
|
|
|
49
39
|
attr :unresolved
|
|
50
40
|
attr :conflicts
|
|
51
41
|
|
|
42
|
+
# Freeze the resolver and all its internal state.
|
|
52
43
|
def freeze
|
|
53
|
-
return
|
|
44
|
+
return self if frozen?
|
|
54
45
|
|
|
55
46
|
@resolved.freeze
|
|
56
47
|
@ordered.freeze
|
data/lib/build/dependency/set.rb
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2019-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require "forwardable"
|
|
22
7
|
|
|
23
8
|
module Build
|
|
24
9
|
module Dependency
|
|
@@ -26,6 +11,8 @@ module Build
|
|
|
26
11
|
class Set
|
|
27
12
|
include Enumerable
|
|
28
13
|
|
|
14
|
+
# Initialize a new set with optional initial contents.
|
|
15
|
+
# @parameter contents [Array] Initial objects to add to the set.
|
|
29
16
|
def initialize(contents = [])
|
|
30
17
|
@table = {}
|
|
31
18
|
|
|
@@ -40,6 +27,7 @@ module Build
|
|
|
40
27
|
|
|
41
28
|
def_delegators :@table, :size, :empty?, :clear, :count, :[], :to_s, :inspect
|
|
42
29
|
|
|
30
|
+
# Freeze the set.
|
|
43
31
|
def freeze
|
|
44
32
|
return self if frozen?
|
|
45
33
|
|
|
@@ -48,14 +36,22 @@ module Build
|
|
|
48
36
|
super
|
|
49
37
|
end
|
|
50
38
|
|
|
39
|
+
# Initialize a duplicate of another set.
|
|
40
|
+
# @parameter other [Set] The set to duplicate.
|
|
51
41
|
def initialize_dup(other)
|
|
52
42
|
@table = other.table.dup
|
|
53
43
|
end
|
|
54
44
|
|
|
45
|
+
# Get the identity of an object for use as a hash key.
|
|
46
|
+
# @parameter object [Object] The object to get the identity for.
|
|
47
|
+
# @returns [String] The object's name.
|
|
55
48
|
def identity(object)
|
|
56
49
|
object.name
|
|
57
50
|
end
|
|
58
51
|
|
|
52
|
+
# Add an object to the set.
|
|
53
|
+
# @parameter object [Object] The object to add.
|
|
54
|
+
# @raises [KeyError] If an object with the same identity already exists.
|
|
59
55
|
def add(object)
|
|
60
56
|
if include?(object)
|
|
61
57
|
raise KeyError, "Object #{identity(object)} already exists!"
|
|
@@ -66,18 +62,29 @@ module Build
|
|
|
66
62
|
|
|
67
63
|
alias << add
|
|
68
64
|
|
|
65
|
+
# Delete an object from the set.
|
|
66
|
+
# @parameter object [Object] The object to delete.
|
|
67
|
+
# @returns [Object, nil] The deleted object, or nil if not found.
|
|
69
68
|
def delete(object)
|
|
70
69
|
@table.delete(identity(object))
|
|
71
70
|
end
|
|
72
71
|
|
|
72
|
+
# Check if the set includes an object.
|
|
73
|
+
# @parameter object [Object] The object to check for.
|
|
74
|
+
# @returns [Boolean] True if the set includes the object.
|
|
73
75
|
def include?(object)
|
|
74
76
|
@table.include?(identity(object))
|
|
75
77
|
end
|
|
76
78
|
|
|
79
|
+
# Iterate over each object in the set.
|
|
80
|
+
# @yields [Object] Each object in the set.
|
|
77
81
|
def each(&block)
|
|
78
82
|
@table.each_value(&block)
|
|
79
83
|
end
|
|
80
84
|
|
|
85
|
+
# Get a subset of objects by their names.
|
|
86
|
+
# @parameter names [Array<String>] The names of objects to retrieve.
|
|
87
|
+
# @returns [Array<Object>] The objects with the given names.
|
|
81
88
|
def slice(names)
|
|
82
89
|
names.collect{|name| @table[name]}
|
|
83
90
|
end
|
|
@@ -1,25 +1,12 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
# @namespace
|
|
21
7
|
module Build
|
|
8
|
+
# @namespace
|
|
22
9
|
module Dependency
|
|
23
|
-
VERSION = "1.
|
|
10
|
+
VERSION = "1.6.0"
|
|
24
11
|
end
|
|
25
12
|
end
|
|
@@ -1,158 +1,94 @@
|
|
|
1
|
-
#
|
|
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.
|
|
1
|
+
# frozen_string_literal: true
|
|
20
2
|
|
|
21
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2017-2026, by Samuel Williams.
|
|
22
5
|
|
|
23
6
|
module Build
|
|
24
7
|
module Dependency
|
|
8
|
+
# Generates Mermaid flowchart visualizations of dependency chains.
|
|
25
9
|
class Visualization
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
}
|
|
10
|
+
# Convert a name to a valid Mermaid node ID.
|
|
11
|
+
# @parameter name [String] The name to sanitize.
|
|
12
|
+
# @returns [String] A sanitized identifier safe for use in Mermaid diagrams.
|
|
13
|
+
def sanitize_id(name)
|
|
14
|
+
# Convert name to a valid Mermaid node ID
|
|
15
|
+
name.to_s.gsub(/[^a-zA-Z0-9_]/, "_")
|
|
60
16
|
end
|
|
61
17
|
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
18
|
+
# Generate a Mermaid flowchart diagram for a dependency chain.
|
|
19
|
+
# @parameter chain [Chain] The dependency chain to visualize.
|
|
20
|
+
# @returns [String] A Mermaid flowchart diagram in text format.
|
|
74
21
|
def generate(chain)
|
|
75
|
-
|
|
76
|
-
graph.attributes[:ratio] = :auto
|
|
22
|
+
lines = ["flowchart LR"]
|
|
77
23
|
|
|
78
|
-
|
|
24
|
+
# Track nodes and their styles
|
|
25
|
+
nodes = {}
|
|
26
|
+
providers = ::Set.new
|
|
27
|
+
provisions_in_chain = ::Set.new
|
|
28
|
+
|
|
29
|
+
# Collect all provisions in the chain
|
|
30
|
+
chain.provisions.each do |provision|
|
|
31
|
+
provisions_in_chain.add(provision.name.to_s)
|
|
32
|
+
end
|
|
79
33
|
|
|
34
|
+
# Build the graph
|
|
80
35
|
chain.ordered.each do |resolution|
|
|
81
36
|
provider = resolution.provider
|
|
82
|
-
name = provider.name
|
|
83
|
-
|
|
84
|
-
# Provider is the dependency that provides the dependency referred to by name.
|
|
85
|
-
node = graph.add_node(name.to_s, @base_attributes.dup)
|
|
37
|
+
name = provider.name.to_s
|
|
38
|
+
node_id = sanitize_id(name)
|
|
86
39
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
elsif chain.selection.include?(provider.name)
|
|
90
|
-
node.attributes.update(@selection_attributes)
|
|
91
|
-
end
|
|
40
|
+
# Track this node
|
|
41
|
+
nodes[name] = node_id
|
|
92
42
|
|
|
93
43
|
# A provision has dependencies...
|
|
94
44
|
provider.dependencies.each do |dependency|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
45
|
+
dep_name = dependency.name.to_s
|
|
46
|
+
dep_id = sanitize_id(dep_name)
|
|
47
|
+
|
|
48
|
+
nodes[dep_name] ||= dep_id
|
|
49
|
+
|
|
50
|
+
# Create edge from provider to dependency
|
|
51
|
+
if dependency.private?
|
|
52
|
+
lines << " #{node_id}[#{name}] -.-> #{dep_id}[#{dep_name}]"
|
|
53
|
+
else
|
|
54
|
+
lines << " #{node_id}[#{name}] --> #{dep_id}[#{dep_name}]"
|
|
101
55
|
end
|
|
102
56
|
end
|
|
103
57
|
|
|
104
58
|
# A provision provides other provisions...
|
|
105
59
|
provider.provisions.each do |provision_name, provision|
|
|
106
|
-
next if name == provision_name
|
|
60
|
+
next if name == provision_name.to_s
|
|
107
61
|
|
|
108
|
-
|
|
62
|
+
provision_str = provision_name.to_s
|
|
63
|
+
provision_id = sanitize_id(provision_str)
|
|
109
64
|
|
|
110
|
-
|
|
111
|
-
provides_node.attributes = @alias_attributes
|
|
112
|
-
end
|
|
65
|
+
nodes[provision_str] ||= provision_id
|
|
113
66
|
|
|
114
|
-
node
|
|
67
|
+
# Mark this node as a provider
|
|
68
|
+
providers.add(name)
|
|
115
69
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
edge.attributes.update(@provider_edge_attributes)
|
|
120
|
-
end
|
|
70
|
+
# Create edge from provision to provider (undirected)
|
|
71
|
+
lines << " #{provision_id}[#{provision_str}] --- #{node_id}[#{name}]"
|
|
121
72
|
end
|
|
122
73
|
end
|
|
123
74
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
75
|
+
# Add styling
|
|
76
|
+
lines << ""
|
|
77
|
+
lines << " %% Styles"
|
|
78
|
+
|
|
79
|
+
# Style providers with light blue
|
|
80
|
+
providers.each do |name|
|
|
81
|
+
lines << " style #{sanitize_id(name)} fill:#add8e6"
|
|
128
82
|
end
|
|
129
83
|
|
|
130
|
-
#
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
name = "subgraph-#{provider.name}"
|
|
135
|
-
|
|
136
|
-
subgraph = graph.nodes[name] || graph.add_subgraph(name, :rank => :same)
|
|
137
|
-
|
|
138
|
-
provider.dependencies.each do |dependency|
|
|
139
|
-
next if done.include? dependency
|
|
140
|
-
|
|
141
|
-
done << dependency
|
|
142
|
-
|
|
143
|
-
if dependency_node = graph.nodes[dependency.name.to_s]
|
|
144
|
-
subgraph.add_node(dependency_node.name)
|
|
145
|
-
end
|
|
84
|
+
# Highlight provisions in the chain with a thicker border
|
|
85
|
+
provisions_in_chain.each do |name|
|
|
86
|
+
if node_id = nodes[name]
|
|
87
|
+
lines << " style #{node_id} stroke-width:3px"
|
|
146
88
|
end
|
|
147
89
|
end
|
|
148
90
|
|
|
149
|
-
return
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
private
|
|
153
|
-
|
|
154
|
-
def dependencies_by_name(dependencies)
|
|
155
|
-
dependencies.map{|depends| [depends.name, depends]}.to_h
|
|
91
|
+
return lines.join("\n")
|
|
156
92
|
end
|
|
157
93
|
end
|
|
158
94
|
end
|