build 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/Gemfile.local +24 -0
- data/build.gemspec +1 -1
- data/lib/build/controller.rb +40 -189
- data/lib/build/logger.rb +47 -16
- data/lib/build/rule_node.rb +56 -0
- data/lib/build/target_node.rb +52 -0
- data/lib/build/task.rb +134 -0
- data/lib/build/version.rb +1 -1
- data/spec/build/controller_spec.rb +9 -6
- data/spec/build/name_spec.rb +1 -1
- data/spec/build/rulebook_spec.rb +2 -2
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2e4b99a0ca6f133e2a922246935b5fea4df8565
|
4
|
+
data.tar.gz: 0cf67127a7ade2972d912feea1d7f60b52059185
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07d415c3b548005c3967c347777a58e0681d4af33837bfa0c45d765a05c271091f1a0530d489673b88ff732517602f1cf4047ca075d5a851a29a2f010f56787e
|
7
|
+
data.tar.gz: 3af3c5c22e15a4d4abc272f1690f0ca49383e2715053589df1bc7aff10399ad19a988ffc3d6312b99301c4e1e15d78d28bc01063eea0dfe11576e5580a2375b6
|
data/.travis.yml
CHANGED
data/Gemfile.local
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in build.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'pry'
|
8
|
+
gem 'pry-coolline'
|
9
|
+
|
10
|
+
gem 'build-environment', path: '../build-environment'
|
11
|
+
gem 'build-files', path: '../build-files'
|
12
|
+
gem 'build-graph', path: '../build-graph'
|
13
|
+
gem 'build-makefile', path: '../build-makefile'
|
14
|
+
|
15
|
+
gem 'process-daemon', path: '../process-daemon'
|
16
|
+
gem 'process-group', path: '../process-group'
|
17
|
+
|
18
|
+
gem 'graphviz', path: '../graphviz'
|
19
|
+
end
|
20
|
+
|
21
|
+
group :test do
|
22
|
+
gem 'simplecov'
|
23
|
+
gem 'coveralls', require: false
|
24
|
+
end
|
data/build.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.required_ruby_version = '>= 2.0'
|
21
21
|
|
22
|
-
spec.add_dependency "build-graph", "~> 1.0.
|
22
|
+
spec.add_dependency "build-graph", "~> 1.0.4"
|
23
23
|
spec.add_dependency "build-environment", "~> 1.1.3"
|
24
24
|
spec.add_dependency "build-makefile", "~> 1.0.0"
|
25
25
|
|
data/lib/build/controller.rb
CHANGED
@@ -18,178 +18,21 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require_relative 'rulebook'
|
22
|
-
require_relative 'name'
|
23
|
-
|
24
21
|
require 'build/files'
|
25
|
-
require 'build/graph'
|
26
22
|
require 'build/makefile'
|
27
|
-
|
23
|
+
require 'build/environment'
|
28
24
|
require 'process/group'
|
29
25
|
|
26
|
+
require_relative 'rulebook'
|
27
|
+
require_relative 'name'
|
28
|
+
|
29
|
+
require_relative 'rule_node'
|
30
|
+
require_relative 'target_node'
|
31
|
+
require_relative 'task'
|
32
|
+
|
30
33
|
require_relative 'logger'
|
31
34
|
|
32
35
|
module Build
|
33
|
-
class RuleNode < Graph::Node
|
34
|
-
def initialize(rule, arguments, &block)
|
35
|
-
@arguments = arguments
|
36
|
-
@rule = rule
|
37
|
-
|
38
|
-
@callback = block
|
39
|
-
|
40
|
-
inputs, outputs = @rule.files(@arguments)
|
41
|
-
|
42
|
-
super(inputs, outputs, @rule)
|
43
|
-
end
|
44
|
-
|
45
|
-
attr :arguments
|
46
|
-
attr :rule
|
47
|
-
attr :callback
|
48
|
-
|
49
|
-
def name
|
50
|
-
@rule.name
|
51
|
-
end
|
52
|
-
|
53
|
-
def apply!(scope)
|
54
|
-
@rule.apply!(scope, @arguments)
|
55
|
-
|
56
|
-
if @callback
|
57
|
-
scope.instance_exec(@arguments, &@callback)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def inspect
|
62
|
-
@rule.name.inspect
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class TargetNode < Graph::Node
|
67
|
-
def initialize(task_class, &update)
|
68
|
-
@update = update
|
69
|
-
@task_class = task_class
|
70
|
-
|
71
|
-
super(Files::Paths::NONE, :inherit, @update)
|
72
|
-
end
|
73
|
-
|
74
|
-
attr :task_class
|
75
|
-
|
76
|
-
def apply!(scope)
|
77
|
-
scope.instance_exec(&@update)
|
78
|
-
end
|
79
|
-
|
80
|
-
def inspect
|
81
|
-
@task_class.name.inspect
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# This task class serves as the base class for the environment specific task classes genearted when adding targets.
|
86
|
-
class Task < Graph::Task
|
87
|
-
class CommandFailure < StandardError
|
88
|
-
def initialize(task, arguments, status)
|
89
|
-
@task = task
|
90
|
-
@arguments = arguments
|
91
|
-
@status = status
|
92
|
-
|
93
|
-
super "#{@arguments.first} exited with status #{@status}"
|
94
|
-
end
|
95
|
-
|
96
|
-
attr :task
|
97
|
-
attr :arguments
|
98
|
-
attr :status
|
99
|
-
end
|
100
|
-
|
101
|
-
def initialize(walker, node, group, logger: nil)
|
102
|
-
super(walker, node)
|
103
|
-
|
104
|
-
@group = group
|
105
|
-
|
106
|
-
@logger = logger || Logger.new($stderr)
|
107
|
-
end
|
108
|
-
|
109
|
-
def wet?
|
110
|
-
@node.dirty?
|
111
|
-
end
|
112
|
-
|
113
|
-
def spawn(*arguments)
|
114
|
-
if wet?
|
115
|
-
@logger.info('shell') {arguments}
|
116
|
-
status = @group.spawn(*arguments)
|
117
|
-
|
118
|
-
if status != 0
|
119
|
-
raise CommandFailure.new(self, arguments, status)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def shell_environment
|
125
|
-
@shell_environment ||= environment.flatten.export
|
126
|
-
end
|
127
|
-
|
128
|
-
def run!(*arguments)
|
129
|
-
self.spawn(shell_environment, *arguments)
|
130
|
-
end
|
131
|
-
|
132
|
-
def touch(path)
|
133
|
-
return unless wet?
|
134
|
-
|
135
|
-
@logger.info('shell'){ ['touch', path] }
|
136
|
-
FileUtils.touch(path)
|
137
|
-
end
|
138
|
-
|
139
|
-
def cp(source_path, destination_path)
|
140
|
-
return unless wet?
|
141
|
-
|
142
|
-
@logger.info('shell'){ ['cp', source_path, destination_path]}
|
143
|
-
FileUtils.copy(source_path, destination_path)
|
144
|
-
end
|
145
|
-
|
146
|
-
def rm(path)
|
147
|
-
return unless wet?
|
148
|
-
|
149
|
-
@logger.info('shell'){ ['rm -rf', path] }
|
150
|
-
FileUtils.rm_rf(path)
|
151
|
-
end
|
152
|
-
|
153
|
-
def mkpath(path)
|
154
|
-
return unless wet?
|
155
|
-
|
156
|
-
unless File.exist?(path)
|
157
|
-
@logger.info('shell'){ ['mkpath', path] }
|
158
|
-
|
159
|
-
FileUtils.mkpath(path)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def install(source_path, destination_path)
|
164
|
-
return unless wet?
|
165
|
-
|
166
|
-
@logger.info('shell'){ ['install', source_path, destination_path]}
|
167
|
-
FileUtils.install(source_path, destination_path)
|
168
|
-
end
|
169
|
-
|
170
|
-
# Legacy FileUtils access, replaced with direct function calls.
|
171
|
-
def fs
|
172
|
-
self
|
173
|
-
end
|
174
|
-
|
175
|
-
def update
|
176
|
-
@node.apply!(self)
|
177
|
-
end
|
178
|
-
|
179
|
-
def invoke_rule(rule, arguments, &block)
|
180
|
-
arguments = rule.normalize(arguments, self)
|
181
|
-
|
182
|
-
@logger.debug('invoke') {"-> #{rule}: #{arguments.inspect}"}
|
183
|
-
|
184
|
-
node = RuleNode.new(rule, arguments, &block)
|
185
|
-
task = invoke(node)
|
186
|
-
|
187
|
-
@logger.debug('invoke') {"<- #{rule}: #{rule.result(arguments)}"}
|
188
|
-
|
189
|
-
return rule.result(arguments)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
36
|
class Controller
|
194
37
|
def initialize(logger: nil, limit: nil)
|
195
38
|
@module = Module.new
|
@@ -199,11 +42,9 @@ module Build
|
|
199
42
|
logger.formatter = CompactFormatter.new
|
200
43
|
end
|
201
44
|
|
202
|
-
# Top level nodes
|
45
|
+
# Top level nodes, for sanity this is a static list.
|
203
46
|
@nodes = []
|
204
|
-
|
205
47
|
yield self
|
206
|
-
|
207
48
|
@nodes.freeze
|
208
49
|
|
209
50
|
@group = Process::Group.new(limit: limit)
|
@@ -211,44 +52,54 @@ module Build
|
|
211
52
|
# The task class is captured as we traverse all the top level targets:
|
212
53
|
@task_class = nil
|
213
54
|
|
214
|
-
@walker = Graph::Walker.new
|
215
|
-
# Instantiate the task class here:
|
216
|
-
task = @task_class.new(walker, node, @group, logger: @logger)
|
217
|
-
|
218
|
-
task.visit do
|
219
|
-
task.update
|
220
|
-
end
|
221
|
-
end
|
55
|
+
@walker = Graph::Walker.new(logger: @logger, &self.method(:step))
|
222
56
|
end
|
223
57
|
|
58
|
+
attr :logger
|
59
|
+
|
224
60
|
attr :nodes
|
225
|
-
attr :
|
61
|
+
attr :walker
|
226
62
|
|
63
|
+
private def step(walker, node, task_class:)
|
64
|
+
task = task_class.new(walker, node, @group, logger: @logger)
|
65
|
+
|
66
|
+
task.visit do
|
67
|
+
task.update
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def failed?
|
72
|
+
@walker.failed?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add a build target to the controller.
|
227
76
|
def add_target(target, environment)
|
228
77
|
task_class = Rulebook.for(environment).with(Task, environment: environment, target: target)
|
229
78
|
|
230
79
|
# Not sure if this is a good idea - makes debugging slightly easier.
|
231
|
-
Object.const_set("TaskClassFor#{Name.from_target(target.name).identifier}_#{
|
80
|
+
Object.const_set("TaskClassFor#{Name.from_target(target.name).identifier}_#{task_class.object_id}", task_class)
|
232
81
|
|
233
|
-
|
82
|
+
# A target node will invoke the build callback on target.
|
83
|
+
@nodes << TargetNode.new(task_class, target)
|
84
|
+
|
85
|
+
return @nodes.last
|
234
86
|
end
|
235
87
|
|
236
88
|
def update
|
237
89
|
@nodes.each do |node|
|
238
|
-
#
|
239
|
-
@
|
240
|
-
|
241
|
-
|
90
|
+
# 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.
|
91
|
+
@group.wait do
|
92
|
+
@walker.call(node, task_class: node.task_class)
|
93
|
+
end
|
242
94
|
end
|
243
|
-
|
244
|
-
@group.wait
|
245
|
-
|
246
|
-
yield @walker if block_given?
|
247
95
|
end
|
248
96
|
|
249
|
-
|
97
|
+
# The entry point for running the walker over the build graph.
|
98
|
+
def run
|
250
99
|
@walker.run do
|
251
|
-
self.update
|
100
|
+
self.update
|
101
|
+
|
102
|
+
yield @walker if block_given?
|
252
103
|
end
|
253
104
|
end
|
254
105
|
end
|
data/lib/build/logger.rb
CHANGED
@@ -28,10 +28,16 @@ module Build
|
|
28
28
|
@verbose = verbose
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
31
|
+
def time_offset_prefix
|
32
32
|
offset = Time.now - @start
|
33
|
+
minutes = (offset/60).floor
|
34
|
+
seconds = (offset - (minutes*60))
|
33
35
|
|
34
|
-
|
36
|
+
if minutes > 0
|
37
|
+
"#{minutes}m#{seconds.floor}s"
|
38
|
+
else
|
39
|
+
"#{seconds.round(2)}s"
|
40
|
+
end.rjust(6)
|
35
41
|
end
|
36
42
|
|
37
43
|
def chdir_string(options)
|
@@ -42,35 +48,60 @@ module Build
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
45
|
-
def format_command(arguments)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
options = {}
|
51
|
-
end
|
51
|
+
def format_command(arguments, buffer)
|
52
|
+
arguments = arguments.dup
|
53
|
+
|
54
|
+
environment = arguments.first.is_a?(Hash) ? arguments.shift : nil
|
55
|
+
options = arguments.last.is_a?(Hash) ? arguments.pop : nil
|
52
56
|
|
53
57
|
arguments = arguments.flatten.collect(&:to_s)
|
54
58
|
|
55
|
-
Rainbow(arguments.join(' ')).blue
|
59
|
+
buffer << Rainbow(arguments.join(' ')).bright.blue
|
60
|
+
|
61
|
+
if options
|
62
|
+
buffer << chdir_string(options)
|
63
|
+
end
|
64
|
+
|
65
|
+
buffer << "\n"
|
66
|
+
|
67
|
+
# if environment
|
68
|
+
# environment.each do |key,value|
|
69
|
+
# buffer << "\texport #{key}=#{value.dump}\n"
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
end
|
73
|
+
|
74
|
+
def format_exception(exception, buffer)
|
75
|
+
buffer << Rainbow("#{exception.class}: #{exception}").bright.red << "\n"
|
76
|
+
exception.backtrace.each do |line|
|
77
|
+
buffer << "\t" << Rainbow(line).red << "\n"
|
78
|
+
end
|
56
79
|
end
|
57
80
|
|
58
81
|
def call(severity, datetime, progname, message)
|
59
82
|
buffer = []
|
83
|
+
prefix = ""
|
60
84
|
|
61
85
|
if @verbose
|
62
|
-
|
86
|
+
prefix = time_offset_prefix
|
87
|
+
buffer << Rainbow(prefix).cyan + ": "
|
88
|
+
prefix = " " * (prefix.size) + "| "
|
63
89
|
end
|
64
90
|
|
65
|
-
if progname == 'shell' and Array
|
66
|
-
|
91
|
+
if progname == 'shell' and message.kind_of? Array
|
92
|
+
format_command(message, buffer)
|
93
|
+
elsif message.kind_of? Exception
|
94
|
+
format_exception(message, buffer)
|
67
95
|
else
|
68
|
-
buffer << message
|
96
|
+
buffer << message << "\n"
|
69
97
|
end
|
70
98
|
|
71
|
-
|
99
|
+
result = buffer.join
|
100
|
+
|
101
|
+
# This fancy regex indents lines correctly depending on the prefix:
|
102
|
+
result.gsub!(/\n(?!$)/, "\n#{prefix}") unless prefix.empty?
|
72
103
|
|
73
|
-
return
|
104
|
+
return result
|
74
105
|
end
|
75
106
|
end
|
76
107
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright, 2012, 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 'build/graph'
|
22
|
+
|
23
|
+
module Build
|
24
|
+
class RuleNode < Graph::Node
|
25
|
+
def initialize(rule, arguments, &block)
|
26
|
+
@arguments = arguments
|
27
|
+
@rule = rule
|
28
|
+
|
29
|
+
@callback = block
|
30
|
+
|
31
|
+
inputs, outputs = @rule.files(@arguments)
|
32
|
+
|
33
|
+
super(inputs, outputs, @rule)
|
34
|
+
end
|
35
|
+
|
36
|
+
attr :arguments
|
37
|
+
attr :rule
|
38
|
+
attr :callback
|
39
|
+
|
40
|
+
def name
|
41
|
+
@rule.name
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply!(scope)
|
45
|
+
@rule.apply!(scope, @arguments)
|
46
|
+
|
47
|
+
if @callback
|
48
|
+
scope.instance_exec(@arguments, &@callback)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def inspect
|
53
|
+
@rule.name.inspect
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright, 2016, 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 'build/files'
|
22
|
+
require 'build/graph'
|
23
|
+
|
24
|
+
module Build
|
25
|
+
class TargetNode < Graph::Node
|
26
|
+
def initialize(task_class, target)
|
27
|
+
@target = target
|
28
|
+
@task_class = task_class
|
29
|
+
|
30
|
+
# Wait here, for all dependent targets, to be done:
|
31
|
+
super(Files::List::NONE, :inherit, target)
|
32
|
+
end
|
33
|
+
|
34
|
+
attr :task_class
|
35
|
+
|
36
|
+
def name
|
37
|
+
@task_class.name
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply!(scope)
|
41
|
+
scope.instance_exec(&@target.build)
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
@task_class.name.inspect
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
"#<#{self.class} #{@target.name}>"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/build/task.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# Copyright, 2016, 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 'fileutils'
|
22
|
+
require 'build/graph'
|
23
|
+
|
24
|
+
module Build
|
25
|
+
# This task class serves as the base class for the environment specific task classes genearted when adding targets.
|
26
|
+
class Task < Graph::Task
|
27
|
+
class CommandFailure < Graph::TransientError
|
28
|
+
def initialize(task, arguments, status)
|
29
|
+
@task = task
|
30
|
+
@arguments = arguments
|
31
|
+
@status = status
|
32
|
+
|
33
|
+
@command_name = arguments.find{|part| part.kind_of? String}
|
34
|
+
|
35
|
+
super "#{@command_name.inspect} exited with status #{@status}"
|
36
|
+
end
|
37
|
+
|
38
|
+
attr :task
|
39
|
+
attr :arguments
|
40
|
+
attr :status
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(walker, node, group, logger: nil)
|
44
|
+
super(walker, node)
|
45
|
+
|
46
|
+
@group = group
|
47
|
+
|
48
|
+
@logger = logger || Logger.new($stderr)
|
49
|
+
end
|
50
|
+
|
51
|
+
def wet?
|
52
|
+
@node.dirty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def spawn(*arguments)
|
56
|
+
if wet?
|
57
|
+
@logger.info('shell') {arguments}
|
58
|
+
status = @group.spawn(*arguments)
|
59
|
+
|
60
|
+
if status != 0
|
61
|
+
raise CommandFailure.new(self, arguments, status)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def shell_environment
|
67
|
+
@shell_environment ||= environment.flatten.export
|
68
|
+
end
|
69
|
+
|
70
|
+
def run!(*arguments)
|
71
|
+
self.spawn(shell_environment, *arguments)
|
72
|
+
end
|
73
|
+
|
74
|
+
def touch(path)
|
75
|
+
return unless wet?
|
76
|
+
|
77
|
+
@logger.info('shell'){ ['touch', path] }
|
78
|
+
FileUtils.touch(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def cp(source_path, destination_path)
|
82
|
+
return unless wet?
|
83
|
+
|
84
|
+
@logger.info('shell'){ ['cp', source_path, destination_path]}
|
85
|
+
FileUtils.copy(source_path, destination_path)
|
86
|
+
end
|
87
|
+
|
88
|
+
def rm(path)
|
89
|
+
return unless wet?
|
90
|
+
|
91
|
+
@logger.info('shell'){ ['rm -rf', path] }
|
92
|
+
FileUtils.rm_rf(path)
|
93
|
+
end
|
94
|
+
|
95
|
+
def mkpath(path)
|
96
|
+
return unless wet?
|
97
|
+
|
98
|
+
unless File.exist?(path)
|
99
|
+
@logger.info('shell'){ ['mkpath', path] }
|
100
|
+
|
101
|
+
FileUtils.mkpath(path)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def install(source_path, destination_path)
|
106
|
+
return unless wet?
|
107
|
+
|
108
|
+
@logger.info('shell'){ ['install', source_path, destination_path]}
|
109
|
+
FileUtils.install(source_path, destination_path)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Legacy FileUtils access, replaced with direct function calls.
|
113
|
+
def fs
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def update
|
118
|
+
@node.apply!(self)
|
119
|
+
end
|
120
|
+
|
121
|
+
def invoke_rule(rule, arguments, &block)
|
122
|
+
arguments = rule.normalize(arguments, self)
|
123
|
+
|
124
|
+
@logger.debug('invoke') {"-> #{rule}(#{arguments.inspect})"}
|
125
|
+
|
126
|
+
node = RuleNode.new(rule, arguments, &block)
|
127
|
+
task = invoke(node)
|
128
|
+
|
129
|
+
@logger.debug('invoke') {"<- #{rule}(...) -> #{rule.result(arguments)}"}
|
130
|
+
|
131
|
+
return rule.result(arguments)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
data/lib/build/version.rb
CHANGED
@@ -20,7 +20,6 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
-
require 'build/environment'
|
24
23
|
require 'build/rulebook'
|
25
24
|
require 'build/controller'
|
26
25
|
|
@@ -39,8 +38,8 @@ module Build::ControllerSpec
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
describe Build::Controller do
|
43
|
-
it "should fail
|
41
|
+
RSpec.describe Build::Controller do
|
42
|
+
it "build graph should fail" do
|
44
43
|
environment = Build::Environment.new do
|
45
44
|
define Build::Rule, "make.file" do
|
46
45
|
output :destination
|
@@ -61,7 +60,11 @@ module Build::ControllerSpec
|
|
61
60
|
controller.add_target(target, environment)
|
62
61
|
end
|
63
62
|
|
64
|
-
|
63
|
+
controller.logger.level = Logger::DEBUG
|
64
|
+
|
65
|
+
controller.update
|
66
|
+
|
67
|
+
expect(controller.failed?).to be_truthy
|
65
68
|
end
|
66
69
|
|
67
70
|
it "should execute the build graph" do
|
@@ -70,7 +73,7 @@ module Build::ControllerSpec
|
|
70
73
|
output :destination
|
71
74
|
|
72
75
|
apply do |parameters|
|
73
|
-
|
76
|
+
touch parameters[:destination]
|
74
77
|
end
|
75
78
|
end
|
76
79
|
|
@@ -79,7 +82,7 @@ module Build::ControllerSpec
|
|
79
82
|
output :destination
|
80
83
|
|
81
84
|
apply do |parameters|
|
82
|
-
|
85
|
+
cp parameters[:source], parameters[:destination]
|
83
86
|
end
|
84
87
|
end
|
85
88
|
end
|
data/spec/build/name_spec.rb
CHANGED
data/spec/build/rulebook_spec.rb
CHANGED
@@ -30,7 +30,7 @@ module Build::RulebookSpec
|
|
30
30
|
output :destination
|
31
31
|
|
32
32
|
apply do |parameters|
|
33
|
-
|
33
|
+
cp parameters[:source], parameters[:destination]
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -38,7 +38,7 @@ module Build::RulebookSpec
|
|
38
38
|
input :target
|
39
39
|
|
40
40
|
apply do |parameters|
|
41
|
-
|
41
|
+
rm parameters[:target]
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: build
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: build-graph
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.0.
|
19
|
+
version: 1.0.4
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.0.
|
26
|
+
version: 1.0.4
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: build-environment
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- ".simplecov"
|
121
121
|
- ".travis.yml"
|
122
122
|
- Gemfile
|
123
|
+
- Gemfile.local
|
123
124
|
- README.md
|
124
125
|
- Rakefile
|
125
126
|
- build.gemspec
|
@@ -129,7 +130,10 @@ files:
|
|
129
130
|
- lib/build/logger.rb
|
130
131
|
- lib/build/name.rb
|
131
132
|
- lib/build/rule.rb
|
133
|
+
- lib/build/rule_node.rb
|
132
134
|
- lib/build/rulebook.rb
|
135
|
+
- lib/build/target_node.rb
|
136
|
+
- lib/build/task.rb
|
133
137
|
- lib/build/version.rb
|
134
138
|
- spec/build/controller_spec.rb
|
135
139
|
- spec/build/name_spec.rb
|
@@ -155,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
159
|
version: '0'
|
156
160
|
requirements: []
|
157
161
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.
|
162
|
+
rubygems_version: 2.5.1
|
159
163
|
signing_key:
|
160
164
|
specification_version: 4
|
161
165
|
summary: Build is a framework for working with task based build systems.
|