comp_tree 0.5.2 → 0.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.
- data/CHANGES +24 -0
- data/README +19 -52
- data/Rakefile +1 -138
- data/comp_tree.gemspec +33 -30
- data/install.rb +3 -3
- data/lib/comp_tree/algorithm.rb +117 -156
- data/lib/comp_tree/driver.rb +39 -154
- data/lib/comp_tree/error.rb +18 -23
- data/lib/comp_tree/node.rb +46 -50
- data/lib/comp_tree.rb +56 -0
- data/rakelib/jumpstart/ruby.rb +51 -0
- data/{contrib/quix/lib/quix → rakelib/jumpstart}/simple_installer.rb +11 -13
- data/test/common.rb +29 -0
- data/test/test_basic.rb +189 -0
- data/test/test_circular.rb +34 -31
- data/test/test_drain.rb +38 -0
- data/test/test_exception.rb +37 -86
- data/test/test_flood.rb +14 -0
- data/test/test_grind.rb +77 -0
- data/test/test_sequential.rb +21 -0
- metadata +45 -58
- data/contrib/quix/Rakefile +0 -16
- data/contrib/quix/install.rb +0 -3
- data/contrib/quix/lib/quix/builtin/dir/casefold_brackets.rb +0 -7
- data/contrib/quix/lib/quix/builtin/kernel/tap.rb +0 -9
- data/contrib/quix/lib/quix/builtin/module/include.rb +0 -21
- data/contrib/quix/lib/quix/builtin/module/private.rb +0 -41
- data/contrib/quix/lib/quix/config.rb +0 -37
- data/contrib/quix/lib/quix/cygwin.rb +0 -60
- data/contrib/quix/lib/quix/diagnostic.rb +0 -44
- data/contrib/quix/lib/quix/enumerable.rb +0 -33
- data/contrib/quix/lib/quix/fileutils.rb +0 -37
- data/contrib/quix/lib/quix/hash_struct.rb +0 -27
- data/contrib/quix/lib/quix/kernel.rb +0 -61
- data/contrib/quix/lib/quix/lazy_struct.rb +0 -55
- data/contrib/quix/lib/quix/string.rb +0 -38
- data/contrib/quix/lib/quix/subpackager.rb +0 -52
- data/contrib/quix/lib/quix/thread_local.rb +0 -32
- data/contrib/quix/lib/quix/vars.rb +0 -138
- data/contrib/quix/lib/quix.rb +0 -32
- data/contrib/quix/test/all.rb +0 -12
- data/contrib/quix/test/test_deps.rb +0 -25
- data/contrib/quix/test/test_include.rb +0 -47
- data/contrib/quix/test/test_private.rb +0 -86
- data/contrib/quix/test/test_root.rb +0 -19
- data/contrib/quix/test/test_struct.rb +0 -48
- data/contrib/quix/test/test_vars.rb +0 -187
- data/lib/comp_tree/bucket_ipc.rb +0 -151
- data/lib/comp_tree/diagnostic.rb +0 -44
- data/lib/comp_tree/misc.rb +0 -61
- data/lib/comp_tree/retriable_fork.rb +0 -42
- data/lib/comp_tree/tap.rb +0 -9
- data/lib/comp_tree/task_node.rb +0 -22
- data/test/all.rb +0 -12
- data/test/test_bucketipc.rb +0 -72
- data/test/test_comp_tree.rb +0 -364
data/lib/comp_tree/driver.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
|
2
|
-
require 'comp_tree/bucket_ipc'
|
3
|
-
require 'comp_tree/diagnostic'
|
4
|
-
require 'comp_tree/misc'
|
5
2
|
require 'comp_tree/algorithm'
|
6
3
|
require 'comp_tree/node'
|
7
|
-
require 'comp_tree/task_node'
|
8
4
|
require 'comp_tree/error'
|
9
5
|
|
10
6
|
require 'thread'
|
@@ -15,53 +11,25 @@ module CompTree
|
|
15
11
|
# responsible for defining nodes and running computations.
|
16
12
|
#
|
17
13
|
class Driver
|
18
|
-
|
19
|
-
:threads => 1,
|
20
|
-
:fork => false,
|
21
|
-
:timeout => 5.0,
|
22
|
-
:wait_interval => 0.02,
|
23
|
-
}
|
14
|
+
include Algorithm
|
24
15
|
|
25
|
-
include Diagnostic
|
26
|
-
include Misc
|
27
|
-
|
28
16
|
#
|
29
|
-
#
|
17
|
+
# Build and run a new computation tree.
|
30
18
|
#
|
31
19
|
# Options hash:
|
32
20
|
#
|
33
21
|
# <tt>:node_class</tt> -- (Class) CompTree::Node subclass from
|
34
22
|
# which nodes are created.
|
35
23
|
#
|
36
|
-
# <tt>:discard_result</tt> -- (boolean) If you are <em>not</em>
|
37
|
-
# interested in the final answer, but only in the actions which
|
38
|
-
# complete the computation, then set this to +true+. This is
|
39
|
-
# equivalent to saying <tt>:node_class => CompTree::TaskNode</tt>.
|
40
|
-
# (If you are forking processes, it is good to know that IPC is
|
41
|
-
# not needed to communicate the result.)
|
42
|
-
#
|
43
24
|
def initialize(opts = nil)
|
44
|
-
|
45
|
-
raise(
|
46
|
-
Error::ArgumentError,
|
47
|
-
"#{self.class.name}.new: :discard_result and :node_class " +
|
48
|
-
"are mutually exclusive")
|
49
|
-
end
|
50
|
-
|
51
|
-
@node_class =
|
25
|
+
@node_class = (
|
52
26
|
if opts and opts[:node_class]
|
53
27
|
opts[:node_class]
|
54
|
-
elsif opts and opts[:discard_result]
|
55
|
-
TaskNode
|
56
28
|
else
|
57
29
|
Node
|
58
30
|
end
|
59
|
-
|
31
|
+
)
|
60
32
|
@nodes = Hash.new
|
61
|
-
|
62
|
-
if block_given?
|
63
|
-
yield self
|
64
|
-
end
|
65
33
|
end
|
66
34
|
|
67
35
|
#
|
@@ -72,55 +40,43 @@ module CompTree
|
|
72
40
|
#
|
73
41
|
# Define a computation node.
|
74
42
|
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# defined which depends on the nodes +height+, +width+, +offset+.
|
43
|
+
# The first argument is the name of the node to define.
|
44
|
+
# Subsequent arguments are the names of this node's children.
|
78
45
|
#
|
79
|
-
# The
|
80
|
-
#
|
81
|
-
# width*height - offset
|
82
|
-
# }
|
46
|
+
# The values of the child nodes are passed to the block. The
|
47
|
+
# block returns the result of this node.
|
83
48
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# width*height - offset
|
87
|
-
# }
|
88
|
-
# (Note the '%' before the brace.)
|
49
|
+
# In this example, a computation node named +area+ is defined
|
50
|
+
# which depends on the nodes +width+ and +height+.
|
89
51
|
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
# }
|
52
|
+
# driver.define(:area, :width, :height) { |width, height|
|
53
|
+
# width*height
|
54
|
+
# }
|
94
55
|
#
|
95
56
|
def define(*args, &block)
|
96
57
|
parent_name = args.first
|
97
58
|
children_names = args[1..-1]
|
98
59
|
|
99
60
|
unless parent_name
|
100
|
-
raise
|
61
|
+
raise ArgumentError, "No name given for node"
|
101
62
|
end
|
102
63
|
|
103
64
|
#
|
104
65
|
# retrieve or create parent and children
|
105
66
|
#
|
106
|
-
parent =
|
107
|
-
|
108
|
-
|
109
|
-
else
|
110
|
-
@nodes[parent_name] = @node_class.new(parent_name)
|
111
|
-
end
|
67
|
+
parent = @nodes[parent_name] || (
|
68
|
+
@nodes[parent_name] = @node_class.new(parent_name)
|
69
|
+
)
|
112
70
|
|
113
71
|
if parent.function
|
114
|
-
raise
|
72
|
+
raise RedefinitionError, "Node `#{parent.name.inspect}' redefined."
|
115
73
|
end
|
116
74
|
parent.function = block
|
117
75
|
|
118
76
|
children = children_names.map { |child_name|
|
119
|
-
|
120
|
-
t
|
121
|
-
else
|
77
|
+
@nodes[child_name] || (
|
122
78
|
@nodes[child_name] = @node_class.new(child_name)
|
123
|
-
|
79
|
+
)
|
124
80
|
}
|
125
81
|
|
126
82
|
#
|
@@ -132,72 +88,37 @@ module CompTree
|
|
132
88
|
}
|
133
89
|
end
|
134
90
|
|
135
|
-
#
|
136
|
-
# parsing/evaling helper
|
137
|
-
#
|
138
|
-
def evaling_define(*args) #:nodoc:
|
139
|
-
function_name = args[0]
|
140
|
-
function_arg_names = args[1..-2]
|
141
|
-
function_string = args.last.to_str
|
142
|
-
|
143
|
-
comma_separated = function_arg_names.map { |name|
|
144
|
-
name.to_s
|
145
|
-
}.join(",")
|
146
|
-
|
147
|
-
eval_me = %{
|
148
|
-
lambda { |#{comma_separated}|
|
149
|
-
#{function_string}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
function = eval(eval_me, TOPLEVEL_BINDING)
|
154
|
-
|
155
|
-
define(function_name, *function_arg_names, &function)
|
156
|
-
end
|
157
|
-
|
158
|
-
def method_missing(symbol, *args, &block) #:nodoc:
|
159
|
-
if match = symbol.to_s.match(%r!\Adefine_(\w+)\Z!)
|
160
|
-
method_name = match.captures.first.to_sym
|
161
|
-
if block
|
162
|
-
define(method_name, *args, &block)
|
163
|
-
else
|
164
|
-
evaling_define(method_name, *args)
|
165
|
-
end
|
166
|
-
else
|
167
|
-
super(symbol, *args, &block)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
91
|
#
|
172
92
|
# Mark this node and all its children as uncomputed.
|
173
93
|
#
|
174
94
|
# Arguments:
|
175
95
|
#
|
176
|
-
# +name+ --
|
96
|
+
# +name+ -- unique node identifier (usually a symbol).
|
177
97
|
#
|
178
98
|
def reset(name)
|
179
99
|
@nodes[name].reset
|
180
100
|
end
|
181
101
|
|
182
102
|
#
|
183
|
-
# Check for a cyclic graph below the given node.
|
184
|
-
#
|
103
|
+
# Check for a cyclic graph below the given node. If found,
|
104
|
+
# returns the names of the nodes (in order) which form a loop.
|
105
|
+
# Otherwise returns nil.
|
185
106
|
#
|
186
107
|
# Arguments:
|
187
108
|
#
|
188
|
-
# +name+ --
|
109
|
+
# +name+ -- unique node identifier (usually a symbol).
|
189
110
|
#
|
190
111
|
def check_circular(name)
|
191
|
-
helper =
|
112
|
+
helper = Proc.new { |root, chain|
|
192
113
|
if chain.include? root
|
193
|
-
|
194
|
-
"Circular dependency detected: #{root} => #{chain.last} => #{root}"
|
114
|
+
return chain + [root]
|
195
115
|
end
|
196
116
|
@nodes[root].children.each { |child|
|
197
117
|
helper.call(child.name, chain + [root])
|
198
118
|
}
|
199
119
|
}
|
200
120
|
helper.call(name, [])
|
121
|
+
nil
|
201
122
|
end
|
202
123
|
|
203
124
|
#
|
@@ -205,62 +126,26 @@ module CompTree
|
|
205
126
|
#
|
206
127
|
# Arguments:
|
207
128
|
#
|
208
|
-
# +name+ --
|
209
|
-
#
|
210
|
-
# Options hash:
|
211
|
-
#
|
212
|
-
# <tt>:threads</tt> -- (Integer) Number of parallel threads.
|
129
|
+
# +name+ -- unique node identifier (usually a symbol).
|
213
130
|
#
|
214
|
-
#
|
215
|
-
# node into its own process.
|
131
|
+
# +threads+ -- (Integer) number of threads.
|
216
132
|
#
|
217
|
-
#
|
133
|
+
# compute(:volume, :threads => 4) syntax is also accepted.
|
218
134
|
#
|
219
|
-
def compute(name, opts
|
220
|
-
|
221
|
-
# Undocumented options:
|
222
|
-
#
|
223
|
-
# <tt>:wait_interval</tt> -- (seconds) (Obscure) How long to
|
224
|
-
# wait after an IPC failure.
|
225
|
-
#
|
226
|
-
# <tt>:timeout</tt> -- (seconds) (Obscure) Give up after this
|
227
|
-
# period of persistent IPC failures.
|
228
|
-
#
|
229
|
-
|
230
|
-
abort_on_exception {
|
231
|
-
compute_private(name, opts || Hash.new)
|
232
|
-
}
|
233
|
-
end
|
234
|
-
|
235
|
-
private
|
236
|
-
|
237
|
-
def compute_private(name, opts_in)
|
238
|
-
opts = DEFAULTS.merge(opts_in)
|
135
|
+
def compute(name, opts)
|
136
|
+
threads = opts.is_a?(Hash) ? opts[:threads] : opts
|
239
137
|
root = @nodes[name]
|
240
138
|
|
241
|
-
if
|
242
|
-
raise
|
139
|
+
if threads < 1
|
140
|
+
raise ArgumentError, "threads is #{threads}"
|
243
141
|
end
|
244
142
|
|
245
|
-
if
|
143
|
+
if root.computed
|
144
|
+
root.result
|
145
|
+
elsif threads == 1
|
246
146
|
root.result = root.compute_now
|
247
|
-
elsif opts[:fork] and not @node_class.discard_result?
|
248
|
-
#
|
249
|
-
# Use buckets to send results across forks.
|
250
|
-
#
|
251
|
-
result = nil
|
252
|
-
BucketIPC::Driver.new(opts[:threads], opts) { |buckets|
|
253
|
-
result =
|
254
|
-
Algorithm.compute_multithreaded(
|
255
|
-
root, opts[:threads], opts[:fork], buckets)
|
256
|
-
}
|
257
|
-
result
|
258
147
|
else
|
259
|
-
|
260
|
-
# Multithreaded computation without fork.
|
261
|
-
#
|
262
|
-
Algorithm.compute_multithreaded(
|
263
|
-
root, opts[:threads], opts[:fork], nil)
|
148
|
+
compute_multithreaded(root, threads)
|
264
149
|
end
|
265
150
|
end
|
266
151
|
end
|
data/lib/comp_tree/error.rb
CHANGED
@@ -1,27 +1,22 @@
|
|
1
1
|
|
2
2
|
module CompTree
|
3
|
-
|
4
|
-
|
5
|
-
class Base < StandardError ; end
|
3
|
+
# Base class for CompTree errors.
|
4
|
+
class Error < StandardError ; end
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# No function was defined for this node.
|
25
|
-
class NoFunctionError < Base ; end
|
26
|
-
end
|
6
|
+
# Internal error inside CompTree. Please send a bug report.
|
7
|
+
class AssertionFailedError < Error ; end
|
8
|
+
|
9
|
+
# Bad arguments were passed to a method.
|
10
|
+
class ArgumentError < Error ; end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Attempt to redefine a Node.
|
14
|
+
#
|
15
|
+
# If you wish to only replace the function, set
|
16
|
+
# driver.nodes[name].function = some_new_lambda
|
17
|
+
#
|
18
|
+
class RedefinitionError < Error ; end
|
19
|
+
|
20
|
+
# No function was defined for this node.
|
21
|
+
class NoFunctionError < Error ; end
|
27
22
|
end
|
data/lib/comp_tree/node.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
|
2
|
-
require 'comp_tree/diagnostic'
|
3
2
|
require 'thread'
|
4
3
|
|
5
4
|
module CompTree
|
@@ -7,24 +6,26 @@ module CompTree
|
|
7
6
|
# Base class for nodes in the computation tree.
|
8
7
|
#
|
9
8
|
class Node
|
10
|
-
include Diagnostic
|
11
|
-
|
12
9
|
attr_reader :name #:nodoc:
|
13
10
|
|
14
11
|
attr_accessor :parents #:nodoc:
|
15
12
|
attr_accessor :children #:nodoc:
|
16
13
|
attr_accessor :function #:nodoc:
|
17
14
|
attr_accessor :result #:nodoc:
|
15
|
+
attr_accessor :computed #:nodoc:
|
18
16
|
attr_accessor :shared_lock #:nodoc:
|
19
17
|
|
18
|
+
attr_writer :children_results #:nodoc:
|
19
|
+
|
20
20
|
#
|
21
21
|
# Create a node
|
22
22
|
#
|
23
23
|
def initialize(name) #:nodoc:
|
24
24
|
@name = name
|
25
|
-
@mutex = Mutex.new
|
26
|
-
@children = []
|
27
25
|
@parents = []
|
26
|
+
@children = []
|
27
|
+
@function = nil
|
28
|
+
@mutex = Mutex.new
|
28
29
|
reset_self
|
29
30
|
end
|
30
31
|
|
@@ -32,9 +33,10 @@ module CompTree
|
|
32
33
|
# Reset the computation for this node.
|
33
34
|
#
|
34
35
|
def reset_self #:nodoc:
|
36
|
+
@result = nil
|
37
|
+
@computed = nil
|
35
38
|
@shared_lock = 0
|
36
39
|
@children_results = nil
|
37
|
-
@result = nil
|
38
40
|
end
|
39
41
|
|
40
42
|
#
|
@@ -83,50 +85,55 @@ module CompTree
|
|
83
85
|
# If all children have been computed, return their results;
|
84
86
|
# otherwise return nil.
|
85
87
|
#
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
else
|
88
|
+
# Do not assign to @children_results since own lock is not
|
89
|
+
# necessarily aquired.
|
90
|
+
#
|
91
|
+
def find_children_results #:nodoc:
|
92
|
+
@children_results or (
|
93
|
+
@children.map { |child|
|
94
|
+
unless child.computed
|
94
95
|
return nil
|
95
96
|
end
|
97
|
+
child.result
|
96
98
|
}
|
97
|
-
|
98
|
-
end
|
99
|
+
)
|
99
100
|
end
|
100
101
|
|
101
|
-
def trace_compute #:nodoc:
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
102
|
+
#def trace_compute #:nodoc:
|
103
|
+
# debug {
|
104
|
+
# # --- own mutex
|
105
|
+
# trace "Computing #{@name}"
|
106
|
+
# raise AssertionFailedError if @computed
|
107
|
+
# raise AssertionFailedError unless @mutex.locked?
|
108
|
+
# raise AssertionFailedError unless @children_results
|
109
|
+
# }
|
110
|
+
#end
|
110
111
|
|
111
112
|
#
|
112
113
|
# Compute this node; children must be computed and lock must be
|
113
114
|
# already acquired.
|
114
115
|
#
|
115
116
|
def compute #:nodoc:
|
116
|
-
|
117
|
-
|
117
|
+
begin
|
118
|
+
unless @function
|
119
|
+
raise NoFunctionError,
|
118
120
|
"No function was defined for node '#{@name.inspect}'"
|
121
|
+
end
|
122
|
+
@result = @function.call(*@children_results)
|
123
|
+
@computed = true
|
124
|
+
rescue Exception => e
|
125
|
+
@computed = e
|
119
126
|
end
|
120
|
-
@
|
127
|
+
@result
|
121
128
|
end
|
122
129
|
|
123
130
|
def try_lock #:nodoc:
|
124
131
|
# --- shared tree mutex and own mutex
|
125
132
|
if @shared_lock == 0 and @mutex.try_lock
|
126
|
-
trace "Locking #{@name}"
|
133
|
+
#trace "Locking #{@name}"
|
127
134
|
each_upward { |node|
|
128
135
|
node.shared_lock += 1
|
129
|
-
trace "#{node.name} locked by #{@name}: level: #{node.shared_lock}"
|
136
|
+
#trace "#{node.name} locked by #{@name}: level: #{node.shared_lock}"
|
130
137
|
}
|
131
138
|
true
|
132
139
|
else
|
@@ -136,30 +143,19 @@ module CompTree
|
|
136
143
|
|
137
144
|
def unlock #:nodoc:
|
138
145
|
# --- shared tree mutex and own mutex
|
139
|
-
debug {
|
140
|
-
|
141
|
-
|
142
|
-
}
|
146
|
+
#debug {
|
147
|
+
# raise AssertionFailedError unless @mutex.locked?
|
148
|
+
# trace "Unlocking #{@name}"
|
149
|
+
#}
|
143
150
|
each_upward { |node|
|
144
151
|
node.shared_lock -= 1
|
145
|
-
debug {
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
}
|
152
|
+
#debug {
|
153
|
+
# if node.shared_lock == 0
|
154
|
+
# trace "#{node.name} unlocked by #{@name}"
|
155
|
+
# end
|
156
|
+
#}
|
150
157
|
}
|
151
158
|
@mutex.unlock
|
152
159
|
end
|
153
|
-
|
154
|
-
class << self
|
155
|
-
#
|
156
|
-
# Throw away the computation result?
|
157
|
-
#
|
158
|
-
# This Node base class always returns false.
|
159
|
-
#
|
160
|
-
def discard_result?
|
161
|
-
false
|
162
|
-
end
|
163
|
-
end
|
164
160
|
end
|
165
161
|
end
|
data/lib/comp_tree.rb
CHANGED
@@ -21,3 +21,59 @@
|
|
21
21
|
#
|
22
22
|
|
23
23
|
require 'comp_tree/driver'
|
24
|
+
|
25
|
+
#
|
26
|
+
# CompTree -- Parallel Computation Tree.
|
27
|
+
#
|
28
|
+
# See README.
|
29
|
+
#
|
30
|
+
module CompTree
|
31
|
+
class << self
|
32
|
+
#
|
33
|
+
# Build and run a new computation tree.
|
34
|
+
#
|
35
|
+
# A Driver instance is passed to the given block.
|
36
|
+
#
|
37
|
+
# Options hash:
|
38
|
+
#
|
39
|
+
# <tt>:node_class</tt> -- (Class) CompTree::Node subclass from
|
40
|
+
# which nodes are created.
|
41
|
+
#
|
42
|
+
# Example:
|
43
|
+
# CompTree.build do |driver|
|
44
|
+
#
|
45
|
+
# # Define a function named 'area' taking these two arguments.
|
46
|
+
# driver.define(:area, :width, :height) { |width, height|
|
47
|
+
# width*height
|
48
|
+
# }
|
49
|
+
#
|
50
|
+
# # Define a function 'width' which takes a 'border' argument.
|
51
|
+
# driver.define(:width, :border) { |border|
|
52
|
+
# 7 + border
|
53
|
+
# }
|
54
|
+
#
|
55
|
+
# # Ditto for 'height'.
|
56
|
+
# driver.define(:height, :border) { |border|
|
57
|
+
# 5 + border
|
58
|
+
# }
|
59
|
+
#
|
60
|
+
# #
|
61
|
+
# # Define a constant function 'border'.
|
62
|
+
# driver.define(:border) {
|
63
|
+
# 2
|
64
|
+
# }
|
65
|
+
#
|
66
|
+
# # Compute the area using four parallel threads.
|
67
|
+
# puts driver.compute(:area, :threads => 4)
|
68
|
+
# # => 63
|
69
|
+
#
|
70
|
+
# # We've done this computation.
|
71
|
+
# puts((7 + 2)*(5 + 2))
|
72
|
+
# # => 63
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
def build(opts = nil)
|
76
|
+
yield Driver.new(opts)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
module Jumpstart
|
5
|
+
module Ruby
|
6
|
+
EXECUTABLE = lambda {
|
7
|
+
name = File.join(
|
8
|
+
Config::CONFIG["bindir"],
|
9
|
+
Config::CONFIG["RUBY_INSTALL_NAME"]
|
10
|
+
)
|
11
|
+
|
12
|
+
if Config::CONFIG["host"] =~ %r!(mswin|cygwin|mingw)! and
|
13
|
+
File.basename(name) !~ %r!\.(exe|com|bat|cmd)\Z!i
|
14
|
+
name + Config::CONFIG["EXEEXT"]
|
15
|
+
else
|
16
|
+
name
|
17
|
+
end
|
18
|
+
}.call
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def run(*args)
|
22
|
+
system(EXECUTABLE, *args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_or_raise(*args)
|
26
|
+
cmd = [EXECUTABLE, *args]
|
27
|
+
unless system(*cmd)
|
28
|
+
msg = (
|
29
|
+
"failed to launch ruby: " +
|
30
|
+
"system(*#{cmd.inspect}) failed with status #{$?.exitstatus}"
|
31
|
+
)
|
32
|
+
raise msg
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_warnings(value = true)
|
37
|
+
previous = $VERBOSE
|
38
|
+
$VERBOSE = value
|
39
|
+
begin
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
$VERBOSE = previous
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def no_warnings(&block)
|
47
|
+
with_warnings(false, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,13 +2,9 @@
|
|
2
2
|
require 'rbconfig'
|
3
3
|
require 'fileutils'
|
4
4
|
require 'find'
|
5
|
-
require 'fileutils'
|
6
|
-
require 'quix/vars'
|
7
|
-
|
8
|
-
module CompTree
|
9
|
-
class SimpleInstaller
|
10
|
-
include CompTree::Vars
|
11
5
|
|
6
|
+
module Jumpstart
|
7
|
+
class SimpleInstaller
|
12
8
|
def initialize
|
13
9
|
dest_root = Config::CONFIG["sitelibdir"]
|
14
10
|
sources = []
|
@@ -49,19 +45,21 @@ module CompTree
|
|
49
45
|
end
|
50
46
|
}
|
51
47
|
|
52
|
-
acc <<
|
48
|
+
acc << {
|
49
|
+
:source => source,
|
50
|
+
:dest => dest,
|
51
|
+
:install => install,
|
52
|
+
:uninstall => uninstall,
|
53
|
+
}
|
53
54
|
end
|
54
55
|
}
|
55
56
|
end
|
56
57
|
|
57
58
|
def install_file?(source)
|
58
|
-
|
59
|
-
|
60
|
-
(File.file?(source) and File.extname(source) == ".rb"))
|
59
|
+
File.directory?(source) or
|
60
|
+
(File.file?(source) and File.extname(source) == ".rb")
|
61
61
|
end
|
62
62
|
|
63
|
-
attr_accessor :spec
|
64
|
-
|
65
63
|
def install
|
66
64
|
@spec.each { |entry|
|
67
65
|
entry[:install].call
|
@@ -75,7 +73,7 @@ module CompTree
|
|
75
73
|
end
|
76
74
|
|
77
75
|
def run(args = ARGV)
|
78
|
-
if args.empty?
|
76
|
+
if args.empty?
|
79
77
|
install
|
80
78
|
elsif args.size == 1 and args.first == "--uninstall"
|
81
79
|
uninstall
|