rubuild-core 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ module Rubuild
2
+
3
+ module Build
4
+
5
+ ## Rubuild::Build::Factory
6
+ # Rubuild::Build::Factory is the interface object for creating
7
+ # Rubuild::Build::Dep and Rubuild::Build::Context objects.
8
+ class Factory
9
+
10
+ # Used to derive Rubuild::Build::Factory
11
+ class ProtocolClass
12
+ # Create a Rubuild::BuildContext object.
13
+ # [_return_] A new Rubuild::BuildContext for executing Rubuild::Dep
14
+ # dependencies.
15
+ def create_context
16
+ end # Rubuild::Build::Factory#create_build_context
17
+
18
+ # Create a Rubuild::Dep object.
19
+ # [+command+] +command+ argument to Rubuild::Dep#new.
20
+ # [+disp+] +disp+ argument to Rubuild::Dep#new.
21
+ # [+args+] Additional arguments to be passed to +command+.
22
+ # [_return_] A new Rubuild::Dep for executing +command+.
23
+ def create_dep(command, disp, *args)
24
+ end # Rubuild::Build::Factory#create_dep
25
+ end # Rubuild::Build::Factory
26
+
27
+ Protocol = Safer::Protocol.create_from_class(ProtocolClass)
28
+ end # Rubuild::Build::Factory
29
+ end # Rubuild::Build
30
+ end # Rubuild
@@ -0,0 +1,3 @@
1
+ require 'rubuild/build/simple/dep'
2
+ require 'rubuild/build/simple/context'
3
+ require 'rubuild/build/simple/factory'
@@ -0,0 +1,90 @@
1
+ module Rubuild
2
+ module Build
3
+ module Simple
4
+ class Context
5
+
6
+ ## Rubuild::Build::Context
7
+ # Hash of dependencies that are loadable in this build context.
8
+ Safer::IVar.instance_variable(self, :loaded)
9
+ # Array of dependencies that are currently waiting execution in this
10
+ # build context.
11
+ Safer::IVar.instance_variable(self, :runable)
12
+ Safer::IVar.instance_variable(self, :debug_level, :debug_file)
13
+ Safer::IVar.export_accessor(self, :debug_level, :debug_file)
14
+
15
+ # Initialize +self+.
16
+ def initialize
17
+ self.rubuild_build_simple_context__loaded = Hash.new
18
+ self.rubuild_build_simple_context__runable = Array.new
19
+ self.rubuild_build_simple_context__debug_level = 0
20
+ self.rubuild_build_simple_context__debug_file = nil
21
+ end # Rubuild::Build::Context#initialize
22
+
23
+ # Mark that a Rubuild::Dep object has been loaded into +self+.
24
+ # Used internally.
25
+ # [+dep+] Rubuild::Dep object loaded into +self+ for future execution.
26
+ # [_return_] Return value is:
27
+ # [+true+] when this is the first time the dependency is being
28
+ # loaded into +self+,
29
+ # [+false+] otherwise.
30
+ def dep_loaded(dep)
31
+ rval = ! self.rubuild_build_simple_context__loaded.has_key?(dep)
32
+ if rval
33
+ self.rubuild_build_simple_context__loaded[dep] = true
34
+ end
35
+ rval
36
+ end # Rubuild::Build::Context#dep_loaded
37
+
38
+ # Mark that a Rubuild::Dep object is now runable within the +self+
39
+ # Rubuild::Build::Context.
40
+ # This indicates that all of the dependency's parents have been satisfied.
41
+ # Used internally.
42
+ # [+dep+] Rubuild::Dep that has become runable in +self+.
43
+ def dep_runable(dep)
44
+ if ! self.rubuild_build_simple_context__loaded.has_key?(dep)
45
+ raise Build::Context::Error::Runable.new(self, dep)
46
+ end
47
+ self.rubuild_build_simple_context__loaded.delete(dep)
48
+ self.rubuild_build_simple_context__runable << dep
49
+ end # Rubuild::Build::Context#dep_runable
50
+
51
+ # Create an exception to capture the event that not all loaded dependencies
52
+ # were built.
53
+ # Used internally.
54
+ # [_return_] Rubuild::Build::Context::Error::Run exception.
55
+ def run_error
56
+ Build::Context::Error::Run.new(self)
57
+ end # Rubuild::Build::Context#run_error
58
+
59
+ # Execute a single dependency object. Not a supported interface in all
60
+ # derived classes.
61
+ def step
62
+ if self.rubuild_build_simple_context__runable.size > 0
63
+ dep = self.rubuild_build_simple_context__runable.shift
64
+ if ! dep.built
65
+ dep.runctx_build(self)
66
+ end
67
+ end
68
+ end # Rubuild::Build::Context#step
69
+
70
+ # Execute the dependencies loaded into this build context, in dependency
71
+ # order.
72
+ def run
73
+ while self.rubuild_build_simple_context__runable.size > 0
74
+ self.step
75
+ end
76
+ if self.rubuild_build_simple_context__loaded.keys.size > 0
77
+ raise self.run_error
78
+ end
79
+ end # Rubuild::Build::Context#run
80
+
81
+ def debug(level)
82
+ if (self.rubuild_build_simple_context__debug_file &&
83
+ level < self.rubuild_build_simple_context__debug_level)
84
+ yield self.rubuild_build_simple_context__debug_file
85
+ end
86
+ end
87
+ end # Rubuild::Build::Simple::Context
88
+ end # Rubuild::Build::Simple
89
+ end # Rubuild::Build
90
+ end # Rubuild
@@ -0,0 +1,367 @@
1
+ module Rubuild
2
+ module Build
3
+ module Simple
4
+ class Dep
5
+ # count of parent dependencies preventing +self+ from executing.
6
+ Safer::IVar.instance_variable(self, :build_wait)
7
+ # Hash of parent dependencies preventing +self+ from executing.
8
+ Safer::IVar.instance_variable(self, :parents)
9
+ # Array of child dependencies waiting for +self+ to execute.
10
+ Safer::IVar.instance_variable(self, :children)
11
+ # Boolean indicates whether all parent dependencies have been satisfied,
12
+ # and +self+'s action can be executed.
13
+ Safer::IVar.instance_variable(self, :runable)
14
+ Safer::IVar.instance_variable(self, :built)
15
+ Safer::IVar.export_reader(self, :built)
16
+ # Hash of Rubuild::Build::Context's into which +self+ has been loaded.
17
+ Safer::IVar.instance_variable(self, :loaded)
18
+ # Boolean used to check for circular dependencies when adding parent
19
+ # Rubuild::Build::Dep objects.
20
+ Safer::IVar.instance_variable(self, :circlecheck)
21
+
22
+ # Object that responds to :call method, or nil. Essentially +self+'s
23
+ # dependency action.
24
+ Safer::IVar.instance_variable(self, :command)
25
+ Safer::IVar.instance_variable(self, :args)
26
+ Safer::IVar.export_reader(self, :args)
27
+ # Pretty name of dependency object, for human consumption.
28
+ Safer::IVar.instance_variable(self, :name)
29
+
30
+ Safer::IVar.instance_variable(self, :err)
31
+ Safer::IVar.export_reader(self, :err)
32
+
33
+ def initialize(command, name)
34
+ self.rubuild_build_simple_dep__build_wait = 0
35
+ self.rubuild_build_simple_dep__parents = Hash.new
36
+ self.rubuild_build_simple_dep__children = Array.new
37
+ self.rubuild_build_simple_dep__runable = false
38
+ self.rubuild_build_simple_dep__built = false
39
+ self.rubuild_build_simple_dep__loaded = Hash.new
40
+ self.rubuild_build_simple_dep__circlecheck = false
41
+
42
+ self.rubuild_build_simple_dep__command = command
43
+ self.rubuild_build_simple_dep__name = name
44
+ self.rubuild_build_simple_dep__err = nil
45
+ self.args = []
46
+ end # Rubuild::Build::Dep#initialize
47
+
48
+ # Returns a human-readable string describing the depandancy object,
49
+ # as set during initialization.
50
+ # [_return_] Human-readable string description of +self+ dependency.
51
+ def name
52
+ if self.rubuild_build_simple_dep__name
53
+ self.rubuild_build_simple_dep__name
54
+ else
55
+ super
56
+ end
57
+ end # Rubuild::Build::Dep#name
58
+
59
+ # Sets the list of optional arguments with which the dependency action will
60
+ # be invoked.
61
+ # [+nargs+] New arguments to dependency action.
62
+ # [_return_] +self+.
63
+ def args=(nargs)
64
+ if self.rubuild_build_simple_dep__runable or self.rubuild_build_simple_dep__built
65
+ raise Rubuild::Build::Dep::Error::Parameter::Args.new(self)
66
+ end
67
+ self.rubuild_build_simple_dep__args = nargs
68
+ self
69
+ end # Rubuild::Build::Dep#args=
70
+
71
+ # Resets the dependency action to be invoked.
72
+ # [+command+] New command to be invoked.
73
+ # [_return_] +self+.
74
+ def set_command(command)
75
+ if self.rubuild_build_simple_dep__runable or self.rubuild_build_simple_dep__built
76
+ raise Rubuild::Build::Dep::Error::Parameter::Command.new(self)
77
+ end
78
+ self.rubuild_build_simple_dep__command = command
79
+ self
80
+ end # Rubuild::Build::Dep#set_command
81
+
82
+ # Inserts dependency between +self+ and all child dependencies of +self+.
83
+ # [+dep+] Dependency against which all child dependencies of +self+ should
84
+ # wait.
85
+ def surrogate(dep)
86
+ dep.add_parent(self)
87
+ self.rubuild_build_simple_dep__children.each do |child|
88
+ if child != dep
89
+ child.add_parent(dep)
90
+ end
91
+ end
92
+
93
+ self.rubuild_build_simple_dep__loaded.each_key do |buildctx|
94
+ dep.load(buildctx)
95
+ end
96
+ end # Rubuild::Build::Dep#surrogate
97
+
98
+ # Makes +dep+ a parent dependency of +self+ - in other words, +dep+ must
99
+ # be run before +self+ can be run.
100
+ # [+dep+] Dependency that must be executed before +self+ can execute.
101
+ def add_parent(dep)
102
+ if self.rubuild_build_simple_dep__runable
103
+ raise Rubuild::Build::Dep::Error::Runable.new(self, dep)
104
+ end
105
+ # Are we already waiting for this dependency?
106
+ if ! self.rubuild_build_simple_dep__parents.has_key?(dep)
107
+ # No, so we probably want to add him in...
108
+ # check that we're not creating a circular dependency.
109
+ self.circle_check(Array.new, [dep])
110
+
111
+ # Indicate that we want to block on parent...
112
+ self.rubuild_build_simple_dep__build_wait += 1
113
+ self.rubuild_build_simple_dep__parents[dep] = true
114
+ # ...and tell parent to prod us after he runs.
115
+ dep.child_added(self)
116
+ end
117
+ # The new parent will need to be loaded into any build context into
118
+ # which self is loaded.
119
+ self.rubuild_build_simple_dep__loaded.each_key do |bctx|
120
+ dep.load(bctx)
121
+ end
122
+ end # Rubuild::Build::Dep#add_parent
123
+
124
+ # Record that a child dependency has been added to +self+.
125
+ # Used internally.
126
+ # [+dep+] New child dependency.
127
+ def child_added(dep)
128
+ if self.built
129
+ dep.parent_built(self)
130
+ else
131
+ self.rubuild_build_simple_dep__children << dep
132
+ end
133
+ end # Rubuild::Build::Dep#child_added
134
+
135
+ # Mark that all parent dependencies have been satisfied for +self+.
136
+ # Inform all build contexts that _might_ execute this dependency that this
137
+ # dependency is now runable.
138
+ # Used internally.
139
+ def make_runable
140
+ self.rubuild_build_simple_dep__loaded.each_key do |buildctx|
141
+ buildctx.dep_runable(self)
142
+ end
143
+ self.rubuild_build_simple_dep__runable = true
144
+ self.rubuild_build_simple_dep__parents = nil
145
+ end # Rubuild::Build::Dep#make_runable
146
+
147
+ # Check for circular dependencies.
148
+ # Used internally.
149
+ # [+loading+] Rubuild::Build::Dep chain in progress. Used as a backtrace, in
150
+ # case a circular dependency is detected.
151
+ # [+check+] Array of Rubuild::Build::Dep objects to place in 'parent' list, when
152
+ # searching for circular dependencies.
153
+ def circle_check(loading, check)
154
+ if self.rubuild_build_simple_dep__circlecheck
155
+ raise Rubuild::Build::Dep::Error::Load.new(self, loading)
156
+ end
157
+ if self.built
158
+ return
159
+ end
160
+ self.rubuild_build_simple_dep__circlecheck = true
161
+ parentcheck = check.dup
162
+ if self.rubuild_build_simple_dep__parents
163
+ self.rubuild_build_simple_dep__parents.each_pair do |key, value|
164
+ if value
165
+ parentcheck << key
166
+ end
167
+ end
168
+ end
169
+ pcheck_arr = Array.new
170
+ loading.push(self)
171
+ parentcheck.each do |parent|
172
+ parent.circle_check(loading, pcheck_arr)
173
+ end
174
+ loading.pop
175
+ self.rubuild_build_simple_dep__circlecheck = false
176
+ end # Rubuild::Build::Dep#circle_check
177
+
178
+ # Record that a build-context is waiting to build this dependency.
179
+ # Search for circular dependencies.
180
+ # Used internally.
181
+ # [+loading+] Rubuild::Build::Dep dependency chain in progress, that lead to
182
+ # +self+ being loaded into a Rubuild::Build::Context.
183
+ # [+buildctx+] Rubuild::Build::Context into which +self+ is being loaded.
184
+ def load_self(loading, buildctx)
185
+ if self.built
186
+ return
187
+ end
188
+ if buildctx.dep_loaded(self) == true
189
+ self.rubuild_build_simple_dep__loaded[buildctx] = loading.dup
190
+ if self.rubuild_build_simple_dep__build_wait > 0
191
+ parentcheck = Array.new
192
+ self.rubuild_build_simple_dep__parents.each_pair do |key, value|
193
+ if value
194
+ parentcheck << key
195
+ end
196
+ end
197
+ loading.push(self)
198
+ parentcheck.each do |parent|
199
+ parent.load_self(loading, buildctx)
200
+ end
201
+ loading.pop
202
+ elsif self.rubuild_build_simple_dep__runable
203
+ buildctx.dep_runable(self)
204
+ else
205
+ self.make_runable
206
+ end
207
+ end
208
+ end # Rubuild::Build::Dep#load_self
209
+
210
+ # Loads +self+ and all parent dependancies into the execution context
211
+ # +buildctx+.
212
+ # [+buildctx+] Rubuild::Build::Context into which +self+ is being loaded.
213
+ def load(buildctx)
214
+ self.load_self(Array.new, buildctx)
215
+ end
216
+
217
+ # Return array of all Rubuild::Build::Context objects that will build this
218
+ # dependency.
219
+ def builders
220
+ self.rubuild_build_simple_dep__loaded.keys
221
+ end # Rubuild::Build::Dep#builders
222
+
223
+ # Return the child-dependencies of +self+ that placed +self+ into the
224
+ # Rubuild::Build::Context +builder+.
225
+ # [+builder+] A Rubuild::Build::Context into which +self+ was loaded.
226
+ # [_return_] The dependency hierarchy in +builder+ that resulted in
227
+ # +self+ being loaded, or nil if +self+ was not loaded into
228
+ # +builder+.
229
+ def loaders(builder)
230
+ self.rubuild_build_simple_dep__loaded[builder]
231
+ end # Rubuild::Build::Dep#loaders
232
+
233
+ # Inform all children that a parent dependency (or +self+) failed to
234
+ # execute a command due to +err+.
235
+ # Used internally.
236
+ # [+err+] Exception that prevents +self+ from completing.
237
+ # [_return_] Rubuild::Build::Dep::Error::Action for +err+.
238
+ def action_error_real(err)
239
+ self.rubuild_build_simple_dep__err = err
240
+ self.rubuild_build_simple_dep__children.each do |child|
241
+ child.parent_action_error(self, err)
242
+ end
243
+ self.rubuild_build_simple_dep__err
244
+ end # Rubuild::Build::Dep#action_error_real
245
+
246
+ # Error +err+ occurred while executing +self+'s dependency command.
247
+ # Inform all child dependencies of the event.
248
+ # Used internally.
249
+ # [+err+] Exception that prevented +self+'s dependency command from
250
+ # completing.
251
+ # [+runctx+] Rubuild::Build::Context used to execute +self+.
252
+ # [_return_] Rubuild::Build::Dep::Error::Action for +err+.
253
+ def action_error(err, runctx)
254
+ self.action_error_real(
255
+ Rubuild::Build::Dep::Error::Action.new(self, err, runctx)
256
+ )
257
+ end # Rubuild::Build::Dep#action_error
258
+
259
+ # Child is being informed by +parent+ that error +err+ occurred processing
260
+ # a dependency action.
261
+ # Used internally.
262
+ # [+parent+] Parent dependency that will not run, thus preventing +self+
263
+ # from running.
264
+ # [+err+] Error that prevents +parent+ from running.
265
+ def parent_action_error(parent, err)
266
+ self.action_error_real(err)
267
+ end # Rubuild::Build::Dep#parent_action_error
268
+
269
+ # Used by a Rubuild::Build::Context to execute the dependency command for
270
+ # +self+.
271
+ # Used internally.
272
+ # [+runctx+] Rubuild::Build::Context used to execute +self+'s dependency
273
+ # command.
274
+ def runctx_build(runctx)
275
+ if self.rubuild_build_simple_dep__built == true
276
+ raise Rubuild::Build::Dep::Error::Build.new(self, runctx)
277
+ end
278
+
279
+ # propogate errors from parents. the error may have been
280
+ # set during the 'load' operation...
281
+ if self.err
282
+ raise self.err
283
+ end
284
+
285
+ # call the command, then lose the reference, so it can be
286
+ # GC'ed.
287
+ begin
288
+ runctx.debug(1) do |outf|
289
+ outf.puts("building #{self.name}")
290
+ end
291
+ if self.rubuild_build_simple_dep__command
292
+ self.rubuild_build_simple_dep__command.call(
293
+ self, *self.rubuild_build_simple_dep__args
294
+ )
295
+ end
296
+ rescue Exception, NoMethodError => e
297
+ raise self.action_error(e, runctx)
298
+ end
299
+
300
+ self.rubuild_build_simple_dep__command = nil
301
+ self.rubuild_build_simple_dep__args = nil
302
+ self.rubuild_build_simple_dep__built = true
303
+ self.rubuild_build_simple_dep__loaded = nil
304
+ self.rubuild_build_simple_dep__children.each do |child|
305
+ child.parent_built(self)
306
+ runctx.debug(1) do |outf|
307
+ puts(" #{child.name} is waiting for #{child.rubuild_build_simple_dep__build_wait}:")
308
+ runctx.debug(2) do |outf|
309
+ if child.rubuild_build_simple_dep__parents
310
+ child.rubuild_build_simple_dep__parents.each_pair do |child_parent, count|
311
+ puts(" #{child_parent.name}(#{count})")
312
+ end
313
+ end
314
+ end
315
+ end
316
+ end
317
+ self.rubuild_build_simple_dep__children = nil
318
+ end # Rubuild::Build::Dep#runctx_build
319
+
320
+ # Record that a parent dependency has been built.
321
+ # Will result in this dependency being made runable, when all parent
322
+ # dependencies are satisfied.
323
+ # Used internally.
324
+ # [+dep+] Parent dependency that was built.
325
+ def parent_built(dep)
326
+ if ! self.rubuild_build_simple_dep__parents[dep]
327
+ raise(Rubuild::Build::Dep::Error::DepInconsistent.new(self, dep))
328
+ end
329
+ self.rubuild_build_simple_dep__build_wait -= 1
330
+ self.rubuild_build_simple_dep__parents[dep] = false
331
+ if (self.rubuild_build_simple_dep__build_wait == 0)
332
+ self.make_runable
333
+ end
334
+ end # Rubuild::Build::Dep#parent_built
335
+
336
+ def parent_tree
337
+ rval = Hash.new
338
+ if self.rubuild_build_simple_dep__parents
339
+ self.rubuild_build_simple_dep__parents.each_pair do |parent, is_waiting|
340
+ if is_waiting
341
+ rval["#{parent.name}"] = parent.parent_tree
342
+ end
343
+ end
344
+ end
345
+ rval
346
+ end
347
+
348
+ def child_tree
349
+ rval = Hash.new
350
+ if self.rubuild_build_simple_dep__children
351
+ self.rubuild_build_simple_dep__children.each do |child|
352
+ rval[child.name] = child.child_tree
353
+ end
354
+ end
355
+ rval
356
+ end
357
+
358
+ def self.print_tree(file, tree, indent = 0)
359
+ tree.keys.sort.each do |node|
360
+ file.puts(' '*indent + node)
361
+ self.print_tree(file, tree[node], indent+1)
362
+ end
363
+ end
364
+ end # Rubuild::Build::Simple::Dep
365
+ end # Rubuild::Build::Simple
366
+ end # Rubuild::Build
367
+ end # Rubuild