rubuild-core 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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