rakish 0.9.01.beta
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/doc/RakishOverview.html +8 -0
- data/doc/SimpleJavaSamples.txt +448 -0
- data/doc/ToDoItems.txt +18 -0
- data/doc/UserGuide +15 -0
- data/doc/WhyIDidIt.txt +96 -0
- data/lib/rakish/ArchiveBuilder.rb +216 -0
- data/lib/rakish/BuildConfig.rb +254 -0
- data/lib/rakish/CppProjects.rb +696 -0
- data/lib/rakish/IntellijConfig.rb +123 -0
- data/lib/rakish/JavaProjects.rb +504 -0
- data/lib/rakish/PlatformTools.rb +299 -0
- data/lib/rakish/Rakish.rb +2049 -0
- data/lib/rakish/RakishProject.rb +539 -0
- data/lib/rakish/RubydocModule.rb +58 -0
- data/lib/rakish/TomcatProjects.rb +45 -0
- data/lib/rakish/VcprojBuilder.rb +256 -0
- data/lib/rakish/WindowsCppTools.rb +897 -0
- data/lib/rakish/ZipBuilder.rb +82 -0
- data/lib/rakish.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +94 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,2049 @@
|
|
|
1
|
+
# Rakish module utilities
|
|
2
|
+
#
|
|
3
|
+
# $Id $
|
|
4
|
+
|
|
5
|
+
# this is becoming a "gem" we wat to require files with "rakish/FileName"
|
|
6
|
+
|
|
7
|
+
gemPath = File.expand_path("#{File.dirname(File.expand_path(__FILE__))}/..");
|
|
8
|
+
$LOAD_PATH.unshift(gemPath) unless $LOAD_PATH.include?(gemPath)
|
|
9
|
+
|
|
10
|
+
require 'open3.rb'
|
|
11
|
+
|
|
12
|
+
module Kernel # :nodoc:
|
|
13
|
+
|
|
14
|
+
#--
|
|
15
|
+
if false
|
|
16
|
+
|
|
17
|
+
if defined?(rakish_original_require) then
|
|
18
|
+
# Ruby ships with a custom_require, override its require
|
|
19
|
+
remove_method :require
|
|
20
|
+
else
|
|
21
|
+
# The Kernel#require from before RubyGems was loaded.
|
|
22
|
+
alias rakish_original_require require
|
|
23
|
+
private :rakish_original_require
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@@_rakish_={}
|
|
27
|
+
|
|
28
|
+
def require path
|
|
29
|
+
# $: is search path list
|
|
30
|
+
# $" is array of loaded files?
|
|
31
|
+
|
|
32
|
+
if rakish_original_require path
|
|
33
|
+
puts("************ requiring #{path}");
|
|
34
|
+
puts(" loaded #{$".last}");
|
|
35
|
+
true
|
|
36
|
+
else
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
private :require
|
|
41
|
+
end # end false
|
|
42
|
+
|
|
43
|
+
end # Kernel
|
|
44
|
+
#++
|
|
45
|
+
|
|
46
|
+
require 'set'
|
|
47
|
+
require 'logger'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
#-- stupid thing needed because rake doesn't check for "" arguments so we make an explicit task
|
|
51
|
+
#++
|
|
52
|
+
task "" do
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Module containg the package Rakish
|
|
56
|
+
# includes the module ::Rakish::Logger
|
|
57
|
+
#
|
|
58
|
+
# :include:doc/RakishOverview.html
|
|
59
|
+
#
|
|
60
|
+
# For more information see UserGuide[link:./doc/UserGuide.html]
|
|
61
|
+
#
|
|
62
|
+
module Rakish
|
|
63
|
+
|
|
64
|
+
# set to true if called from windows - cygwin
|
|
65
|
+
HostIsCygwin_ = (RUBY_PLATFORM =~ /(cygwin)/i) != nil;
|
|
66
|
+
# set to true if called on a windows host
|
|
67
|
+
HostIsWindows_ = (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil;
|
|
68
|
+
# set to true if called on a unix host
|
|
69
|
+
HostIsUnix_ = (!HostIsWindows_);
|
|
70
|
+
# set to true on a MacOS or iOS host
|
|
71
|
+
HostIsMac_ = (/darwin/ =~ RUBY_PLATFORM) != nil;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Logger module
|
|
75
|
+
# To use this Logger initialization include it in a class or module
|
|
76
|
+
# enables log.debug { "message" } etc
|
|
77
|
+
# from methods or initializations in that class
|
|
78
|
+
# Other than for INFO level output
|
|
79
|
+
# output messages are formatted to include the file and line number where
|
|
80
|
+
# log.[level] was invoked.
|
|
81
|
+
|
|
82
|
+
module Logger
|
|
83
|
+
|
|
84
|
+
@@_logger_ = ::Logger.new(STDOUT);
|
|
85
|
+
|
|
86
|
+
# Returns the singleton instance of ::Logger managed by the Rakish::Logger
|
|
87
|
+
def self.log
|
|
88
|
+
@@_logger_
|
|
89
|
+
end
|
|
90
|
+
@@_logger_.formatter = proc do |severity, datetime, progname, msg|
|
|
91
|
+
|
|
92
|
+
fileLine = "";
|
|
93
|
+
unless('INFO' === severity)
|
|
94
|
+
caller.each do |clr|
|
|
95
|
+
unless(/\/logger.rb:/ =~ clr)
|
|
96
|
+
fileLine = clr;
|
|
97
|
+
break;
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
fileLine = fileLine.split(':in `',2)[0];
|
|
101
|
+
fileLine.sub!(/:(\d)/, '(\1');
|
|
102
|
+
fileLine += ') : ';
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if(msg.is_a? Exception)
|
|
106
|
+
"#{fileLine}#{msg}\n #{formatBacktraceLine(msg.backtrace[0])}\n"
|
|
107
|
+
else
|
|
108
|
+
"#{fileLine}#{msg}\n"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Format a single backtrace line as defined for the IDE we are using.
|
|
113
|
+
def self.formatBacktraceLine(line)
|
|
114
|
+
sp = line.split(':in `',2);
|
|
115
|
+
sp0 = sp[0].sub(/:(\d)/, '(\1');
|
|
116
|
+
sp1 = sp.length > 1 ? "in `#{sp[1]}" : "";
|
|
117
|
+
"#{sp0}) : #{sp1}";
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Format all lines in a backtrace using formatBacktraceLine() into a
|
|
121
|
+
# single printable string with entries separated by "\\n"
|
|
122
|
+
def self.formatBacktrace(backtrace)
|
|
123
|
+
out=[];
|
|
124
|
+
backtrace.each do |line|
|
|
125
|
+
out << formatBacktraceLine(line);
|
|
126
|
+
end
|
|
127
|
+
out.join("\n");
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Defines the method "log" in any including
|
|
131
|
+
# module or class at the class "static" level
|
|
132
|
+
def self.included(by) # :nodoc:
|
|
133
|
+
by.class.send(:define_method, :log) do
|
|
134
|
+
::Rakish.log
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Returns the singleton instance of ::Logger managed by the Rakish::Logger
|
|
139
|
+
def log
|
|
140
|
+
STDOUT.flush;
|
|
141
|
+
::Rakish.log
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.log # :nodoc:
|
|
146
|
+
Rakish::Logger.log
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Execute shell command in sub process and pipe output to Logger at info level
|
|
150
|
+
# cmdline - single string command line, or array of command and arguments
|
|
151
|
+
# opts:
|
|
152
|
+
# :verbose - if set to true (testable value is true) will print command when executing
|
|
153
|
+
# :env - optional environment hash for spawned process
|
|
154
|
+
#
|
|
155
|
+
# returns status return from spawned process.
|
|
156
|
+
# uses Open3:popen2()
|
|
157
|
+
|
|
158
|
+
def self.execLogged(cmdline, opts={})
|
|
159
|
+
begin
|
|
160
|
+
if(cmdline.respond_to?(:to_ary))
|
|
161
|
+
log.info("\"#{cmdline.join("\" \"")}\"") if opts[:verbose]
|
|
162
|
+
# it is the array form of command
|
|
163
|
+
unless (Hash === cmdline[0]) # to handle ruby style environment argument - env is cmdline[0]
|
|
164
|
+
cmdline.unshift(opts[:env]) if opts[:env];
|
|
165
|
+
end
|
|
166
|
+
else
|
|
167
|
+
# TODO: handle parsing command line into array of arguments if opts[:env]
|
|
168
|
+
log.info("#{cmdline}") if opts[:verbose]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# this will redirect both stdout and stderr to the "output" pipe
|
|
172
|
+
# TODO: handle throwing exception if the process aborts with an error return code
|
|
173
|
+
exit_status = nil;
|
|
174
|
+
Open3.popen2(*cmdline, :err => [:child, :out]) do |i,output,t|
|
|
175
|
+
while line = output.gets do
|
|
176
|
+
log.info line.strip!
|
|
177
|
+
end
|
|
178
|
+
exit_status = t.value; # Process::Status object returned.
|
|
179
|
+
end
|
|
180
|
+
return(exit_status);
|
|
181
|
+
# IO.popen(cmdline) do |output|
|
|
182
|
+
# while line = output.gets do
|
|
183
|
+
# log.info line.strip!
|
|
184
|
+
# end
|
|
185
|
+
# end
|
|
186
|
+
# return $?
|
|
187
|
+
rescue => e
|
|
188
|
+
if(opts[:verbose])
|
|
189
|
+
if(cmdline.respond_to?(:to_ary))
|
|
190
|
+
cmdline.shift if opts[:env];
|
|
191
|
+
cmdline = "\"#{cmdline.join("\" \"")}\"";
|
|
192
|
+
end
|
|
193
|
+
log.error("failure executing: #{cmdline}");
|
|
194
|
+
end
|
|
195
|
+
log.error(e);
|
|
196
|
+
raise(e);
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# convenience method like Rake::task
|
|
201
|
+
def self.task(*args,&block)
|
|
202
|
+
::Rake::Task.define_task(*args, &block)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# Rake extensions
|
|
209
|
+
module Rake
|
|
210
|
+
|
|
211
|
+
module DSL # :nodoc: so if a version doesn't have it it works
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
class << self
|
|
215
|
+
# get a new generated unique name for "anonymous" classes
|
|
216
|
+
# and tasks and other uses
|
|
217
|
+
def get_unique_name
|
|
218
|
+
@_s_||=0
|
|
219
|
+
@_s_ += 1
|
|
220
|
+
:"_nona_#{@_s_}"
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# Rake::TaskManager extensions
|
|
228
|
+
module TaskManager
|
|
229
|
+
|
|
230
|
+
# Two difference here:
|
|
231
|
+
# flattening of dependency lists
|
|
232
|
+
# so arguments can be arrays of arrays
|
|
233
|
+
# and it will recognize a leading ':' as an indicator of global root namespace scope
|
|
234
|
+
# in additon to "rake:"
|
|
235
|
+
def resolve_args(args)
|
|
236
|
+
if args.last.is_a?(Hash)
|
|
237
|
+
deps = args.pop
|
|
238
|
+
ret = resolve_args_with_dependencies(args, deps)
|
|
239
|
+
ret[2].flatten!
|
|
240
|
+
ret[2].map! do |e|
|
|
241
|
+
(e=~/^:/)?"rake#{e}":e
|
|
242
|
+
end
|
|
243
|
+
ret
|
|
244
|
+
else
|
|
245
|
+
resolve_args_without_dependencies(args)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Rake::Application extensions
|
|
251
|
+
class Application
|
|
252
|
+
|
|
253
|
+
# Display the error message that caused the exception.
|
|
254
|
+
# formatted the way we like it for a particualar IDE
|
|
255
|
+
|
|
256
|
+
def display_error_message(ex)
|
|
257
|
+
|
|
258
|
+
$stdout.flush;
|
|
259
|
+
$stderr.flush;
|
|
260
|
+
|
|
261
|
+
$stderr.puts "#{name} aborted!: #{ex.message}"
|
|
262
|
+
backtrace = ex.backtrace;
|
|
263
|
+
|
|
264
|
+
if options.trace
|
|
265
|
+
$stderr.puts Rakish::Logger.formatBacktrace(backtrace)
|
|
266
|
+
else
|
|
267
|
+
|
|
268
|
+
lineNum = 0;
|
|
269
|
+
useLine = 0;
|
|
270
|
+
|
|
271
|
+
if(ex.message =~ /wrong number of arguments/)
|
|
272
|
+
useLine = 1;
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
backtrace.each do |line|
|
|
276
|
+
lineNum = lineNum + 1;
|
|
277
|
+
sp = line.split(':in `',2);
|
|
278
|
+
if(sp.length > 1)
|
|
279
|
+
if(sp[1] =~ /const_missing'$/)
|
|
280
|
+
useLine = lineNum;
|
|
281
|
+
break;
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
$stderr.puts(Rakish::Logger.formatBacktraceLine(backtrace[useLine]));
|
|
287
|
+
$stderr.puts(rakefile_location(backtrace)); # this seems to be broken !!
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
$stderr.puts "Tasks: #{ex.chain}" if has_chain?(ex)
|
|
291
|
+
$stderr.puts "(See full trace by running task with --trace)" unless options.trace
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
class Task
|
|
296
|
+
include Rakish::Logger
|
|
297
|
+
|
|
298
|
+
rake_extension('config') do
|
|
299
|
+
# note commented because Rdoc does not parse this
|
|
300
|
+
# attr_accessor :config
|
|
301
|
+
end
|
|
302
|
+
# optional "config" field on Rake Task objects
|
|
303
|
+
attr_accessor :config
|
|
304
|
+
|
|
305
|
+
rake_extension('data') do
|
|
306
|
+
# note commented because RDoc does not parse this
|
|
307
|
+
# attr_accessor :data
|
|
308
|
+
end
|
|
309
|
+
# optional "per instance" field on Rake Task objects
|
|
310
|
+
attr_accessor :data
|
|
311
|
+
|
|
312
|
+
# see Rake.Task as this overrides it's method
|
|
313
|
+
# to flatten dependencies so they can be provided as
|
|
314
|
+
# nested arrays or arguments
|
|
315
|
+
def enhance(args,&b)
|
|
316
|
+
# instead of |=
|
|
317
|
+
@prerequisites = [@prerequisites,args].flatten if args
|
|
318
|
+
@actions << b if block_given?
|
|
319
|
+
self
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def scopeExec(args=nil) # :nodoc:
|
|
323
|
+
@application.in_namespace_scope(@scope) do
|
|
324
|
+
FileUtils.cd @_p_.projectDir do
|
|
325
|
+
_baseExec_(args);
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
private :scopeExec
|
|
330
|
+
|
|
331
|
+
rake_extension('setProjectScope') do
|
|
332
|
+
def setProjectScope(d) # :nodoc:
|
|
333
|
+
return self if(@_p_)
|
|
334
|
+
instance_eval do
|
|
335
|
+
alias :_baseExec_ :execute
|
|
336
|
+
alias :execute :scopeExec
|
|
337
|
+
end
|
|
338
|
+
@_p_=d;
|
|
339
|
+
self
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
class << self
|
|
344
|
+
# define a task with a unique anonymous name
|
|
345
|
+
# does not handle :name=>[] dependencies because the generated name is
|
|
346
|
+
# not known at the time of this declaratation
|
|
347
|
+
def define_unique_task(*args,&b)
|
|
348
|
+
args.unshift(Rake.get_unique_name)
|
|
349
|
+
Rake.application.define_task(self,*args,&b);
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# Extension to force all file tasks to reference the full path for the file name.
|
|
355
|
+
# We want to make sure all File tasks are named after the full path
|
|
356
|
+
# so there is only one present for any given file.
|
|
357
|
+
class FileTask
|
|
358
|
+
class << self
|
|
359
|
+
# Apply the scope to the task name according to the rules for this kind
|
|
360
|
+
# of task. File based tasks ignore the scope when creating the name.
|
|
361
|
+
def scope_name(scope, task_name)
|
|
362
|
+
File.expand_path(task_name)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
module TaskManager
|
|
368
|
+
|
|
369
|
+
if(RUBY_VERSION =~ /^2./)
|
|
370
|
+
def _trc # :nodoc:
|
|
371
|
+
puts("** namespace \":#{@scope.path}\"");
|
|
372
|
+
end
|
|
373
|
+
else # ruby 1.9.X
|
|
374
|
+
def _trc # :nodoc:
|
|
375
|
+
puts("** namespace \":#{@scope.join(':')}\"");
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
private :_trc
|
|
379
|
+
|
|
380
|
+
# Directory tasks are always in root list so this should be a bit faster
|
|
381
|
+
rake_extension('directory_task_defined?') do
|
|
382
|
+
# Return true if a directory creation task for the diven path is defined.
|
|
383
|
+
def directory_task_defined?(path)
|
|
384
|
+
@tasks.has_key?(path)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
rake_extension('in_namespace_scope') do
|
|
389
|
+
# Allows for explicitly setting an "absolute" namespace
|
|
390
|
+
# Executes the block in the provided scope.
|
|
391
|
+
def in_namespace_scope(scope)
|
|
392
|
+
prior = @scope;
|
|
393
|
+
@scope = scope;
|
|
394
|
+
if options.trace
|
|
395
|
+
_trc
|
|
396
|
+
end
|
|
397
|
+
ns = NameSpace.new(self,scope);
|
|
398
|
+
yield(ns)
|
|
399
|
+
ns
|
|
400
|
+
ensure
|
|
401
|
+
@scope = prior;
|
|
402
|
+
if options.trace
|
|
403
|
+
_trc
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
if(RUBY_VERSION =~ /^2./)
|
|
409
|
+
# this allows for explicitly setting an "absolute" namespace from string
|
|
410
|
+
rake_extension('in_namespace_path') do
|
|
411
|
+
def in_namespace_path(name,&b)
|
|
412
|
+
|
|
413
|
+
# handle new scope which is a linked list instead of an array
|
|
414
|
+
prior=@scope
|
|
415
|
+
if(name.instance_of?(String))
|
|
416
|
+
spl = name.split(':');
|
|
417
|
+
newScope = @scope;
|
|
418
|
+
if(spl.size() == 0 || spl[0].length == 0) # absolute, begins with ':'
|
|
419
|
+
spl.shift();
|
|
420
|
+
# Rakish.log.debug("prior scope is \"#{name}\" => \"#{prior.path}\"");
|
|
421
|
+
newScope = Scope.make;
|
|
422
|
+
# else # relative
|
|
423
|
+
# TODO: handle '..:..: for back a level ???
|
|
424
|
+
end
|
|
425
|
+
spl.each do |elem|
|
|
426
|
+
newScope = Scope.new(elem,newScope);
|
|
427
|
+
end
|
|
428
|
+
@scope = newScope;
|
|
429
|
+
# Rakish.log.debug("new scope is \"#{@scope.path}\"");
|
|
430
|
+
elsif(name) # untested
|
|
431
|
+
Rakish.log.debug("prior scope is \"#{prior.path}\"");
|
|
432
|
+
@scope=Scope.new(name,@scope);
|
|
433
|
+
Rakish.log.debug("new scope is \"#{@scope.path}\"");
|
|
434
|
+
else # untested
|
|
435
|
+
Rakish.log.debug("prior scope is \"#{prior.path}\"");
|
|
436
|
+
@scope=Scope.make; # explicit to root
|
|
437
|
+
Rakish.log.debug("new scope is \"#{@scope.path}\"");
|
|
438
|
+
end
|
|
439
|
+
if options.trace
|
|
440
|
+
_trc
|
|
441
|
+
end
|
|
442
|
+
ns = NameSpace.new(self,@scope);
|
|
443
|
+
yield(ns)
|
|
444
|
+
ns
|
|
445
|
+
ensure
|
|
446
|
+
@scope=prior;
|
|
447
|
+
if options.trace
|
|
448
|
+
_trc
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
else # Ruby 1.9.X
|
|
454
|
+
# this allows for explicitly setting an "absolute" namespace from string
|
|
455
|
+
rake_extension('in_namespace_path') do
|
|
456
|
+
def in_namespace_path(name,&b)
|
|
457
|
+
prior=@scope
|
|
458
|
+
if(name.instance_of?(String))
|
|
459
|
+
spl = name.split(':');
|
|
460
|
+
if(spl.size() == 0 || spl[0].length == 0) # absolute
|
|
461
|
+
spl.shift();
|
|
462
|
+
@scope = spl;
|
|
463
|
+
else # relative
|
|
464
|
+
@scope = Array.new(prior).concat(spl);
|
|
465
|
+
end
|
|
466
|
+
elsif(name)
|
|
467
|
+
@scope=Array.new(prior).push(name);
|
|
468
|
+
else
|
|
469
|
+
@scope=Array.new
|
|
470
|
+
end
|
|
471
|
+
if options.trace
|
|
472
|
+
_trc
|
|
473
|
+
end
|
|
474
|
+
ns = NameSpace.new(self,@scope);
|
|
475
|
+
yield(ns)
|
|
476
|
+
ns
|
|
477
|
+
ensure
|
|
478
|
+
@scope=prior;
|
|
479
|
+
if options.trace
|
|
480
|
+
_trc
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
end # ruby 1.9.X
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
module Rakish
|
|
489
|
+
|
|
490
|
+
# extension to Ruby ::File class
|
|
491
|
+
class ::File
|
|
492
|
+
|
|
493
|
+
unless defined? ::File.path_is_absolute?
|
|
494
|
+
|
|
495
|
+
if(HostIsWindows_)
|
|
496
|
+
# Return true if path is an absolute path
|
|
497
|
+
def self.path_is_absolute?(path)
|
|
498
|
+
f0 = path[0]
|
|
499
|
+
f0 == '/' or f0 == '\\' or path[1] == ':'
|
|
500
|
+
end
|
|
501
|
+
else
|
|
502
|
+
# Return true if file is an absolute path
|
|
503
|
+
def self.path_is_absolute?(path)
|
|
504
|
+
path[0] == '/'
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
# Extensons to root level Module
|
|
511
|
+
|
|
512
|
+
class ::Module
|
|
513
|
+
|
|
514
|
+
# Static method used like ruby's attr_accessor declaration
|
|
515
|
+
# for use in declaring added properties on a class
|
|
516
|
+
# inheriting from a Rakish::PropertyBag or including a Rakish::PropertyBagMod
|
|
517
|
+
|
|
518
|
+
def attr_property(*args)
|
|
519
|
+
if(self.include? ::Rakish::PropertyBagMod)
|
|
520
|
+
args.each do |s|
|
|
521
|
+
# add "property" assignment operator method s= to this class
|
|
522
|
+
# equivalent of: def s=(v) { @_h[s]=v }
|
|
523
|
+
# where s is the input symbol, it is formatted as a string and passed
|
|
524
|
+
# to eval
|
|
525
|
+
eval("self.send(:define_method,:#{s}=){|v|@_h[:#{s}]=v}")
|
|
526
|
+
end
|
|
527
|
+
else
|
|
528
|
+
raise("can only add properties to PropertyBag object")
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
# Allows for the declaration and initialization of
|
|
533
|
+
# "Constructor" chains in the way C++ or Java operates where base classes (here mixin modules)
|
|
534
|
+
# can be optionally "automagically" invoked in inclusion order on class instance initialization.
|
|
535
|
+
# Any Class and Module may now take advantage of this. see ::Class.initializeIncluded
|
|
536
|
+
#
|
|
537
|
+
# Module HasConstructor
|
|
538
|
+
# addInitBlock do |args|
|
|
539
|
+
# @myVariable_ = "initialized in constructor of HasContructor"
|
|
540
|
+
# log.debug("initializing HasConstructor - on #{self} XX #{arg[0]}");
|
|
541
|
+
# end
|
|
542
|
+
# end
|
|
543
|
+
#
|
|
544
|
+
# class MyObject
|
|
545
|
+
# include HasConstructor
|
|
546
|
+
#
|
|
547
|
+
# initialize(*args)
|
|
548
|
+
# # Of course all modules included on this object and by their recursively
|
|
549
|
+
# # included modules must respond properly to args so likely best to use
|
|
550
|
+
# # named hash args and a naming convention for what included modules
|
|
551
|
+
# # use as opposed to an array of positional arguments
|
|
552
|
+
# self.class.initializeIncluded(self,args);
|
|
553
|
+
# end
|
|
554
|
+
# end
|
|
555
|
+
|
|
556
|
+
def addInitBlock(&b)
|
|
557
|
+
(@_init_||=[])<<b if block_given?
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def _initBlocks_ # :nodoc:
|
|
561
|
+
@_init_;
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
class ::Class
|
|
567
|
+
|
|
568
|
+
# Monkey Hack to enable constructor inheritance like C++ on mixin modules
|
|
569
|
+
# and call the "initBlocks" of all modules included in this class in the included order
|
|
570
|
+
# installed by included modules which are nicely provided by the ruby ancestors list
|
|
571
|
+
# To do this use this in a Class instance initializer, the arguments will be passed to all superclass mixin init blocks:
|
|
572
|
+
#
|
|
573
|
+
# obj.class.initializeIncluded(obj,*args);
|
|
574
|
+
#
|
|
575
|
+
# see ::Module and ::Module.addInitBlock() for example.
|
|
576
|
+
|
|
577
|
+
def initializeIncluded(obj,*args)
|
|
578
|
+
# call the included modules init blocks with arguments
|
|
579
|
+
self.ancestors.reverse_each do |mod|
|
|
580
|
+
inits = mod._initBlocks_;
|
|
581
|
+
if inits
|
|
582
|
+
inits.each do |b|
|
|
583
|
+
obj.instance_exec(args,&b);
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
# Container for searchable path set for finding files in
|
|
591
|
+
class SearchPath
|
|
592
|
+
|
|
593
|
+
# Initialize a new SearchPath calls setPath(*paths)
|
|
594
|
+
def initialize(*paths)
|
|
595
|
+
setPath(*paths);
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
if( HostIsWindows_ )
|
|
599
|
+
@@osDelimiter_=';';
|
|
600
|
+
else
|
|
601
|
+
@@osDelimiter_=':';
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Clear and set path set and call adPath(*paths)
|
|
605
|
+
#
|
|
606
|
+
# If no paths are provided then this path set is left empty.
|
|
607
|
+
def setPath(*paths)
|
|
608
|
+
@path_=[];
|
|
609
|
+
addPath(*paths);
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
# So we can pass this into SearchPath.new or SearchPath.addPath
|
|
613
|
+
def to_ary # :nodoc:
|
|
614
|
+
@path_
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# Iterate over all paths in this SearchPath
|
|
618
|
+
def each(&b)
|
|
619
|
+
@path_.each(&b)
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
# Add a path or path list to this search path
|
|
623
|
+
# If a path entry begins with a '.' is will be left in the search path
|
|
624
|
+
# as a relative path, otherwise it will be expanded to an absolute path when added.
|
|
625
|
+
#
|
|
626
|
+
# Named opts:
|
|
627
|
+
# :delimiter => path entry delimiter
|
|
628
|
+
#
|
|
629
|
+
def addPath(*paths)
|
|
630
|
+
opts = (Hash === paths.last) ? paths.pop : {}
|
|
631
|
+
delimiter = opts[:delimiter] ||@@osDelimiter_;
|
|
632
|
+
paths.flatten!
|
|
633
|
+
paths.each do |path|
|
|
634
|
+
pa = path.split(delimiter);
|
|
635
|
+
pa.each do |p|
|
|
636
|
+
p=File.absolute_path(p) unless p[0]=='.'
|
|
637
|
+
@path_ << p;
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
@path_.uniq!
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# like array.join() to build path strings
|
|
644
|
+
def join(s)
|
|
645
|
+
@path_.join(s);
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
private
|
|
649
|
+
def onNotFound(name,opts) # :nodoc:
|
|
650
|
+
msg = "could not find file #{name}\n from: #{File.expand_path('.')}\n in:\n #{join("\n ")}"
|
|
651
|
+
case opts[:onMissing]
|
|
652
|
+
when 'log.error'
|
|
653
|
+
::Rakish.log.error msg;
|
|
654
|
+
when 'log.warn'
|
|
655
|
+
::Rakish.log.warn msg;
|
|
656
|
+
when 'log.debug'
|
|
657
|
+
::Rakish.log.debug msg;
|
|
658
|
+
when 'log.info'
|
|
659
|
+
::Rakish.log.debug msg;
|
|
660
|
+
else
|
|
661
|
+
raise Exception.new(msg);
|
|
662
|
+
end
|
|
663
|
+
end
|
|
664
|
+
public
|
|
665
|
+
|
|
666
|
+
# Find a file with the given name (or relative subpath) in this search set
|
|
667
|
+
# If the input name is an absolute path it is simply returned.
|
|
668
|
+
# named ops:
|
|
669
|
+
# :suffi => If set search for file with suffix in order of suffi list
|
|
670
|
+
# '' is a valid suffix in this case. suffi must have leading dot
|
|
671
|
+
# as in '.exe'
|
|
672
|
+
# :onMissing => reporting action to perform when file is not found
|
|
673
|
+
# 'log.error','log.warn',log.debug','log.info',
|
|
674
|
+
# any other true (or non false/nil) value raises an exception
|
|
675
|
+
# I prefer 'raise'
|
|
676
|
+
#
|
|
677
|
+
|
|
678
|
+
def findFile(name,opts={})
|
|
679
|
+
if(File.path_is_absolute?(name))
|
|
680
|
+
onNotFound(name,opts) if(opts[:onMissing] && (!File.exists?(name)))
|
|
681
|
+
return(name);
|
|
682
|
+
end
|
|
683
|
+
found = nil;
|
|
684
|
+
suffi = opts[:suffi];
|
|
685
|
+
@path_.each do |path|
|
|
686
|
+
path = "#{path}/#{name}";
|
|
687
|
+
unless suffi
|
|
688
|
+
if(File.exists?(path))
|
|
689
|
+
found=File.absolute_path(path);
|
|
690
|
+
break;
|
|
691
|
+
end
|
|
692
|
+
else
|
|
693
|
+
suffi.each do |suff|
|
|
694
|
+
fpath="#{path}.exe";
|
|
695
|
+
if(File.exists?(fpath))
|
|
696
|
+
found=File.absolute_path(fpath);
|
|
697
|
+
break;
|
|
698
|
+
end
|
|
699
|
+
end
|
|
700
|
+
break if(found)
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
onNotFound(name,opts) if(!found && opts[:onMissing]);
|
|
704
|
+
found;
|
|
705
|
+
end
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
# Intended to clean up things to minimize thread usage and queue up these so as to
|
|
709
|
+
# keep avaiable processor cores saturated but without thread thrashing. Spawning lots of threads
|
|
710
|
+
# does not help in the process spawning case and actually slows things down.
|
|
711
|
+
class MultiProcessTask < Rake::Task
|
|
712
|
+
private
|
|
713
|
+
def invoke_prerequisites(args, invocation_chain)
|
|
714
|
+
threads = @prerequisites.collect { |p|
|
|
715
|
+
Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
|
|
716
|
+
}
|
|
717
|
+
threads.each { |t| t.join }
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
module LoadableModule
|
|
722
|
+
include Rakish::Logger
|
|
723
|
+
|
|
724
|
+
@@loadedByFile_ = {};
|
|
725
|
+
|
|
726
|
+
def self.load(fileName)
|
|
727
|
+
fileName = File.expand_path(fileName);
|
|
728
|
+
mod = @@loadedByFile_[fileName];
|
|
729
|
+
return mod if mod;
|
|
730
|
+
begin
|
|
731
|
+
Thread.current[:loadReturn] = nil;
|
|
732
|
+
Kernel.load(fileName);
|
|
733
|
+
mod = Thread.current[:loadReturn];
|
|
734
|
+
@@loadedByFile_[fileName] = mod if(mod);
|
|
735
|
+
rescue => e
|
|
736
|
+
log.error { e };
|
|
737
|
+
mod = nil;
|
|
738
|
+
end
|
|
739
|
+
Thread.current[:loadReturn] = nil;
|
|
740
|
+
mod
|
|
741
|
+
end
|
|
742
|
+
def self.onLoaded(retVal)
|
|
743
|
+
Thread.current[:loadReturn] = retVal;
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
public
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
# a bunch of utility functions used by Projects and configurations
|
|
751
|
+
module Util
|
|
752
|
+
include ::Rake::DSL
|
|
753
|
+
include Rakish::Logger
|
|
754
|
+
|
|
755
|
+
# Very simple module for Git used to initialize my projects
|
|
756
|
+
module Git # :nodoc:
|
|
757
|
+
|
|
758
|
+
class << self
|
|
759
|
+
def clone(src,dest,opts={})
|
|
760
|
+
if(!File.directory?(dest))
|
|
761
|
+
|
|
762
|
+
origin = opts[:remote] || "origin";
|
|
763
|
+
|
|
764
|
+
puts("Git.clone -o \"#{origin}\" -n \"#{src}\" \"#{dest}\"");
|
|
765
|
+
|
|
766
|
+
system("git clone -o \"#{origin}\" -n \"#{src}\" \"#{dest}\"");
|
|
767
|
+
cd dest do
|
|
768
|
+
system("git config -f ./.git/config --replace-all core.autocrlf true");
|
|
769
|
+
system("git reset -q --hard");
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
def addRemote(dir, name, uri)
|
|
775
|
+
cd dir do
|
|
776
|
+
system("git remote add \"#{name}\" \"#{uri}\"");
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
# convenience method like Rake::task
|
|
783
|
+
def task(*args,&block)
|
|
784
|
+
Rake::Task.define_task(*args, &block)
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# Like each but checks for null and if object doesn't respond to each
|
|
788
|
+
#
|
|
789
|
+
# use like
|
|
790
|
+
# eachof [1,2,3] do |v|
|
|
791
|
+
# end
|
|
792
|
+
#
|
|
793
|
+
def eachof(v,&b)
|
|
794
|
+
v.each &b rescue yield v if v # TODO: should use a narrower exception type ?
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
protected
|
|
798
|
+
# Task action to simply copy source to destination
|
|
799
|
+
SimpleCopyAction_ = ->(t) { FileUtils.cp(t.source, t.name) }
|
|
800
|
+
|
|
801
|
+
# Task action to do nothing.
|
|
802
|
+
DoNothingAction_ = ->(t) {}
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
public
|
|
806
|
+
|
|
807
|
+
# Execute shell command and pipe output to Logger
|
|
808
|
+
def execLogged(cmd, opts={})
|
|
809
|
+
Rakish.execLogged(cmd,opts)
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
# Get current namespace as a string.
|
|
813
|
+
def currentNamespace
|
|
814
|
+
":#{Rake.application.current_scope.join(':')}";
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
# Used like Rake's 'namespace' to execute the block
|
|
818
|
+
# in the specified namespace, except it enables
|
|
819
|
+
# explicit specification of absolute namespace paths
|
|
820
|
+
# ie:
|
|
821
|
+
# ':' selects the root namespace
|
|
822
|
+
# ':levelOne:levelTwo' is an absolute specification to ':'
|
|
823
|
+
#
|
|
824
|
+
def namespace(name=nil,&block)
|
|
825
|
+
Rake.application.in_namespace_path(name, &block)
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
# Get time stamp of file or directory
|
|
829
|
+
def filetime(name)
|
|
830
|
+
File.exists?(name) ? File.mtime(name.to_s) : Rake::EARLY
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
# Are there any tasks in the iterable 'tasks' list with an earlier 'time' than the given time stamp?
|
|
834
|
+
def any_task_earlier?(tasks,time)
|
|
835
|
+
tasks.any? { |n| n.timestamp < time }
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
# Get simple task action block (lambda) to copy from t.source to t.name
|
|
839
|
+
# do |t|
|
|
840
|
+
# cp t.source, t.name
|
|
841
|
+
# end
|
|
842
|
+
def simpleCopyAction()
|
|
843
|
+
SimpleCopyAction_
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
def deleteFileArray(files,opts={}) # :nodoc:
|
|
847
|
+
noglob = opts[:noglob]
|
|
848
|
+
|
|
849
|
+
files.each do |f|
|
|
850
|
+
if(f.respond_to?(:to_ary))
|
|
851
|
+
deleteFileArray(f,opts)
|
|
852
|
+
next
|
|
853
|
+
end
|
|
854
|
+
f = f.to_s
|
|
855
|
+
unless noglob
|
|
856
|
+
if(f =~ /[*?]/)
|
|
857
|
+
deleteFileArray(FileList.new(f),opts)
|
|
858
|
+
next
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
rm f,opts
|
|
862
|
+
end
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
# delete list of files (a single file or no files) similar to system("rm [list of files]")
|
|
866
|
+
# accepts Strings, FileList(s) and FileSet(s) and arrays of them
|
|
867
|
+
#
|
|
868
|
+
# named options: all [true|false]:
|
|
869
|
+
#
|
|
870
|
+
# :force => default true
|
|
871
|
+
# :noop => just print (if verbose) don't do anything
|
|
872
|
+
# :verbose => print "rm ..." for each file
|
|
873
|
+
# :noglob => do not interpret '*' or '?' as wildcard chars
|
|
874
|
+
#
|
|
875
|
+
#
|
|
876
|
+
def deleteFiles(*files)
|
|
877
|
+
opts = (Hash === files.last) ? files.pop : {}
|
|
878
|
+
opts[:force]||=true # default to true
|
|
879
|
+
opts[:verbose]||=false # default to false
|
|
880
|
+
deleteFileArray(files,opts)
|
|
881
|
+
end
|
|
882
|
+
alias :deleteFile :deleteFiles
|
|
883
|
+
|
|
884
|
+
def getCallingLocation(count = 0)
|
|
885
|
+
myLoc = nil
|
|
886
|
+
count += 1;
|
|
887
|
+
if(RUBY_VERSION =~ /^1\.9\.\d/)
|
|
888
|
+
caller.each do |clr|
|
|
889
|
+
if(count <= 0)
|
|
890
|
+
myLoc = clr;
|
|
891
|
+
break;
|
|
892
|
+
end
|
|
893
|
+
count = count - 1;
|
|
894
|
+
if(clr =~ /:in `<top \(required\)>'$/)
|
|
895
|
+
myLoc = $`;
|
|
896
|
+
break;
|
|
897
|
+
end
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
return(myLoc);
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
# ensures a task is present to create directory dir
|
|
904
|
+
def ensureDirectoryTask(dir)
|
|
905
|
+
unless(dir)
|
|
906
|
+
loc = getCallingLocation();
|
|
907
|
+
log.debug("warning: #{loc} ensuring NIL directory");
|
|
908
|
+
else
|
|
909
|
+
unless Rake.application.directory_task_defined?(dir)
|
|
910
|
+
Rake.each_dir_parent(dir) do |d|
|
|
911
|
+
file_create d do |t|
|
|
912
|
+
FileUtils.mkdir_p t.name if ! File.exist?(t.name)
|
|
913
|
+
end
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
dir
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
def copyRule(destdir, srcdir, suffix) # :nodoc:
|
|
921
|
+
|
|
922
|
+
# puts(" copy rule #{srcdir} #{destdir} #{suffix}" );
|
|
923
|
+
|
|
924
|
+
if(srcdir =~ /\/\z/)
|
|
925
|
+
srcdir = $`
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
if(destdir =~ /\/\z/)
|
|
929
|
+
# too bad rake doesn't check both, but string based
|
|
930
|
+
ensureDirectoryTask(destdir)
|
|
931
|
+
destdir = $`
|
|
932
|
+
end
|
|
933
|
+
ensureDirectoryTask(destdir)
|
|
934
|
+
|
|
935
|
+
# puts("creating rule for #{srcdir} -> #{destdir}");
|
|
936
|
+
|
|
937
|
+
regex =
|
|
938
|
+
Regexp.new('^' + Regexp.escape(destdir) + '\/[^\/]+' + suffix + '\z', true);
|
|
939
|
+
|
|
940
|
+
Rake::Task::create_rule( regex => [
|
|
941
|
+
proc { |task_name|
|
|
942
|
+
task_name =~ /\/[^\/]+\z/
|
|
943
|
+
task_name = srcdir + $&
|
|
944
|
+
}
|
|
945
|
+
]) do |t|
|
|
946
|
+
cp(t.source, t.name);
|
|
947
|
+
end
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
# This will "pre-process" input lines using the ruby escape sequence
|
|
951
|
+
# '#{}' for substitutions
|
|
952
|
+
#
|
|
953
|
+
# in the binding
|
|
954
|
+
# linePrefix is an optional prefix to prepend to each line.
|
|
955
|
+
#
|
|
956
|
+
# setIndent means set a variable "indent" in the environment
|
|
957
|
+
# to be the indent level of the current raw line
|
|
958
|
+
#
|
|
959
|
+
# lines = input lines (has to implement each_line)
|
|
960
|
+
# fout = output file (has to implement puts, print)
|
|
961
|
+
# bnd = "binding" to context to evaluate substitutions in
|
|
962
|
+
def rubyLinePP(lines,fout,bnd,opts={})
|
|
963
|
+
|
|
964
|
+
setIndent = eval('defined? indent',bnd)
|
|
965
|
+
linePrefix = opts[:linePrefix];
|
|
966
|
+
|
|
967
|
+
rawLine = nil;
|
|
968
|
+
lineNum = 0;
|
|
969
|
+
begin
|
|
970
|
+
lines.each_line do |line|
|
|
971
|
+
++lineNum;
|
|
972
|
+
rawLine = line;
|
|
973
|
+
fout.print(linePrefix) if linePrefix;
|
|
974
|
+
fout.puts line.gsub(/\#\{[^\#]+\}/) { |m|
|
|
975
|
+
eval("indent=#{$`.length}",bnd) if setIndent;
|
|
976
|
+
eval('"'+m+'"',bnd)
|
|
977
|
+
}
|
|
978
|
+
end
|
|
979
|
+
rescue => e
|
|
980
|
+
log.error do
|
|
981
|
+
bt=[]
|
|
982
|
+
e.backtrace.each do |bline|
|
|
983
|
+
bt << Logger.formatBacktraceLine(bline);
|
|
984
|
+
break if bline =~ /(.*)rubyLinePP/;
|
|
985
|
+
end
|
|
986
|
+
"error processing line #{lineNum}: #{e}\n\"#{rawLine.chomp}\"\n#{bt.join("\n")}"
|
|
987
|
+
end
|
|
988
|
+
end
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
# This will "preprocess" an entire file using the ruby escape sequence
|
|
992
|
+
# '#{}' for substitutions
|
|
993
|
+
#
|
|
994
|
+
# ffrom = input file path
|
|
995
|
+
# fto = output file path
|
|
996
|
+
# bnd = "binding" to context to evaluate substitutions in
|
|
997
|
+
def rubyPP(ffrom,fto,bnd)
|
|
998
|
+
|
|
999
|
+
begin
|
|
1000
|
+
File.open(fto,'w') do |file|
|
|
1001
|
+
File.open(ffrom,'r') do |fin|
|
|
1002
|
+
rubyLinePP(fin,file,bnd)
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
rescue => e
|
|
1006
|
+
log.error("error precessing: #{ffrom} #{e}")
|
|
1007
|
+
raise e
|
|
1008
|
+
end
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
# Get relative path between path and relto
|
|
1012
|
+
# returns absolute path of path if the roots
|
|
1013
|
+
# are different.
|
|
1014
|
+
def getRelativePath(path,relto=nil)
|
|
1015
|
+
|
|
1016
|
+
relto ||= pwd
|
|
1017
|
+
relto = File.expand_path(relto)
|
|
1018
|
+
path = File.expand_path(path.to_s)
|
|
1019
|
+
if( path =~ /^#{relto}\//)
|
|
1020
|
+
return("./#{$'}")
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
# puts("### #{path} relto #{relto}")
|
|
1024
|
+
|
|
1025
|
+
rtspl = relto.split('/')
|
|
1026
|
+
pspl = path.split('/')
|
|
1027
|
+
pspsz = pspl.size
|
|
1028
|
+
|
|
1029
|
+
cmpi = 0
|
|
1030
|
+
rtspl.each_index do |i|
|
|
1031
|
+
if(i < pspsz)
|
|
1032
|
+
next if rtspl[i] == pspl[i]
|
|
1033
|
+
end
|
|
1034
|
+
cmpi = i;
|
|
1035
|
+
break;
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
# puts(" ##### cmpi #{cmpi}")
|
|
1039
|
+
|
|
1040
|
+
if(cmpi < 1)
|
|
1041
|
+
return('.') if(relto == path)
|
|
1042
|
+
return(path)
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
diff = rtspl.size - cmpi
|
|
1046
|
+
|
|
1047
|
+
# puts(" ##### diff #{diff}")
|
|
1048
|
+
op=[]
|
|
1049
|
+
1.upto(diff) { op << '..' }
|
|
1050
|
+
cmpi.upto(pspsz-1) { |i| op << pspl[i] }
|
|
1051
|
+
op.join('/')
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
# Same as getRelativePath except the returned path uses '\\' instead of '/'
|
|
1055
|
+
# as a path separator
|
|
1056
|
+
def getWindowsRelativePath(path,relto=nil)
|
|
1057
|
+
getRelativePath(path,relto).gsub('/','\\');
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
# return true if host environment is windows or cygwin
|
|
1061
|
+
def hostIsWindows?
|
|
1062
|
+
HostIsWindows_
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
# open and read first line of a file and return it
|
|
1066
|
+
# returns nil if the file is not present.
|
|
1067
|
+
def readOneLineFile(path)
|
|
1068
|
+
line = nil
|
|
1069
|
+
begin
|
|
1070
|
+
File::open(path,'r') do |ifile|
|
|
1071
|
+
line = ifile.readline();
|
|
1072
|
+
line.chomp!()
|
|
1073
|
+
end
|
|
1074
|
+
rescue
|
|
1075
|
+
end
|
|
1076
|
+
line
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
# open and read an entire file into a string
|
|
1080
|
+
# throws excpetion if the file is not present.
|
|
1081
|
+
def readFileToString(path)
|
|
1082
|
+
str = nil
|
|
1083
|
+
File::open(path,'r') do |f|
|
|
1084
|
+
str = f.read();
|
|
1085
|
+
end
|
|
1086
|
+
str
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
if( HostIsWindows_ )
|
|
1090
|
+
if(HostIsCygwin_)
|
|
1091
|
+
@@stderrToNUL = "2>/dev/null"
|
|
1092
|
+
else
|
|
1093
|
+
@@stderrToNUL = "2>NUL:"
|
|
1094
|
+
end
|
|
1095
|
+
else
|
|
1096
|
+
@@stderrToNUL = "2>/dev/null"
|
|
1097
|
+
end
|
|
1098
|
+
|
|
1099
|
+
def textFilesDiffer(a,b)
|
|
1100
|
+
differ = true;
|
|
1101
|
+
|
|
1102
|
+
sh "diff #{@@stderrToNUL} --brief \"#{a}\" \"#{b}\"", :verbose=>false do |ok, res|
|
|
1103
|
+
differ = false if ok
|
|
1104
|
+
end
|
|
1105
|
+
differ
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
private
|
|
1109
|
+
if( HostIsWindows_ )
|
|
1110
|
+
def u2d(file)
|
|
1111
|
+
system "unix2dos \"#{file}\" #{@@stderrToNUL}"
|
|
1112
|
+
end
|
|
1113
|
+
else
|
|
1114
|
+
def u2d(file)
|
|
1115
|
+
system "unix2dos -q \"#{file}\""
|
|
1116
|
+
end
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
public
|
|
1120
|
+
# convert unix EOLs to dos EOLs on a file in place
|
|
1121
|
+
def unix2dos(file)
|
|
1122
|
+
begin
|
|
1123
|
+
u2d(file)
|
|
1124
|
+
rescue => e
|
|
1125
|
+
puts("Warning: #{e}")
|
|
1126
|
+
end
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
# Returns hash containing the difference between a "parent" hash
|
|
1130
|
+
# and an overriding "child" hash
|
|
1131
|
+
def hashDiff(parent,child)
|
|
1132
|
+
dif={}
|
|
1133
|
+
child.defines.each do |k,v|
|
|
1134
|
+
next if(parent.has_key?(k) && (parent[k] == v))
|
|
1135
|
+
dif[k]=v
|
|
1136
|
+
end
|
|
1137
|
+
dif
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
# Prepends a parent path to an array of file names
|
|
1141
|
+
#
|
|
1142
|
+
# returns a FileList containing the joined paths
|
|
1143
|
+
def addPathParent(prefix,files)
|
|
1144
|
+
|
|
1145
|
+
if(prefix =~ /\/\z/)
|
|
1146
|
+
prefix = $`
|
|
1147
|
+
end
|
|
1148
|
+
if(files.instance_of?(String))
|
|
1149
|
+
a = prefix + '/' + files;
|
|
1150
|
+
else
|
|
1151
|
+
a = FileList.new() # can one allocate to files.size?
|
|
1152
|
+
files.each_index { |i|
|
|
1153
|
+
a[i] = prefix + '/' + files[i];
|
|
1154
|
+
}
|
|
1155
|
+
end
|
|
1156
|
+
return(a)
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
if( HostIsWindows_ )
|
|
1160
|
+
@@binPathOpts_ = { :suffi => [ '.exe', '.bat' ] };
|
|
1161
|
+
else
|
|
1162
|
+
@@binPathOpts_ = {};
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
# Find executable in the "bin" search path
|
|
1166
|
+
# return nil if not found.
|
|
1167
|
+
#
|
|
1168
|
+
# currently the search path is set to the value of ENV['PATH']
|
|
1169
|
+
#
|
|
1170
|
+
def self.findInBinPath(name)
|
|
1171
|
+
@@binpath||=SearchPath.new(ENV['PATH']);
|
|
1172
|
+
@@binpath.findFile(name,@@binPathOpts_);
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
# Create a single simple file task to process source to dest
|
|
1176
|
+
#
|
|
1177
|
+
# if &block is not given, then a simple copy action
|
|
1178
|
+
# do |t| { FileUtils::cp(t.source, t.name) }
|
|
1179
|
+
# is used
|
|
1180
|
+
#
|
|
1181
|
+
# <b>named arguments:</b>
|
|
1182
|
+
# :config => a config object to set on the created task
|
|
1183
|
+
#
|
|
1184
|
+
# returns the task created
|
|
1185
|
+
|
|
1186
|
+
def createFileTask(dest,source,opts={},&block)
|
|
1187
|
+
block = SimpleCopyAction_ unless block_given?
|
|
1188
|
+
dest = File.expand_path(dest.to_s)
|
|
1189
|
+
dir = File.dirname(dest)
|
|
1190
|
+
ensureDirectoryTask(dir)
|
|
1191
|
+
task = file dest=>[source,dir], &block
|
|
1192
|
+
task.sources = task.prerequisites
|
|
1193
|
+
if(dir = opts[:config]) # re-use dir
|
|
1194
|
+
task.config = dir
|
|
1195
|
+
end
|
|
1196
|
+
task
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
# Look up a task in the task table using a leading ':' as
|
|
1200
|
+
# the indicator of an absolute 'path' like 'rake:'
|
|
1201
|
+
def lookupTask(tname)
|
|
1202
|
+
Rake.application.lookup((tname=~/^:/)?"rake#{tname}":tname);
|
|
1203
|
+
end
|
|
1204
|
+
|
|
1205
|
+
# Create a single simple "copy" task to process source file
|
|
1206
|
+
# file of same name in destination directory
|
|
1207
|
+
#
|
|
1208
|
+
# if &block is not given, then a simple copy action
|
|
1209
|
+
# do |t| { cp(t.source, t.name) }
|
|
1210
|
+
# is used
|
|
1211
|
+
#
|
|
1212
|
+
# <b>named arguments:</b>
|
|
1213
|
+
# :config => a config object to set on the created task
|
|
1214
|
+
#
|
|
1215
|
+
# returns the task created
|
|
1216
|
+
|
|
1217
|
+
def createCopyTask(destDir,sourceFile,opts={},&block)
|
|
1218
|
+
createFileTask("#{destDir}/#{File.basename(sourceFile)}",sourceFile,opts,&block)
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
# For all files in files create a file task to process the file from the
|
|
1223
|
+
# source file files[n] to destdir/basename(files[n])
|
|
1224
|
+
#
|
|
1225
|
+
# if &block is not given, then a simple copy task
|
|
1226
|
+
# do |t| { cp t.source t.name }
|
|
1227
|
+
# is used
|
|
1228
|
+
#
|
|
1229
|
+
# <b>named arguments:</b>
|
|
1230
|
+
#
|
|
1231
|
+
# :config => 'config' object to set on the created tasks
|
|
1232
|
+
# :basedir => directory which will be used to truncate the
|
|
1233
|
+
# path of file[n] to get the relative path of the output
|
|
1234
|
+
# file from destdir.
|
|
1235
|
+
# ie: if basedir == "xx/yy" and file[n] == /aa/bb/xx/yy/file.x
|
|
1236
|
+
# then the output file will be 'outdir'+/xx/yy/file.x
|
|
1237
|
+
# :preserve if true will not overwrite existing task
|
|
1238
|
+
#
|
|
1239
|
+
# returns an array of all tasks created
|
|
1240
|
+
#
|
|
1241
|
+
|
|
1242
|
+
def createCopyTasks(destdir,*files,&block)
|
|
1243
|
+
|
|
1244
|
+
block = SimpleCopyAction_ unless block_given?
|
|
1245
|
+
opts = (Hash === files.last) ? files.pop : {}
|
|
1246
|
+
preserve = opts[:preserve];
|
|
1247
|
+
|
|
1248
|
+
files = FileSet.new(files); # recursively expand wildcards.
|
|
1249
|
+
|
|
1250
|
+
destdir = File.expand_path(destdir);
|
|
1251
|
+
if(destdir =~ /\/\z/)
|
|
1252
|
+
# too bad rake doesn't check both, it is string based
|
|
1253
|
+
ensureDirectoryTask(destdir)
|
|
1254
|
+
end
|
|
1255
|
+
ensureDirectoryTask(destdir)
|
|
1256
|
+
|
|
1257
|
+
config = opts[:config]
|
|
1258
|
+
if(regx = opts[:basedir])
|
|
1259
|
+
basedir = File.expand_path(regx);
|
|
1260
|
+
if(basedir =~ /\/\z/)
|
|
1261
|
+
basedir = $`
|
|
1262
|
+
end
|
|
1263
|
+
regx = Regexp.new('^' + Regexp.escape(basedir+'/'),Regexp::IGNORECASE);
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
tsk = nil; # declaration only, used below in loop
|
|
1267
|
+
flist=[]
|
|
1268
|
+
files.each do |f| # as not a set, flatten if an array
|
|
1269
|
+
f = f.to_s
|
|
1270
|
+
f = File.expand_path(f)
|
|
1271
|
+
dir = destdir
|
|
1272
|
+
next if(File.directory?(f))
|
|
1273
|
+
if(regx)
|
|
1274
|
+
if(f =~ regx)
|
|
1275
|
+
dir = File.dirname($');
|
|
1276
|
+
if(dir.length == 0 || dir == '.')
|
|
1277
|
+
dir = destdir
|
|
1278
|
+
elsif(destdir.length > 0)
|
|
1279
|
+
dir = "#{destdir}/#{dir}"
|
|
1280
|
+
ensureDirectoryTask(dir)
|
|
1281
|
+
end
|
|
1282
|
+
end
|
|
1283
|
+
end
|
|
1284
|
+
|
|
1285
|
+
destFile = "#{dir}/#{File.basename(f)}"; # name of task
|
|
1286
|
+
if((!preserve) || ((tsk = Rake.application.lookup(destFile)) == nil))
|
|
1287
|
+
tsk = file destFile => [ f, dir ], &block
|
|
1288
|
+
tsk.sources = tsk.prerequisites
|
|
1289
|
+
tsk.config = config if config
|
|
1290
|
+
end
|
|
1291
|
+
flist << tsk # will always be task and not name here
|
|
1292
|
+
end
|
|
1293
|
+
flist
|
|
1294
|
+
end
|
|
1295
|
+
end
|
|
1296
|
+
|
|
1297
|
+
# nothing uses this now - bad idea probably
|
|
1298
|
+
# # include in our own module ( not needed )
|
|
1299
|
+
# # include Rakish::Util
|
|
1300
|
+
#
|
|
1301
|
+
# private
|
|
1302
|
+
# class Utils < Module
|
|
1303
|
+
# include Util
|
|
1304
|
+
# end
|
|
1305
|
+
# @@utils = Utils.new
|
|
1306
|
+
#
|
|
1307
|
+
# public
|
|
1308
|
+
# def self.utils
|
|
1309
|
+
# @@utils
|
|
1310
|
+
# end
|
|
1311
|
+
|
|
1312
|
+
# Generic dynamic propety bag functionality module1
|
|
1313
|
+
# allows 'dot' access to dynamicly set properties.
|
|
1314
|
+
# ie: value = bag.nameOfProperty
|
|
1315
|
+
# bag.nameOfProperty = newValue
|
|
1316
|
+
#
|
|
1317
|
+
# Throws an execption if the property or method is not found on this
|
|
1318
|
+
# node or any of it's parents.
|
|
1319
|
+
#
|
|
1320
|
+
# Assignment to a property that does not exist will add a new field *only* if
|
|
1321
|
+
# done so within an enableNewFields block
|
|
1322
|
+
#
|
|
1323
|
+
# bag.newProperty = "new value" # throws missing method exception
|
|
1324
|
+
# bag.enableNewFields do |s|
|
|
1325
|
+
# s.newProperty = "new value" # OK
|
|
1326
|
+
# end
|
|
1327
|
+
#
|
|
1328
|
+
|
|
1329
|
+
module PropertyBagMod
|
|
1330
|
+
|
|
1331
|
+
# constructor for PropertyBagMod to be called by including classes
|
|
1332
|
+
# This will take an array of parents scanned like a like a path, first hit wins.
|
|
1333
|
+
# by default parents o level above are split into heritable and non-heritable parents
|
|
1334
|
+
# the first parent i the list is considered heritable subsequent parents are in the
|
|
1335
|
+
# search path but are not considerd "heritable" so they will not be fround from
|
|
1336
|
+
# inhering childern.
|
|
1337
|
+
def init_PropertyBag(*args)
|
|
1338
|
+
@_h = (Hash === args.last) ? args.pop : {}
|
|
1339
|
+
allP = [];
|
|
1340
|
+
@parents_ = allP;
|
|
1341
|
+
|
|
1342
|
+
if(args.length > 0)
|
|
1343
|
+
hp = nil;
|
|
1344
|
+
# make parents array the array in the of order of encounter of all unique parents.
|
|
1345
|
+
args.each do |p|
|
|
1346
|
+
if(p)
|
|
1347
|
+
allP << p;
|
|
1348
|
+
php = p.heritableParents
|
|
1349
|
+
hp||=[p,php].flatten;
|
|
1350
|
+
allP << php;
|
|
1351
|
+
else
|
|
1352
|
+
hp||=[]
|
|
1353
|
+
end
|
|
1354
|
+
end
|
|
1355
|
+
@parents_ = allP.flatten.uniq;
|
|
1356
|
+
if( hp.length != @parents_.length)
|
|
1357
|
+
@_hpc_ = hp.length;
|
|
1358
|
+
end
|
|
1359
|
+
end
|
|
1360
|
+
# log.debug("****** parents #{@parents_} allP #{allP}")
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
# get the first parent of this property bag if any
|
|
1364
|
+
def parent
|
|
1365
|
+
(parents.length > 0 ? @parents_[0] : nil);
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1368
|
+
# get the list of ancestors (flattened) in search order.
|
|
1369
|
+
def parents
|
|
1370
|
+
@parents_||=[]
|
|
1371
|
+
end
|
|
1372
|
+
# This will supply inheritable parents to children.
|
|
1373
|
+
#
|
|
1374
|
+
# By default only parents[0] and it's hetitableParents are inheritable by children
|
|
1375
|
+
# added parents resolve in the search only.
|
|
1376
|
+
def heritableParents
|
|
1377
|
+
return parents unless @_hpc_;
|
|
1378
|
+
@parents_.take(@_hpc_)
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
# Enable creation of new fields in a property bag within the supplied block.
|
|
1382
|
+
# may be called recursively
|
|
1383
|
+
|
|
1384
|
+
def enableNewFields(&b)
|
|
1385
|
+
# field creation locked by default, can be recursively "unlocked"
|
|
1386
|
+
# by using reference count
|
|
1387
|
+
@ul_=@ul_ ? @ul_+1:1
|
|
1388
|
+
yield self
|
|
1389
|
+
remove_instance_variable(:@ul_) if((@ul_-=1) < 1)
|
|
1390
|
+
self # return self for convenience
|
|
1391
|
+
end
|
|
1392
|
+
|
|
1393
|
+
# Returns false if outside an enableNewFields block the nesting count if
|
|
1394
|
+
# inside a enebleNewFields block if(newFieldsEnabled?) will test true in this case.
|
|
1395
|
+
def newFieldsEnabled?()
|
|
1396
|
+
@ul_ ? @ul_:false
|
|
1397
|
+
end
|
|
1398
|
+
|
|
1399
|
+
# item from "Module" we want overidable
|
|
1400
|
+
# note name does NOT inherit from parents
|
|
1401
|
+
def name # :nodoc:
|
|
1402
|
+
@_h[:name]
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
# item from "Module" we want overidable
|
|
1406
|
+
# note name does NOT inherit from parents
|
|
1407
|
+
def name=(v) # :nodoc:
|
|
1408
|
+
@_h[:name]=v
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
def self.included(by) # :nodoc:
|
|
1412
|
+
end
|
|
1413
|
+
|
|
1414
|
+
# set or create property irrespective of property (field) creation lock on this object
|
|
1415
|
+
def set(k,v)
|
|
1416
|
+
if self.class.method_defined? k
|
|
1417
|
+
raise PropertyBagMod::cantOverrideX_(k)
|
|
1418
|
+
end
|
|
1419
|
+
@_h[k]=v
|
|
1420
|
+
end
|
|
1421
|
+
|
|
1422
|
+
# Get non-nil value for property 0n any level above, traverse up parent tree via flattened
|
|
1423
|
+
# ancestor list to get first inherited value or nil if not found.
|
|
1424
|
+
# opts - none define at present
|
|
1425
|
+
def getAnyAbove(sym)
|
|
1426
|
+
parents.each do |p|
|
|
1427
|
+
val = p.getMy(sym);
|
|
1428
|
+
return(val) if val;
|
|
1429
|
+
end
|
|
1430
|
+
nil
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1433
|
+
# Get non-nil value for property from heritable parents on any level above,
|
|
1434
|
+
# traverse up parent tree via
|
|
1435
|
+
# ancestor list to get first inherited value or nil if not found.
|
|
1436
|
+
# opts - none defined at present
|
|
1437
|
+
def getInherited(sym)
|
|
1438
|
+
return(getAnyAbove(sym)) unless @_hpc_;
|
|
1439
|
+
pc = @_hpc_;
|
|
1440
|
+
@parents_.each do |p|
|
|
1441
|
+
break if(pc < 1)
|
|
1442
|
+
val = p.getMy(sym);
|
|
1443
|
+
return(val) if val;
|
|
1444
|
+
pc=pc-1;
|
|
1445
|
+
end
|
|
1446
|
+
nil
|
|
1447
|
+
end
|
|
1448
|
+
|
|
1449
|
+
|
|
1450
|
+
# Get value for property, traverse up parent tree to get first inherited
|
|
1451
|
+
# value if not present on this node, returns nil if property not found or
|
|
1452
|
+
# it's value is explicitly set to nil
|
|
1453
|
+
def get(sym)
|
|
1454
|
+
if((v=@_h[sym]).nil?)
|
|
1455
|
+
unless @_h.has_key?(sym)
|
|
1456
|
+
if(self.class.method_defined? sym)
|
|
1457
|
+
v=__send__(sym)
|
|
1458
|
+
elsif(@parents_.length > 0)
|
|
1459
|
+
@parents_.each do |p|
|
|
1460
|
+
val = p.getMy(sym);
|
|
1461
|
+
return(val) if val;
|
|
1462
|
+
end
|
|
1463
|
+
end
|
|
1464
|
+
end
|
|
1465
|
+
end
|
|
1466
|
+
v
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
protected
|
|
1470
|
+
def self.cantOverrideX_(k) # :nodoc:
|
|
1471
|
+
"can't overide method \"#{k}\" with a property"
|
|
1472
|
+
end
|
|
1473
|
+
|
|
1474
|
+
# returns true if any ancestor has a key defined in the hashtable
|
|
1475
|
+
def hasAncestorKey(sym) # :nodoc:
|
|
1476
|
+
@parents_.each do |p|
|
|
1477
|
+
return(true) if p.has_key?(sym);
|
|
1478
|
+
end
|
|
1479
|
+
false
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1482
|
+
def _h # :nodoc: _h accessor
|
|
1483
|
+
@_h
|
|
1484
|
+
end
|
|
1485
|
+
|
|
1486
|
+
def raiseUndef_(sym) # :nodoc:
|
|
1487
|
+
c = caller;
|
|
1488
|
+
caller.each do |clr|
|
|
1489
|
+
c.shift
|
|
1490
|
+
unless(clr =~ /\/Rakish.rb:\d+:in `(method_missing|__send__)'/)
|
|
1491
|
+
# log.debug("\n#{Logger.formatBacktraceLine(clr)} - ##### undefined property or method \"#{sym}\"");
|
|
1492
|
+
raise RuntimeError, "\n#{Logger.formatBacktraceLine(clr)} - undefined property or method \"#{sym}\"", c
|
|
1493
|
+
end
|
|
1494
|
+
end
|
|
1495
|
+
end
|
|
1496
|
+
|
|
1497
|
+
public
|
|
1498
|
+
# Get value for property.
|
|
1499
|
+
# Does *not* traverse up tree, gets local value only.
|
|
1500
|
+
# returns nil if value is either nil or not present
|
|
1501
|
+
def getMy(s)
|
|
1502
|
+
(self.class.method_defined? s) ? self.send(s) : @_h[s]
|
|
1503
|
+
end
|
|
1504
|
+
|
|
1505
|
+
# true if a property is set in hash on this object
|
|
1506
|
+
# does not detect methods
|
|
1507
|
+
def has_key?(k) # :nodoc:
|
|
1508
|
+
@_h.has_key?(k)
|
|
1509
|
+
end
|
|
1510
|
+
|
|
1511
|
+
|
|
1512
|
+
# needed so we can flatten the parents array.
|
|
1513
|
+
def to_ary # :nodoc:
|
|
1514
|
+
nil
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
# allows 'dot' access to properties.
|
|
1518
|
+
# ie: value = bag.nameOfProperty
|
|
1519
|
+
# bag.nameOfProperty = newValue
|
|
1520
|
+
#
|
|
1521
|
+
# Throws an execption if the property or method is not found on this
|
|
1522
|
+
# node or any of it's parents.
|
|
1523
|
+
#
|
|
1524
|
+
# Assignment to a property that does not exist will add a new field *only* if
|
|
1525
|
+
# done so within an enableNewFields block
|
|
1526
|
+
#
|
|
1527
|
+
def method_missing(sym, *args, &block) # :nodoc:
|
|
1528
|
+
|
|
1529
|
+
if((v=@_h[sym]).nil?)
|
|
1530
|
+
unless @_h.has_key?(sym) # if property exists nil is a valid value
|
|
1531
|
+
if sym.to_s =~ /=$/ # it's an attempted asignment ie: ':sym='
|
|
1532
|
+
sym = $`.to_sym # $` has symbol with '=' chopped off
|
|
1533
|
+
unless @ul_ # if not locked check if there is an inherited
|
|
1534
|
+
# property key declared by an ancestor to assign to
|
|
1535
|
+
unless(has_key?(sym))
|
|
1536
|
+
super unless hasAncestorKey(sym); # raise no method exception if no key!
|
|
1537
|
+
end
|
|
1538
|
+
end
|
|
1539
|
+
if(self.class.method_defined? sym)
|
|
1540
|
+
raise PropertyBagMod::cantOverrideX_(sym)
|
|
1541
|
+
end
|
|
1542
|
+
return(@_h[sym]=args[0]) # assign value to property
|
|
1543
|
+
elsif(@parents_.length > 0) # "recurse" to parents
|
|
1544
|
+
# we don't actually recurse here but check the flattened parent list in order
|
|
1545
|
+
eqSym = "#{sym}=".to_sym;
|
|
1546
|
+
anyDefined = self.class.method_defined?(eqSym);
|
|
1547
|
+
@parents_.each do |p|
|
|
1548
|
+
return(p.send(sym)) if(p.class.method_defined? sym);
|
|
1549
|
+
v = p._h[sym];
|
|
1550
|
+
return(v) if (v || p._h.has_key?(sym));
|
|
1551
|
+
anyDefined||=p.class.method_defined?(eqSym);
|
|
1552
|
+
end
|
|
1553
|
+
return v if(anyDefined);
|
|
1554
|
+
raiseUndef_(sym)
|
|
1555
|
+
else
|
|
1556
|
+
return v if (self.class.method_defined?("#{sym}="));
|
|
1557
|
+
raiseUndef_ sym;
|
|
1558
|
+
end
|
|
1559
|
+
end
|
|
1560
|
+
end
|
|
1561
|
+
v
|
|
1562
|
+
end
|
|
1563
|
+
end
|
|
1564
|
+
|
|
1565
|
+
# General purpose property bag class includes PropertyBagMod
|
|
1566
|
+
class PropertyBag < Module
|
|
1567
|
+
include PropertyBagMod
|
|
1568
|
+
|
|
1569
|
+
def initialize(*args,&block)
|
|
1570
|
+
init_PropertyBag(*args)
|
|
1571
|
+
enableNewFields(&block) if(block_given?)
|
|
1572
|
+
end
|
|
1573
|
+
end
|
|
1574
|
+
|
|
1575
|
+
# A case independent set for file paths
|
|
1576
|
+
# intended to act like a Ruby class Set for File path names
|
|
1577
|
+
class FileSet < Module
|
|
1578
|
+
|
|
1579
|
+
# Create a FileSet containing an initial set of files
|
|
1580
|
+
# contained in 'files'. It will acccept 'wildcard'
|
|
1581
|
+
# entries as defined for a Rake::FileList which are expanded
|
|
1582
|
+
# relative to the current directory at the time entries are added
|
|
1583
|
+
|
|
1584
|
+
def initialize(*files)
|
|
1585
|
+
@h={}
|
|
1586
|
+
add_ary(files) unless(files.empty?)
|
|
1587
|
+
end
|
|
1588
|
+
|
|
1589
|
+
# Case independent string key. WARNING does not clone and intern keys
|
|
1590
|
+
# so the source strings must not be changed after being set.
|
|
1591
|
+
class Key # :nodoc:
|
|
1592
|
+
def initialize(str)
|
|
1593
|
+
@s=str.to_s
|
|
1594
|
+
@h=@s.downcase.hash
|
|
1595
|
+
end
|
|
1596
|
+
def hash
|
|
1597
|
+
@h
|
|
1598
|
+
end
|
|
1599
|
+
def eql?(o)
|
|
1600
|
+
@s.casecmp(o)==0
|
|
1601
|
+
end
|
|
1602
|
+
def to_s
|
|
1603
|
+
@s
|
|
1604
|
+
end
|
|
1605
|
+
alias :to_str :to_s
|
|
1606
|
+
end
|
|
1607
|
+
|
|
1608
|
+
protected
|
|
1609
|
+
def add_ary(files,v=nil) # :nodoc:
|
|
1610
|
+
files.each do |f|
|
|
1611
|
+
if(f.respond_to?(:to_ary))
|
|
1612
|
+
add_ary(f) # recurse
|
|
1613
|
+
next
|
|
1614
|
+
end
|
|
1615
|
+
f = f.to_s # :nodoc:
|
|
1616
|
+
unless(f =~ /[*?]/) # unless a glob?
|
|
1617
|
+
f = File.expand_path(f)
|
|
1618
|
+
f = Key.new(f)
|
|
1619
|
+
@ordered << f if @h[f]
|
|
1620
|
+
@h[f]=v
|
|
1621
|
+
else
|
|
1622
|
+
add_ary(FileList.new(File.expand_path(f)))
|
|
1623
|
+
end
|
|
1624
|
+
end
|
|
1625
|
+
end
|
|
1626
|
+
def delete_a(f) # :nodoc:
|
|
1627
|
+
if(f.respond_to?(:to_ary))
|
|
1628
|
+
f.each do |x| delete_a(x) end
|
|
1629
|
+
else
|
|
1630
|
+
@h.delete(Key.new(f))
|
|
1631
|
+
end
|
|
1632
|
+
end
|
|
1633
|
+
|
|
1634
|
+
public
|
|
1635
|
+
# Add files contained in 'files' to this set. It will acccept 'wildcard'
|
|
1636
|
+
# entries which are expanded relative to the current directory.
|
|
1637
|
+
# relative to the current directory at the time entries are added
|
|
1638
|
+
def include(*files)
|
|
1639
|
+
add_ary(files)
|
|
1640
|
+
end
|
|
1641
|
+
|
|
1642
|
+
# Add a single file path to this set if it is not present.
|
|
1643
|
+
#
|
|
1644
|
+
# returns true if the path was not previously in the set, false otherwise
|
|
1645
|
+
# note does NOT expand the path when inserted
|
|
1646
|
+
def add?(f)
|
|
1647
|
+
f = Key.new(f)
|
|
1648
|
+
return false if @h[f]
|
|
1649
|
+
@ordered << f if @ordered
|
|
1650
|
+
@h[f]=nil
|
|
1651
|
+
true
|
|
1652
|
+
end
|
|
1653
|
+
# Add a single file path to this set
|
|
1654
|
+
# note does NOT expand the path when inserted
|
|
1655
|
+
# returns self for convenience
|
|
1656
|
+
def add(f)
|
|
1657
|
+
add?(f);
|
|
1658
|
+
self
|
|
1659
|
+
end
|
|
1660
|
+
alias :<< :add
|
|
1661
|
+
|
|
1662
|
+
# Remove path or paths from this set if they are present
|
|
1663
|
+
# It does not accept wildcards, but will accept FileLists
|
|
1664
|
+
def delete(*args)
|
|
1665
|
+
delete_a(args)
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
# Returns true if the path is in this set
|
|
1669
|
+
# false otherwise.
|
|
1670
|
+
def include?(f)
|
|
1671
|
+
@h.has_key?(Key.new(f))
|
|
1672
|
+
end
|
|
1673
|
+
|
|
1674
|
+
# Returns true if this set is empty
|
|
1675
|
+
def empty?
|
|
1676
|
+
@h.empty?
|
|
1677
|
+
end
|
|
1678
|
+
|
|
1679
|
+
# Iterates over each path in the set
|
|
1680
|
+
def each(&b) # :yields: path
|
|
1681
|
+
@h.each do |k,v|
|
|
1682
|
+
yield(k.to_s)
|
|
1683
|
+
end
|
|
1684
|
+
end
|
|
1685
|
+
|
|
1686
|
+
# Like array.join, joins all paths with separator
|
|
1687
|
+
def join(separator)
|
|
1688
|
+
out = nil;
|
|
1689
|
+
each do |p|
|
|
1690
|
+
if out
|
|
1691
|
+
out += separator; # TODO: not too efficient - memory thrashing
|
|
1692
|
+
out += p;
|
|
1693
|
+
else
|
|
1694
|
+
out = p;
|
|
1695
|
+
end
|
|
1696
|
+
end
|
|
1697
|
+
out||'';
|
|
1698
|
+
end
|
|
1699
|
+
|
|
1700
|
+
# Returns then number of entries in this set
|
|
1701
|
+
def size
|
|
1702
|
+
@h.size
|
|
1703
|
+
end
|
|
1704
|
+
# Returns an array of all path entries in this set
|
|
1705
|
+
def to_ary
|
|
1706
|
+
@h.keys
|
|
1707
|
+
end
|
|
1708
|
+
end
|
|
1709
|
+
|
|
1710
|
+
# A FileSet where the order entries are installed is preserved
|
|
1711
|
+
class OrderedFileSet < FileSet
|
|
1712
|
+
def initialize
|
|
1713
|
+
super
|
|
1714
|
+
@ordered=[]
|
|
1715
|
+
end
|
|
1716
|
+
alias :add :add?
|
|
1717
|
+
alias :<< :add?
|
|
1718
|
+
|
|
1719
|
+
# Iterates over each path (key) in the set
|
|
1720
|
+
# in the order added
|
|
1721
|
+
def each(&b) # :yields: path
|
|
1722
|
+
@ordered.each do |k|
|
|
1723
|
+
yield(k.to_s) unless k.nil?
|
|
1724
|
+
end
|
|
1725
|
+
end
|
|
1726
|
+
# Returns then number of entries in this set
|
|
1727
|
+
def size
|
|
1728
|
+
@h.size
|
|
1729
|
+
end
|
|
1730
|
+
# Returns an array of all path entries in this set
|
|
1731
|
+
# in the order added
|
|
1732
|
+
def to_ary
|
|
1733
|
+
@ordered
|
|
1734
|
+
end
|
|
1735
|
+
|
|
1736
|
+
def join # :nodoc:
|
|
1737
|
+
@ordered.join
|
|
1738
|
+
end
|
|
1739
|
+
|
|
1740
|
+
end
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
# Case independent "path" hash
|
|
1744
|
+
# preserves order of addition
|
|
1745
|
+
class FileHash < FileSet
|
|
1746
|
+
def initialize()
|
|
1747
|
+
super
|
|
1748
|
+
end
|
|
1749
|
+
def addAll
|
|
1750
|
+
|
|
1751
|
+
end
|
|
1752
|
+
def [](k)
|
|
1753
|
+
@h[Key.new(k)]
|
|
1754
|
+
end
|
|
1755
|
+
def []=(k,v)
|
|
1756
|
+
@h[Key.new(k)]=v
|
|
1757
|
+
end
|
|
1758
|
+
|
|
1759
|
+
def each_pair(&b)
|
|
1760
|
+
@h.each_pair do |k,v|
|
|
1761
|
+
yield k,v
|
|
1762
|
+
end
|
|
1763
|
+
end
|
|
1764
|
+
# Returns array of all values in the hash
|
|
1765
|
+
def values
|
|
1766
|
+
@h.values
|
|
1767
|
+
end
|
|
1768
|
+
end
|
|
1769
|
+
|
|
1770
|
+
# A set of "output" directories each assigned a set of source files.
|
|
1771
|
+
# The intention to map a set of input files to a set of output files
|
|
1772
|
+
# in a differing directory structure.
|
|
1773
|
+
class FileCopySet
|
|
1774
|
+
include Util
|
|
1775
|
+
|
|
1776
|
+
private
|
|
1777
|
+
|
|
1778
|
+
def add_set(set) # :nodoc:
|
|
1779
|
+
set.filesByDir do |dir,files|
|
|
1780
|
+
ilist = (@byDir_[dir] ||= [])
|
|
1781
|
+
add_files_a(ilist,files,nil)
|
|
1782
|
+
end
|
|
1783
|
+
end
|
|
1784
|
+
public
|
|
1785
|
+
|
|
1786
|
+
# Create new FileCopySet with optional argument to initialize this set as a
|
|
1787
|
+
# deep copy of another FileCopySet
|
|
1788
|
+
def initialize(cloneFrom=nil)
|
|
1789
|
+
@byDir_=FileHash.new
|
|
1790
|
+
if(cloneFrom && FileCopySet === cloneFrom)
|
|
1791
|
+
add_set(cloneFrom)
|
|
1792
|
+
end
|
|
1793
|
+
end
|
|
1794
|
+
|
|
1795
|
+
def debug=(v) # :nodoc:
|
|
1796
|
+
@debug=v
|
|
1797
|
+
end
|
|
1798
|
+
|
|
1799
|
+
class Entry # :nodoc: all
|
|
1800
|
+
def initialize(f,data=nil)
|
|
1801
|
+
@f=f
|
|
1802
|
+
@data = data unless data.nil?
|
|
1803
|
+
end
|
|
1804
|
+
def to_s
|
|
1805
|
+
@f.to_s
|
|
1806
|
+
end
|
|
1807
|
+
alias :to_str :to_s
|
|
1808
|
+
alias :source :to_s
|
|
1809
|
+
def dest
|
|
1810
|
+
File.basename(@f.to_s)
|
|
1811
|
+
end
|
|
1812
|
+
def data
|
|
1813
|
+
@data
|
|
1814
|
+
end
|
|
1815
|
+
end
|
|
1816
|
+
|
|
1817
|
+
protected
|
|
1818
|
+
|
|
1819
|
+
@@truncLen_ = File.expand_path("/./").length;
|
|
1820
|
+
|
|
1821
|
+
# Cleans up a relative path 'rp' without expanding against the current directory
|
|
1822
|
+
# ie:
|
|
1823
|
+
# ./a/b/c/../../ => ./a
|
|
1824
|
+
# ./ => .
|
|
1825
|
+
#
|
|
1826
|
+
# NOTE: this will not work if the relative path evaluates to below itself
|
|
1827
|
+
# which is improper for a destination directory
|
|
1828
|
+
#
|
|
1829
|
+
def cleanupDestdir(dd) # :nodoc:
|
|
1830
|
+
dd=dd.to_s;
|
|
1831
|
+
unless(File.path_is_absolute?(dd))
|
|
1832
|
+
dd = File.expand_path("/./#{dd}");
|
|
1833
|
+
dd = "./#{dd[@@truncLen_,10000]}";
|
|
1834
|
+
dd='.' if(dd=='./')
|
|
1835
|
+
end
|
|
1836
|
+
dd
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
def add_simple_a(list,files,data) # :nodoc:
|
|
1840
|
+
files.each do |f|
|
|
1841
|
+
list << Entry.new(File.expand_path(f.to_s),data)
|
|
1842
|
+
end
|
|
1843
|
+
end
|
|
1844
|
+
def add_files_a(list,files,data) # :nodoc:
|
|
1845
|
+
files.each do |f|
|
|
1846
|
+
if(f.respond_to?(:to_ary))
|
|
1847
|
+
add_files_a(list,f,data)
|
|
1848
|
+
next
|
|
1849
|
+
end
|
|
1850
|
+
if(f =~ /[*?]/)
|
|
1851
|
+
add_simple_a(list,FileList.new(f),data)
|
|
1852
|
+
next
|
|
1853
|
+
end
|
|
1854
|
+
list << Entry.new(File.expand_path(f.to_s),data)
|
|
1855
|
+
end
|
|
1856
|
+
end
|
|
1857
|
+
|
|
1858
|
+
public
|
|
1859
|
+
# Add a directory (in destination) with no source files to this set, if not already there.
|
|
1860
|
+
# dir = './set/dir' or '.' for the root of a relative destination
|
|
1861
|
+
def addDir(dir)
|
|
1862
|
+
@byDir_[cleanupDestdir(dir)]||=[]
|
|
1863
|
+
end
|
|
1864
|
+
|
|
1865
|
+
# add files all assigned to the destdir directory
|
|
1866
|
+
def addFiles(destdir, *files)
|
|
1867
|
+
if(!files.empty?)
|
|
1868
|
+
ilist = (@byDir_[cleanupDestdir(destdir)] ||= [])
|
|
1869
|
+
add_files_a(ilist,files,nil)
|
|
1870
|
+
end
|
|
1871
|
+
end
|
|
1872
|
+
protected
|
|
1873
|
+
|
|
1874
|
+
def add_filet_a(destdir,regx,files,data) # :nodoc:
|
|
1875
|
+
files.each do |f|
|
|
1876
|
+
if(f.respond_to?(:to_ary))
|
|
1877
|
+
add_filet_a(destdir,regx,f,data)
|
|
1878
|
+
next
|
|
1879
|
+
end
|
|
1880
|
+
if(f =~ /[*?]/)
|
|
1881
|
+
add_filet_a(destdir,regx,FileList.new(f),data)
|
|
1882
|
+
next
|
|
1883
|
+
end
|
|
1884
|
+
f = File.expand_path(f.to_s)
|
|
1885
|
+
isDir = File.directory?(f)
|
|
1886
|
+
f =~ regx
|
|
1887
|
+
if(isDir)
|
|
1888
|
+
dir = ($') ? ((destdir.length > 0) ? "#{destdir}/#{$'}" : $') : destdir
|
|
1889
|
+
@byDir_[dir]||=[]
|
|
1890
|
+
else
|
|
1891
|
+
dir = File.dirname($');
|
|
1892
|
+
if(dir.length == 0 || dir == '.')
|
|
1893
|
+
dir = destdir
|
|
1894
|
+
elsif(destdir.length > 0)
|
|
1895
|
+
dir = "#{destdir}/#{dir}"
|
|
1896
|
+
end
|
|
1897
|
+
(@byDir_[dir]||=[]) << Entry.new(f,data)
|
|
1898
|
+
end
|
|
1899
|
+
end
|
|
1900
|
+
end
|
|
1901
|
+
|
|
1902
|
+
public
|
|
1903
|
+
|
|
1904
|
+
# Adds all the files from a subtree into the destdir in the set
|
|
1905
|
+
# the subtree will have it's leading "basedir" removed from the file path
|
|
1906
|
+
# and replaced with the "basedir" before adding to the archive.
|
|
1907
|
+
# ie:
|
|
1908
|
+
# file = '/a/b/c/d/e/file.txt'
|
|
1909
|
+
# basedir = '/a/b/c'
|
|
1910
|
+
# destdir = './set/dir' or '.' for the root of a relative destination
|
|
1911
|
+
#
|
|
1912
|
+
# added to set = 'set/dir/d/e/file.txt'
|
|
1913
|
+
#
|
|
1914
|
+
# <b>named options:</b>
|
|
1915
|
+
# :data => user value to assign to all entries added to this set
|
|
1916
|
+
#
|
|
1917
|
+
def addFileTree(destdir, basedir, *files)
|
|
1918
|
+
opts = (Hash === files.last) ? files.pop : {}
|
|
1919
|
+
destdir = cleanupDestdir(destdir);
|
|
1920
|
+
basedir = File.expand_path(basedir)
|
|
1921
|
+
regx = Regexp.new('^' + Regexp.escape(basedir+'/'),Regexp::IGNORECASE);
|
|
1922
|
+
add_filet_a(destdir,regx,files,opts[:data])
|
|
1923
|
+
end
|
|
1924
|
+
|
|
1925
|
+
# Retrieve all source files by assigned output directory
|
|
1926
|
+
# one source file may be assigned to more than one output directory
|
|
1927
|
+
#
|
|
1928
|
+
def filesByDir(&block) # :yields: directory, iterable of files
|
|
1929
|
+
@byDir_.each_pair do |k,v|
|
|
1930
|
+
yield(k.to_s,v)
|
|
1931
|
+
end
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
# Return array of all source files in this set
|
|
1935
|
+
def sources
|
|
1936
|
+
v = @byDir_.values.flatten;
|
|
1937
|
+
v.uniq!
|
|
1938
|
+
v
|
|
1939
|
+
end
|
|
1940
|
+
|
|
1941
|
+
def prettyPrint
|
|
1942
|
+
filesByDir do |k,v|
|
|
1943
|
+
if(v.length > 0)
|
|
1944
|
+
puts("\n");
|
|
1945
|
+
end
|
|
1946
|
+
puts("directory #{k}");
|
|
1947
|
+
v.each do |f|
|
|
1948
|
+
puts( " \"#{f}\"")
|
|
1949
|
+
end
|
|
1950
|
+
end
|
|
1951
|
+
end
|
|
1952
|
+
|
|
1953
|
+
# Generate processing tasks for all files in this copy set
|
|
1954
|
+
# using the task action provided or a simple copy if not
|
|
1955
|
+
# hash args
|
|
1956
|
+
# :suffixMap - map from source suffi to destination suffi
|
|
1957
|
+
# :config - value to set for task.config
|
|
1958
|
+
# TODO:ensureOutputDirs - if true ensure a task is present for creating
|
|
1959
|
+
# the output directory and assign it as prerequisite
|
|
1960
|
+
# default is true
|
|
1961
|
+
# TODO: :outputDir value of directory to place output files
|
|
1962
|
+
|
|
1963
|
+
def generateFileTasks(args={}, &block)
|
|
1964
|
+
|
|
1965
|
+
ensureOutputDirs = args[:ensureOutputDirs];
|
|
1966
|
+
suffixMap = args[:suffixMap]||{};
|
|
1967
|
+
tasks = [];
|
|
1968
|
+
block = SimpleCopyAction_ unless block_given?
|
|
1969
|
+
|
|
1970
|
+
filesByDir do |dir,files|
|
|
1971
|
+
# TODO: maybe have an output directory option and maybe relative path option for destinations ?
|
|
1972
|
+
# dir = File.join(destDir,dir);
|
|
1973
|
+
ensureDirectoryTask(dir)
|
|
1974
|
+
|
|
1975
|
+
files.each do |srcfile|
|
|
1976
|
+
destname = File.basename(srcfile);
|
|
1977
|
+
oldext = File.extname(destname);
|
|
1978
|
+
if(oldext)
|
|
1979
|
+
newext = suffixMap[oldext];
|
|
1980
|
+
destname = destname.pathmap("%n#{newext}") if newext
|
|
1981
|
+
end
|
|
1982
|
+
dest = File.join(dir, destname);
|
|
1983
|
+
task = file dest=>[srcfile,dir], &block
|
|
1984
|
+
task.sources = task.prerequisites
|
|
1985
|
+
# set configuration data on task if desired
|
|
1986
|
+
if(cfg = args[:config])
|
|
1987
|
+
task.config = cfg
|
|
1988
|
+
end
|
|
1989
|
+
tasks << task
|
|
1990
|
+
end
|
|
1991
|
+
end
|
|
1992
|
+
tasks
|
|
1993
|
+
end
|
|
1994
|
+
|
|
1995
|
+
end
|
|
1996
|
+
|
|
1997
|
+
# not used yet intending to use it for MultiTask queueing
|
|
1998
|
+
class CountingSemaphore
|
|
1999
|
+
def initialize(initvalue = 0)
|
|
2000
|
+
@counter = initvalue
|
|
2001
|
+
@waiting_list = []
|
|
2002
|
+
end
|
|
2003
|
+
|
|
2004
|
+
def wait
|
|
2005
|
+
Thread.critical = true
|
|
2006
|
+
if (@counter -= 1) < 0
|
|
2007
|
+
@waiting_list.push(Thread.current)
|
|
2008
|
+
Thread.stop
|
|
2009
|
+
end
|
|
2010
|
+
self
|
|
2011
|
+
ensure
|
|
2012
|
+
Thread.critical = false
|
|
2013
|
+
end
|
|
2014
|
+
|
|
2015
|
+
def signal
|
|
2016
|
+
Thread.critical = true
|
|
2017
|
+
begin
|
|
2018
|
+
if (@counter += 1) <= 0
|
|
2019
|
+
t = @waiting_list.shift
|
|
2020
|
+
t.wakeup if t
|
|
2021
|
+
end
|
|
2022
|
+
rescue ThreadError
|
|
2023
|
+
retry
|
|
2024
|
+
end
|
|
2025
|
+
self
|
|
2026
|
+
ensure
|
|
2027
|
+
Thread.critical = false
|
|
2028
|
+
end
|
|
2029
|
+
|
|
2030
|
+
alias down wait
|
|
2031
|
+
alias up signal
|
|
2032
|
+
alias P wait
|
|
2033
|
+
alias V signal
|
|
2034
|
+
|
|
2035
|
+
def exclusive
|
|
2036
|
+
wait
|
|
2037
|
+
yield
|
|
2038
|
+
ensure
|
|
2039
|
+
signal
|
|
2040
|
+
end
|
|
2041
|
+
|
|
2042
|
+
alias synchronize exclusive
|
|
2043
|
+
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2046
|
+
# :nodoc: not used curently
|
|
2047
|
+
# Semaphore = CountingSemaphore
|
|
2048
|
+
|
|
2049
|
+
end
|