build 2.6.2 → 2.7.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/build_node.rb +63 -31
- data/lib/build/chain_node.rb +16 -26
- data/lib/build/controller.rb +26 -36
- data/lib/build/dependency_node.rb +28 -22
- data/lib/build/graphviz.rb +12 -26
- data/lib/build/name.rb +15 -24
- data/lib/build/provision_node.rb +28 -21
- data/lib/build/rule.rb +60 -23
- data/lib/build/rule_node.rb +16 -20
- data/lib/build/rulebook.rb +22 -22
- data/lib/build/task.rb +16 -25
- data/lib/build/version.rb +6 -20
- data/lib/build.rb +5 -20
- data/license.md +21 -0
- data/readme.md +47 -0
- data/releases.md +3 -0
- data.tar.gz.sig +0 -0
- metadata +11 -80
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '00349494157af5d057e1ee2a70c3b65c8dd6873fd60419e50f90cb47d2d77018'
|
|
4
|
+
data.tar.gz: 0131571a8d92702daba61ab85c00ede57e1856505ea06a39e504296759a8e123
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c3196a81c93111aa37ba354b225c5796d6c9600205e229a863865c84c7b29d4bf7e817af4a41a8db50ced349a1b68feb281708ac765e089d9dbe576496576fce
|
|
7
|
+
data.tar.gz: cce38609f20d57f6d751a5ba2ae80f321bc8d16eca34fb0f512d3b514d5695cc3bc418e9dee904ae1c821d10cd7cf67308fb13f1a28331d28889135f177a10fa
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/lib/build/build_node.rb
CHANGED
|
@@ -1,30 +1,21 @@
|
|
|
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
|
-
|
|
22
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
|
23
5
|
|
|
24
|
-
require
|
|
6
|
+
require "fileutils"
|
|
7
|
+
require "build/graph"
|
|
25
8
|
|
|
9
|
+
require "console/event/spawn"
|
|
10
|
+
|
|
11
|
+
# @namespace
|
|
26
12
|
module Build
|
|
13
|
+
# Represents a build graph node that applies a single provision to produce an output environment.
|
|
27
14
|
class BuildNode < Graph::Node
|
|
15
|
+
# Initialize the build node with an environment, provision, and arguments.
|
|
16
|
+
# @parameter environment [Build::Environment] The environment to build within.
|
|
17
|
+
# @parameter provision [Build::Dependency::Provision] The provision to apply.
|
|
18
|
+
# @parameter arguments [Array] Arguments passed to the provision constructor.
|
|
28
19
|
def initialize(environment, provision, arguments)
|
|
29
20
|
@environment = environment
|
|
30
21
|
@provision = provision
|
|
@@ -37,6 +28,7 @@ module Build
|
|
|
37
28
|
attr :provision
|
|
38
29
|
attr :arguments
|
|
39
30
|
|
|
31
|
+
# @returns [Boolean] Whether this node is equal to another.
|
|
40
32
|
def == other
|
|
41
33
|
super and
|
|
42
34
|
@environment == other.environment and
|
|
@@ -44,22 +36,28 @@ module Build
|
|
|
44
36
|
@arguments == other.arguments
|
|
45
37
|
end
|
|
46
38
|
|
|
39
|
+
# @returns [Integer] A hash value for this node.
|
|
47
40
|
def hash
|
|
48
41
|
super ^ @environment.hash ^ @provision.hash ^ @arguments.hash
|
|
49
42
|
end
|
|
50
43
|
|
|
44
|
+
# @returns [Class] The task class to use for building this node.
|
|
51
45
|
def task_class(parent_task)
|
|
52
46
|
task_class = Rulebook.for(@environment).with(BuildTask, environment: @environment)
|
|
53
47
|
end
|
|
54
48
|
|
|
49
|
+
# @returns [Build::Environment] A fresh copy of the environment for output.
|
|
55
50
|
def initial_environment
|
|
56
51
|
Build::Environment.new(@environment)
|
|
57
52
|
end
|
|
58
53
|
|
|
54
|
+
# @returns [String] The name of the environment.
|
|
59
55
|
def name
|
|
60
56
|
@environment.name
|
|
61
57
|
end
|
|
62
58
|
|
|
59
|
+
# Apply this node to the given task, constructing the output environment.
|
|
60
|
+
# @parameter task [Build::Task] The task context.
|
|
63
61
|
def apply!(task)
|
|
64
62
|
output_environment = self.initial_environment
|
|
65
63
|
|
|
@@ -71,7 +69,12 @@ module Build
|
|
|
71
69
|
|
|
72
70
|
# This task class serves as the base class for the environment specific task classes genearted when adding targets.
|
|
73
71
|
class BuildTask < Task
|
|
72
|
+
# Represents a failure when a spawned command exits with a non-zero status.
|
|
74
73
|
class CommandFailure < Graph::TransientError
|
|
74
|
+
# Initialize the failure with the task, arguments, and exit status.
|
|
75
|
+
# @parameter task [Build::BuildTask] The task that spawned the command.
|
|
76
|
+
# @parameter arguments [Array] The command arguments that were run.
|
|
77
|
+
# @parameter status [Process::Status] The exit status of the command.
|
|
75
78
|
def initialize(task, arguments, status)
|
|
76
79
|
@task = task
|
|
77
80
|
@arguments = arguments
|
|
@@ -80,6 +83,7 @@ module Build
|
|
|
80
83
|
super "#{File.basename(executable_name).inspect} exited with status #{@status.to_i}"
|
|
81
84
|
end
|
|
82
85
|
|
|
86
|
+
# @returns [String] The name of the executable that failed.
|
|
83
87
|
def executable_name
|
|
84
88
|
if @arguments[0].kind_of? Hash
|
|
85
89
|
@arguments[1]
|
|
@@ -95,13 +99,17 @@ module Build
|
|
|
95
99
|
|
|
96
100
|
attr_accessor :output_environment
|
|
97
101
|
|
|
102
|
+
# @returns [Boolean] Whether the node is dirty and commands should actually be executed.
|
|
98
103
|
def wet?
|
|
99
104
|
@node.dirty?
|
|
100
105
|
end
|
|
101
106
|
|
|
107
|
+
# Spawn a process if the node is dirty, raising {CommandFailure} on non-zero exit.
|
|
108
|
+
# @parameter arguments [Array] The command and its arguments.
|
|
109
|
+
# @parameter options [Hash] Options forwarded to the process group.
|
|
102
110
|
def spawn(*arguments, **options)
|
|
103
111
|
if wet?
|
|
104
|
-
|
|
112
|
+
Console.info(self){Console::Event::Spawn.for(*arguments, **options)}
|
|
105
113
|
status = @group.spawn(*arguments, **options)
|
|
106
114
|
|
|
107
115
|
if status != 0
|
|
@@ -110,70 +118,94 @@ module Build
|
|
|
110
118
|
end
|
|
111
119
|
end
|
|
112
120
|
|
|
121
|
+
# @returns [Hash] A flattened, exported shell environment hash.
|
|
113
122
|
def shell_environment
|
|
114
123
|
@shell_environment ||= environment.flatten.export
|
|
115
124
|
end
|
|
116
125
|
|
|
126
|
+
# Run a shell command within the task's environment.
|
|
127
|
+
# @parameter arguments [Array] The command and its arguments.
|
|
128
|
+
# @parameter options [Hash] Options forwarded to the process group.
|
|
117
129
|
def run!(*arguments, **options)
|
|
118
130
|
self.spawn(shell_environment, *arguments, **options)
|
|
119
131
|
end
|
|
120
132
|
|
|
133
|
+
# Touch a file, creating or updating its modification time.
|
|
134
|
+
# @parameter path [String] The file path to touch.
|
|
121
135
|
def touch(path)
|
|
122
136
|
return unless wet?
|
|
123
137
|
|
|
124
|
-
Console::Event::Spawn.for(
|
|
138
|
+
Console::Event::Spawn.for("touch", path).emit(self)
|
|
125
139
|
FileUtils.touch(path)
|
|
126
140
|
end
|
|
127
141
|
|
|
142
|
+
# Copy a file from source to destination.
|
|
143
|
+
# @parameter source_path [String] The source file path.
|
|
144
|
+
# @parameter destination_path [String] The destination file path.
|
|
128
145
|
def cp(source_path, destination_path)
|
|
129
146
|
return unless wet?
|
|
130
147
|
|
|
131
|
-
Console::Event::Spawn.for(
|
|
148
|
+
Console::Event::Spawn.for("cp", source_path, destination_path).emit(self)
|
|
132
149
|
FileUtils.copy(source_path, destination_path)
|
|
133
150
|
end
|
|
134
151
|
|
|
152
|
+
# Remove a file or directory recursively.
|
|
153
|
+
# @parameter path [String] The path to remove.
|
|
135
154
|
def rm(path)
|
|
136
155
|
return unless wet?
|
|
137
156
|
|
|
138
|
-
Console::Event::Spawn.for(
|
|
157
|
+
Console::Event::Spawn.for("rm", "-rf", path).emit(self)
|
|
139
158
|
FileUtils.rm_rf(path)
|
|
140
159
|
end
|
|
141
160
|
|
|
161
|
+
# Create a directory and all intermediate directories.
|
|
162
|
+
# @parameter path [String] The directory path to create.
|
|
142
163
|
def mkpath(path)
|
|
143
164
|
return unless wet?
|
|
144
165
|
|
|
145
166
|
unless File.exist?(path)
|
|
146
|
-
Console::Event::Spawn.for(
|
|
167
|
+
Console::Event::Spawn.for("mkdir", "-p", path).emit(self)
|
|
147
168
|
FileUtils.mkpath(path)
|
|
148
169
|
end
|
|
149
170
|
end
|
|
150
171
|
|
|
172
|
+
# Install a file to a destination path.
|
|
173
|
+
# @parameter source_path [String] The source file path.
|
|
174
|
+
# @parameter destination_path [String] The destination file path.
|
|
151
175
|
def install(source_path, destination_path)
|
|
152
176
|
return unless wet?
|
|
153
177
|
|
|
154
|
-
Console::Event::Spawn.for(
|
|
178
|
+
Console::Event::Spawn.for("install", source_path, destination_path).emit(self)
|
|
155
179
|
FileUtils.install(source_path, destination_path)
|
|
156
180
|
end
|
|
157
181
|
|
|
182
|
+
# Write data to a file.
|
|
183
|
+
# @parameter path [String] The destination file path.
|
|
184
|
+
# @parameter data [String] The data to write.
|
|
185
|
+
# @parameter mode [String] The file open mode.
|
|
158
186
|
def write(path, data, mode = "w")
|
|
159
187
|
return unless wet?
|
|
160
188
|
|
|
161
|
-
Console::Event::Spawn.for(
|
|
189
|
+
Console::Event::Spawn.for("write", path).emit(self, size: data.size)
|
|
162
190
|
File.open(path, mode) do |file|
|
|
163
191
|
file.write(data)
|
|
164
192
|
end
|
|
165
193
|
end
|
|
166
194
|
|
|
195
|
+
# Invoke a rule with the given arguments, normalising them and invoking the rule node.
|
|
196
|
+
# @parameter rule [Build::Rule] The rule to invoke.
|
|
197
|
+
# @parameter arguments [Hash] The arguments to pass to the rule.
|
|
198
|
+
# @returns [Object] The result of the rule, typically a file path.
|
|
167
199
|
def invoke_rule(rule, arguments, &block)
|
|
168
200
|
arguments = rule.normalize(arguments, self)
|
|
169
201
|
|
|
170
|
-
|
|
202
|
+
Console.debug(self){"-> #{rule}(#{arguments.inspect})"}
|
|
171
203
|
|
|
172
204
|
invoke(
|
|
173
205
|
RuleNode.new(rule, arguments, &block)
|
|
174
206
|
)
|
|
175
207
|
|
|
176
|
-
|
|
208
|
+
Console.debug(self){"<- #{rule}(...) -> #{rule.result(arguments)}"}
|
|
177
209
|
|
|
178
210
|
return rule.result(arguments)
|
|
179
211
|
end
|
data/lib/build/chain_node.rb
CHANGED
|
@@ -1,35 +1,20 @@
|
|
|
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
|
-
|
|
22
|
-
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2016-2019, by Samuel Williams.
|
|
23
5
|
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
require "build/files"
|
|
7
|
+
require "build/graph"
|
|
8
|
+
|
|
9
|
+
require_relative "task"
|
|
10
|
+
require_relative "dependency_node"
|
|
26
11
|
|
|
27
12
|
module Build
|
|
28
13
|
# Responsible for processing a chain into a series of dependency nodes.
|
|
29
14
|
class ChainNode < Graph::Node
|
|
30
|
-
# @
|
|
31
|
-
# @
|
|
32
|
-
# @
|
|
15
|
+
# @parameter chain [Chain] the chain to build.
|
|
16
|
+
# @parameter arguments [Array] the arguments to pass to the output environment constructor.
|
|
17
|
+
# @parameter environment [Build::Environment] the root environment to prepend into the chain.
|
|
33
18
|
def initialize(chain, arguments, environment)
|
|
34
19
|
@chain = chain
|
|
35
20
|
@arguments = arguments
|
|
@@ -43,6 +28,7 @@ module Build
|
|
|
43
28
|
attr :arguments
|
|
44
29
|
attr :environment
|
|
45
30
|
|
|
31
|
+
# @returns [Boolean] Whether this node is equal to another.
|
|
46
32
|
def == other
|
|
47
33
|
super and
|
|
48
34
|
@chain == other.chain and
|
|
@@ -50,14 +36,17 @@ module Build
|
|
|
50
36
|
@environment == other.environment
|
|
51
37
|
end
|
|
52
38
|
|
|
39
|
+
# @returns [Integer] A hash value for this node.
|
|
53
40
|
def hash
|
|
54
41
|
super ^ @chain.hash ^ @arguments.hash ^ @environment.hash
|
|
55
42
|
end
|
|
56
43
|
|
|
44
|
+
# @returns [Class] The task class to use for this node.
|
|
57
45
|
def task_class(parent_task)
|
|
58
46
|
Task
|
|
59
47
|
end
|
|
60
48
|
|
|
49
|
+
# @returns [String] The name of the environment.
|
|
61
50
|
def name
|
|
62
51
|
@environment.name
|
|
63
52
|
end
|
|
@@ -72,6 +61,7 @@ module Build
|
|
|
72
61
|
end
|
|
73
62
|
end
|
|
74
63
|
|
|
64
|
+
# @returns [String] A human-readable representation of this node.
|
|
75
65
|
def inspect
|
|
76
66
|
"#<#{self.class} #{@environment.inspect}>"
|
|
77
67
|
end
|
data/lib/build/controller.rb
CHANGED
|
@@ -1,44 +1,30 @@
|
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
require 'build/environment'
|
|
24
|
-
require 'process/group'
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2015-2019, by Samuel Williams.
|
|
25
5
|
|
|
26
|
-
|
|
27
|
-
|
|
6
|
+
require "build/files"
|
|
7
|
+
require "build/makefile"
|
|
8
|
+
require "build/environment"
|
|
9
|
+
require "process/group"
|
|
28
10
|
|
|
29
|
-
require_relative
|
|
30
|
-
require_relative
|
|
31
|
-
require_relative 'task'
|
|
11
|
+
require_relative "rulebook"
|
|
12
|
+
require_relative "name"
|
|
32
13
|
|
|
33
|
-
|
|
14
|
+
require_relative "rule_node"
|
|
15
|
+
require_relative "chain_node"
|
|
16
|
+
require_relative "task"
|
|
17
|
+
|
|
18
|
+
require "console"
|
|
34
19
|
|
|
35
20
|
module Build
|
|
21
|
+
# Represents the top-level build controller that manages the walker and process group.
|
|
36
22
|
class Controller
|
|
37
|
-
|
|
23
|
+
# Initialize the controller, yielding self to allow adding chain nodes.
|
|
24
|
+
# @parameter limit [Integer | Nil] Maximum number of concurrent processes.
|
|
25
|
+
def initialize(limit: nil)
|
|
38
26
|
@module = Module.new
|
|
39
27
|
|
|
40
|
-
@logger = logger
|
|
41
|
-
|
|
42
28
|
# Top level nodes, for sanity this is a static list.
|
|
43
29
|
@nodes = []
|
|
44
30
|
yield self
|
|
@@ -49,23 +35,26 @@ module Build
|
|
|
49
35
|
# The task class is captured as we traverse all the top level targets:
|
|
50
36
|
@task_class = nil
|
|
51
37
|
|
|
52
|
-
@walker = Graph::Walker.new(
|
|
38
|
+
@walker = Graph::Walker.new(&self.method(:step))
|
|
53
39
|
end
|
|
54
40
|
|
|
55
|
-
attr :logger
|
|
56
|
-
|
|
57
41
|
attr :nodes
|
|
58
42
|
attr :walker
|
|
59
43
|
|
|
44
|
+
# Execute a single step of the build graph for the given node.
|
|
45
|
+
# @parameter walker [Build::Graph::Walker] The graph walker.
|
|
46
|
+
# @parameter node [Build::Graph::Node] The node to process.
|
|
47
|
+
# @parameter parent_task [Build::Task | Nil] The parent task, if any.
|
|
60
48
|
def step(walker, node, parent_task = nil)
|
|
61
49
|
task_class = node.task_class(parent_task) || Task
|
|
62
|
-
task = task_class.new(walker, node, @group
|
|
50
|
+
task = task_class.new(walker, node, @group)
|
|
63
51
|
|
|
64
52
|
task.visit do
|
|
65
53
|
task.update
|
|
66
54
|
end
|
|
67
55
|
end
|
|
68
56
|
|
|
57
|
+
# @returns [Boolean] Whether the build has failed.
|
|
69
58
|
def failed?
|
|
70
59
|
@walker.failed?
|
|
71
60
|
end
|
|
@@ -75,6 +64,7 @@ module Build
|
|
|
75
64
|
@nodes << ChainNode.new(chain, arguments, environment)
|
|
76
65
|
end
|
|
77
66
|
|
|
67
|
+
# Execute all top-level nodes, waiting for each to complete.
|
|
78
68
|
def update
|
|
79
69
|
@nodes.each do |node|
|
|
80
70
|
# We wait for all processes to complete within each node. The result is that we don't execute top level nodes concurrently, but we do execute within each node concurrently where possible. Ideally, some node could be executed concurrently, but right now expressing non-file dependencies between nodes is not possible.
|
|
@@ -1,29 +1,20 @@
|
|
|
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, by Samuel Williams.
|
|
22
5
|
|
|
23
|
-
|
|
6
|
+
require "build/graph"
|
|
7
|
+
|
|
8
|
+
require_relative "provision_node"
|
|
24
9
|
|
|
25
10
|
module Build
|
|
11
|
+
# Represents a build graph node for resolving and building a single dependency.
|
|
26
12
|
class DependencyNode < Graph::Node
|
|
13
|
+
# Initialize the dependency node.
|
|
14
|
+
# @parameter chain [Build::Dependency::Chain] The dependency chain.
|
|
15
|
+
# @parameter dependency [Build::Dependency] The dependency to resolve.
|
|
16
|
+
# @parameter environment [Build::Environment] The root environment.
|
|
17
|
+
# @parameter arguments [Array] Arguments passed down the build chain.
|
|
27
18
|
def initialize(chain, dependency, environment, arguments)
|
|
28
19
|
@chain = chain
|
|
29
20
|
@dependency = dependency
|
|
@@ -39,6 +30,7 @@ module Build
|
|
|
39
30
|
attr :environment
|
|
40
31
|
attr :arguments
|
|
41
32
|
|
|
33
|
+
# @returns [Boolean] Whether this node is equal to another.
|
|
42
34
|
def == other
|
|
43
35
|
super and
|
|
44
36
|
@chain == other.chain and
|
|
@@ -47,38 +39,50 @@ module Build
|
|
|
47
39
|
@arguments == other.arguments
|
|
48
40
|
end
|
|
49
41
|
|
|
42
|
+
# @returns [Integer] A hash value for this node.
|
|
50
43
|
def hash
|
|
51
44
|
super ^ @chain.hash ^ @dependency.hash ^ @environment.hash ^ @arguments.hash
|
|
52
45
|
end
|
|
53
46
|
|
|
47
|
+
# @returns [Class] The task class to use for this node.
|
|
54
48
|
def task_class(parent_task)
|
|
55
49
|
DependencyTask
|
|
56
50
|
end
|
|
57
51
|
|
|
52
|
+
# @returns [String] The name of the dependency.
|
|
58
53
|
def name
|
|
59
54
|
@dependency.name
|
|
60
55
|
end
|
|
61
56
|
|
|
57
|
+
# @returns [Array] The provisions resolved for this dependency.
|
|
62
58
|
def provisions
|
|
63
59
|
@chain.resolved[@dependency]
|
|
64
60
|
end
|
|
65
61
|
|
|
62
|
+
# @returns [Boolean] Whether this dependency is public.
|
|
66
63
|
def public?
|
|
67
64
|
@dependency.public?
|
|
68
65
|
end
|
|
69
66
|
|
|
67
|
+
# Build a {ProvisionNode} for the given provision.
|
|
68
|
+
# @parameter provision [Build::Dependency::Provision] The provision to wrap.
|
|
69
|
+
# @returns [Build::ProvisionNode] The corresponding provision node.
|
|
70
70
|
def provision_node_for(provision)
|
|
71
71
|
ProvisionNode.new(@chain, provision, @environment, @arguments)
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
# @namespace
|
|
75
76
|
module ProvisionsFailed
|
|
77
|
+
# @returns [String] A description of the failure.
|
|
76
78
|
def self.to_s
|
|
77
79
|
"Failed to build all provisions!"
|
|
78
80
|
end
|
|
79
81
|
end
|
|
80
82
|
|
|
83
|
+
# Represents a task that resolves and builds all provisions for a dependency.
|
|
81
84
|
class DependencyTask < Task
|
|
85
|
+
# Initialize the dependency task.
|
|
82
86
|
def initialize(*arguments, **options)
|
|
83
87
|
super
|
|
84
88
|
|
|
@@ -90,12 +94,14 @@ module Build
|
|
|
90
94
|
|
|
91
95
|
attr :environment
|
|
92
96
|
|
|
97
|
+
# @returns [Build::Dependency] The dependency being resolved by this task.
|
|
93
98
|
def dependency
|
|
94
99
|
@node.dependency
|
|
95
100
|
end
|
|
96
101
|
|
|
102
|
+
# Build all provisions for the dependency and combine the resulting environments.
|
|
97
103
|
def update
|
|
98
|
-
|
|
104
|
+
Console.debug(self) do |buffer|
|
|
99
105
|
buffer.puts "building #{@node} which #{@node.dependency}"
|
|
100
106
|
@node.provisions.each do |provision|
|
|
101
107
|
buffer.puts "\tbuilding #{provision.provider.name} which #{provision}"
|
data/lib/build/graphviz.rb
CHANGED
|
@@ -1,37 +1,25 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2015, by Samuel Williams.
|
|
20
5
|
|
|
21
6
|
module Build
|
|
7
|
+
# Generate a Graphviz graph visualisation of the build graph.
|
|
8
|
+
# @parameter walker [Build::Graph::Walker] The completed walker containing tasks.
|
|
9
|
+
# @returns [Graphviz::Graph] A graph object ready for rendering.
|
|
22
10
|
def self.graph_visualisation(walker)
|
|
23
|
-
|
|
11
|
+
graph = Graphviz::Graph.new("G", rankdir: "LR")
|
|
24
12
|
|
|
25
13
|
walker.tasks.each do |node, task|
|
|
26
14
|
input_nodes = []
|
|
27
15
|
output_nodes = []
|
|
28
16
|
|
|
29
17
|
task.inputs.each do |path|
|
|
30
|
-
input_nodes <<
|
|
18
|
+
input_nodes << graph.add_node(path.basename)
|
|
31
19
|
end
|
|
32
20
|
|
|
33
21
|
task.outputs.each do |path|
|
|
34
|
-
output_nodes <<
|
|
22
|
+
output_nodes << graph.add_node(path.basename)
|
|
35
23
|
end
|
|
36
24
|
|
|
37
25
|
if output_nodes.size == 1
|
|
@@ -41,9 +29,7 @@ module Build
|
|
|
41
29
|
end
|
|
42
30
|
end
|
|
43
31
|
end
|
|
44
|
-
|
|
45
|
-
return
|
|
46
|
-
#Graphviz::output(viz, path: ENV['BUILD_GRAPH_PDF']) rescue nil
|
|
47
|
-
#`dot -Tpdf graph.dot > graph.pdf && open graph.pdf`
|
|
32
|
+
|
|
33
|
+
return graph
|
|
48
34
|
end
|
|
49
35
|
end
|
data/lib/build/name.rb
CHANGED
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2015-2019, by Samuel Williams.
|
|
20
5
|
|
|
21
6
|
module Build
|
|
7
|
+
# Represents a human-readable name with helpers for generating identifiers, target names, and macros.
|
|
22
8
|
class Name
|
|
9
|
+
# Initialize the name with the given text.
|
|
10
|
+
# @parameter text [String] The human-readable name text.
|
|
23
11
|
def initialize(text)
|
|
24
12
|
@text = text
|
|
25
13
|
|
|
@@ -28,6 +16,9 @@ module Build
|
|
|
28
16
|
@key = nil
|
|
29
17
|
end
|
|
30
18
|
|
|
19
|
+
# Construct a {Name} from a hyphen-separated target name string.
|
|
20
|
+
# @parameter string [String] A target name such as `"foo-bar"`.
|
|
21
|
+
# @returns [Build::Name] The corresponding name instance.
|
|
31
22
|
def self.from_target(string)
|
|
32
23
|
self.new(string.gsub(/(^|[ \-_])(.)/){" " + $2.upcase}.strip)
|
|
33
24
|
end
|
|
@@ -36,27 +27,27 @@ module Build
|
|
|
36
27
|
|
|
37
28
|
# @return [String] suitable for constant identifier.
|
|
38
29
|
def identifier
|
|
39
|
-
@identifier ||= @text.gsub(/\s+/,
|
|
30
|
+
@identifier ||= @text.gsub(/\s+/, "")
|
|
40
31
|
end
|
|
41
32
|
|
|
42
33
|
# @return [String] suitable for target name.
|
|
43
34
|
def target
|
|
44
|
-
@target ||= @text.gsub(/\s+/,
|
|
35
|
+
@target ||= @text.gsub(/\s+/, "-").downcase
|
|
45
36
|
end
|
|
46
37
|
|
|
47
38
|
# @return [String] suitable for variable name.
|
|
48
39
|
def key(*postfix)
|
|
49
|
-
@key ||= ([@text] + postfix).collect{|part| part.downcase.gsub(/\s+/,
|
|
40
|
+
@key ||= ([@text] + postfix).collect{|part| part.downcase.gsub(/\s+/, "_")}.join("_")
|
|
50
41
|
end
|
|
51
42
|
|
|
52
43
|
# @return [String] suitable for C macro name.
|
|
53
44
|
def macro(prefix = [])
|
|
54
|
-
(Array(prefix) + [@text]).collect{|name| name.upcase.gsub(/\s+/,
|
|
45
|
+
(Array(prefix) + [@text]).collect{|name| name.upcase.gsub(/\s+/, "_")}.join("_")
|
|
55
46
|
end
|
|
56
47
|
|
|
57
48
|
# @return [String] suitable for C header guard macro.
|
|
58
49
|
def header_guard(path)
|
|
59
|
-
macro(path) +
|
|
50
|
+
macro(path) + "_H"
|
|
60
51
|
end
|
|
61
52
|
end
|
|
62
53
|
end
|