pwrake 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +30 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +57 -0
- data/Rakefile +1 -0
- data/bin/pwrake +36 -0
- data/lib/pwrake/application.rb +187 -0
- data/lib/pwrake/counter.rb +54 -0
- data/lib/pwrake/file_utils.rb +70 -0
- data/lib/pwrake/gfarm_feature.rb +229 -0
- data/lib/pwrake/graphviz.rb +113 -0
- data/lib/pwrake/locality_aware_queue.rb +254 -0
- data/lib/pwrake/logger.rb +153 -0
- data/lib/pwrake/master.rb +109 -0
- data/lib/pwrake/option.rb +367 -0
- data/lib/pwrake/profiler.rb +88 -0
- data/lib/pwrake/rake_modify.rb +14 -0
- data/lib/pwrake/shell.rb +151 -0
- data/lib/pwrake/task_algorithm.rb +171 -0
- data/lib/pwrake/task_queue.rb +167 -0
- data/lib/pwrake/timer.rb +22 -0
- data/lib/pwrake/version.rb +3 -0
- data/lib/pwrake.rb +18 -0
- data/pwrake.gemspec +19 -0
- data/setup.rb +1585 -0
- data/spec/001/Rakefile +5 -0
- data/spec/002/Rakefile +19 -0
- data/spec/003/Rakefile +9 -0
- data/spec/004/Rakefile +7 -0
- data/spec/005/Rakefile +11 -0
- data/spec/006/Rakefile +3 -0
- data/spec/006/pwrake_conf.yaml +3 -0
- data/spec/007/Rakefile +22 -0
- data/spec/008/Rakefile +3 -0
- data/spec/008/pwrake_conf.yaml +3 -0
- data/spec/009/Rakefile +18 -0
- data/spec/009/pwrake_conf.yaml +2 -0
- data/spec/helper.rb +82 -0
- data/spec/hosts +3 -0
- data/spec/pwrake_spec.rb +83 -0
- metadata +119 -0
@@ -0,0 +1,367 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
START_TIME = Time.now
|
4
|
+
|
5
|
+
module Option
|
6
|
+
|
7
|
+
DEFAULT_CONFFILES = ["pwrake_conf.yaml","PwrakeConf.yaml"]
|
8
|
+
|
9
|
+
def option_data
|
10
|
+
[
|
11
|
+
'DRYRUN',
|
12
|
+
'IGNORE_SYSTEM',
|
13
|
+
'IGNORE_DEPRECATE',
|
14
|
+
'LOAD_SYSTEM',
|
15
|
+
'NOSEARCH',
|
16
|
+
'RAKELIB',
|
17
|
+
'SHOW_PREREQS',
|
18
|
+
'SILENT',
|
19
|
+
'TRACE',
|
20
|
+
'TRACE_RULES',
|
21
|
+
|
22
|
+
'FILESYSTEM',
|
23
|
+
'SSH_OPTION',
|
24
|
+
'PASS_ENV',
|
25
|
+
'GNU_TIME',
|
26
|
+
'HALT_QUEUE_WHILE_SEARCH',
|
27
|
+
'SHOW_CONF',
|
28
|
+
|
29
|
+
['HOSTFILE','HOSTS'],
|
30
|
+
['LOGFILE','LOG',
|
31
|
+
proc{|v|
|
32
|
+
if v
|
33
|
+
# turn trace option on
|
34
|
+
Rake.application.options.trace = true
|
35
|
+
if v == "" || !v.kind_of?(String)
|
36
|
+
v = "Pwrake%Y%m%d-%H%M%S_%$.log"
|
37
|
+
end
|
38
|
+
START_TIME.strftime(v).sub("%$",Process.pid.to_s)
|
39
|
+
end
|
40
|
+
}],
|
41
|
+
['PROFILE',
|
42
|
+
proc{|v|
|
43
|
+
if v
|
44
|
+
if v == "" || !v.kind_of?(String)
|
45
|
+
v = "Pwrake%Y%m%d-%H%M%S_%$.csv"
|
46
|
+
end
|
47
|
+
START_TIME.strftime(v).sub("%$",Process.pid.to_s)
|
48
|
+
end
|
49
|
+
}],
|
50
|
+
['NUM_THREADS', proc{|v| v && v.to_i}],
|
51
|
+
['DISABLE_AFFINITY', proc{|v| v || ENV['AFFINITY']=='off'}],
|
52
|
+
['GFARM_BASEDIR', proc{|v| v || '/tmp'}],
|
53
|
+
['GFARM_PREFIX', proc{|v| v || "pwrake_#{ENV['USER']}"}],
|
54
|
+
['GFARM_SUBDIR', proc{|v| v || '/'}],
|
55
|
+
['MASTER_HOSTNAME', proc{|v| v || `hostname -f`.chomp}],
|
56
|
+
['WORK_DIR',proc{|v|
|
57
|
+
v ||= '$HOME/%CWD_RELATIVE_TO_HOME'
|
58
|
+
v.sub('%CWD_RELATIVE_TO_HOME',cwd_relative_to_home)
|
59
|
+
}]
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# ----- init -----
|
65
|
+
|
66
|
+
def init_option
|
67
|
+
@host_group = []
|
68
|
+
init_options
|
69
|
+
init_pass_env
|
70
|
+
init_logger
|
71
|
+
if @opts['SHOW_CONF']
|
72
|
+
require "yaml"
|
73
|
+
YAML.dump(@opts,$stdout)
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
@counter = Counter.new
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_reader :core_list
|
80
|
+
attr_reader :counter
|
81
|
+
attr_reader :logfile
|
82
|
+
attr_reader :queue_class
|
83
|
+
attr_reader :shell_class
|
84
|
+
|
85
|
+
|
86
|
+
def pwrake_options
|
87
|
+
@opts
|
88
|
+
end
|
89
|
+
|
90
|
+
def init_options
|
91
|
+
# Read pwrake_conf
|
92
|
+
@pwrake_conf = Rake.application.options.pwrake_conf
|
93
|
+
|
94
|
+
if @pwrake_conf
|
95
|
+
if !File.exist?(@pwrake_conf)
|
96
|
+
raise "Configuration file not found: #{@pwrake_conf}"
|
97
|
+
end
|
98
|
+
else
|
99
|
+
@pwrake_conf = DEFAULT_CONFFILES.find{|fn| File.exist?(fn)}
|
100
|
+
end
|
101
|
+
|
102
|
+
if @pwrake_conf.nil?
|
103
|
+
@yaml = {}
|
104
|
+
else
|
105
|
+
Log.debug "@pwrake_conf=#{@pwrake_conf}"
|
106
|
+
require "yaml"
|
107
|
+
@yaml = open(@pwrake_conf){|f| YAML.load(f) }
|
108
|
+
end
|
109
|
+
|
110
|
+
@opts = {'PWRAKE_CONF' => @pwrake_conf}
|
111
|
+
|
112
|
+
option_data.each do |a|
|
113
|
+
prc = nil
|
114
|
+
keys = []
|
115
|
+
case a
|
116
|
+
when String
|
117
|
+
keys << a
|
118
|
+
when Array
|
119
|
+
a.each do |x|
|
120
|
+
case x
|
121
|
+
when String
|
122
|
+
keys << x
|
123
|
+
when Proc
|
124
|
+
prc = x
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
key = keys[0]
|
129
|
+
val = search_opts(keys)
|
130
|
+
val = prc.call(val) if prc
|
131
|
+
@opts[key] = val if !val.nil?
|
132
|
+
instance_variable_set("@"+key.downcase, val)
|
133
|
+
end
|
134
|
+
|
135
|
+
feedback_options [
|
136
|
+
'DRYRUN',
|
137
|
+
'IGNORE_SYSTEM',
|
138
|
+
'IGNORE_DEPRECATE',
|
139
|
+
'LOAD_SYSTEM',
|
140
|
+
'NOSEARCH',
|
141
|
+
'RAKELIB',
|
142
|
+
'SHOW_PREREQS',
|
143
|
+
'SILENT',
|
144
|
+
'TRACE',
|
145
|
+
'TRACE_RULES']
|
146
|
+
Rake.verbose(true) if Rake.application.options.trace
|
147
|
+
Rake.verbose(false) if Rake.application.options.silent
|
148
|
+
end
|
149
|
+
|
150
|
+
def feedback_options(a)
|
151
|
+
a.each do |k|
|
152
|
+
if v=@opts[k]
|
153
|
+
m = (k.downcase+"=").to_sym
|
154
|
+
Rake.application.options.send(m,v)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Option order:
|
160
|
+
# command_option > ENV > pwrake_conf > DEFAULT_OPTIONS
|
161
|
+
def search_opts(keys)
|
162
|
+
val = Rake.application.options.send(keys[0].downcase.to_sym)
|
163
|
+
return val if !val.nil?
|
164
|
+
#
|
165
|
+
keys.each do |k|
|
166
|
+
val = ENV[k.upcase]
|
167
|
+
return val if !val.nil?
|
168
|
+
end
|
169
|
+
#
|
170
|
+
return nil if !@yaml
|
171
|
+
keys.each do |k|
|
172
|
+
val = @yaml[k.upcase]
|
173
|
+
return val if !val.nil?
|
174
|
+
end
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
|
178
|
+
def cwd_relative_to_home
|
179
|
+
Pathname.pwd.relative_path_from(Pathname.new(ENV['HOME'])).to_s
|
180
|
+
end
|
181
|
+
|
182
|
+
def cwd_relative_if_under_home
|
183
|
+
home = Pathname.new(ENV['HOME']).realpath
|
184
|
+
path = pwd = Pathname.pwd.realpath
|
185
|
+
while path != home
|
186
|
+
if path.root?
|
187
|
+
return pwd.to_s
|
188
|
+
end
|
189
|
+
path = path.parent
|
190
|
+
end
|
191
|
+
return pwd.relative_path_from(home).to_s
|
192
|
+
end
|
193
|
+
|
194
|
+
def init_pass_env
|
195
|
+
if envs = @opts['PASS_ENV']
|
196
|
+
pass_env = {}
|
197
|
+
|
198
|
+
case envs
|
199
|
+
when Array
|
200
|
+
envs.each do |k|
|
201
|
+
k = k.to_s
|
202
|
+
if v = ENV[k]
|
203
|
+
pass_env[k] = v
|
204
|
+
end
|
205
|
+
end
|
206
|
+
when Hash
|
207
|
+
envs.each do |k,v|
|
208
|
+
k = k.to_s
|
209
|
+
if v = ENV[k] || v
|
210
|
+
pass_env[k] = v
|
211
|
+
end
|
212
|
+
end
|
213
|
+
else
|
214
|
+
raise "invalid option for PASS_ENV in pwrake_conf.yaml"
|
215
|
+
end
|
216
|
+
|
217
|
+
if pass_env.empty?
|
218
|
+
@opts.delete('PASS_ENV')
|
219
|
+
else
|
220
|
+
@opts['PASS_ENV'] = pass_env
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def init_logger
|
226
|
+
if Rake.application.options.debug
|
227
|
+
Log.level = Log::DEBUG
|
228
|
+
elsif Rake.verbose.kind_of? TrueClass
|
229
|
+
Log.level = Log::INFO
|
230
|
+
else
|
231
|
+
Log.level = Log::WARN
|
232
|
+
end
|
233
|
+
|
234
|
+
if @logfile
|
235
|
+
logdir = File.dirname(@logfile)
|
236
|
+
if !File.directory?(logdir)
|
237
|
+
mkdir_p logdir
|
238
|
+
end
|
239
|
+
Log.open(@logfile)
|
240
|
+
# turn trace option on
|
241
|
+
#Rake.application.options.trace = true
|
242
|
+
else
|
243
|
+
Log.open($stdout)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# ----- setup -----
|
248
|
+
|
249
|
+
def setup_option
|
250
|
+
set_hosts
|
251
|
+
set_filesystem
|
252
|
+
end
|
253
|
+
|
254
|
+
def set_hosts
|
255
|
+
if @hostfile && @num_threads
|
256
|
+
raise "Cannot set `hostfile' and `num_threads' simultaneously"
|
257
|
+
end
|
258
|
+
if @hostfile
|
259
|
+
require "socket"
|
260
|
+
tmplist = []
|
261
|
+
File.open(@hostfile) do |f|
|
262
|
+
while l = f.gets
|
263
|
+
l = $1 if /^([^#]*)#/ =~ l
|
264
|
+
host, ncore, group = l.split
|
265
|
+
if host
|
266
|
+
begin
|
267
|
+
host = Socket.gethostbyname(host)[0]
|
268
|
+
rescue
|
269
|
+
Log.info "FQDN not resoved : #{host}"
|
270
|
+
end
|
271
|
+
ncore = (ncore || 1).to_i
|
272
|
+
group = (group || 0).to_i
|
273
|
+
tmplist << ([host] * ncore.to_i)
|
274
|
+
@host_group[group] ||= []
|
275
|
+
@host_group[group] << host
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
#
|
280
|
+
@core_list = []
|
281
|
+
begin # alternative order
|
282
|
+
sz = 0
|
283
|
+
tmplist.each do |a|
|
284
|
+
@core_list << a.shift if !a.empty?
|
285
|
+
sz += a.size
|
286
|
+
end
|
287
|
+
end while sz>0
|
288
|
+
@num_threads = @core_list.size
|
289
|
+
else
|
290
|
+
@num_threads = 1 if !@num_threads
|
291
|
+
@core_list = ['localhost'] * @num_threads
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
def set_filesystem
|
297
|
+
if fn = @opts["PROFILE"]
|
298
|
+
Shell.profiler.open(fn,@opts['GNU_TIME'])
|
299
|
+
end
|
300
|
+
|
301
|
+
@shell_opt = {
|
302
|
+
:work_dir => @opts['WORK_DIR'],
|
303
|
+
:pass_env => @opts['PASS_ENV'],
|
304
|
+
:ssh_opt => @opts['SSH_OPTION']
|
305
|
+
}
|
306
|
+
|
307
|
+
if @filesystem.nil?
|
308
|
+
case mount_type
|
309
|
+
when /gfarm2fs/
|
310
|
+
@opts['FILESYSTEM'] = @filesystem = 'gfarm'
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
case @filesystem
|
315
|
+
when 'gfarm'
|
316
|
+
require "pwrake/locality_aware_queue"
|
317
|
+
require "pwrake/gfarm_feature"
|
318
|
+
GfarmPath.subdir = @opts['GFARM_SUBDIR']
|
319
|
+
@filesystem = 'gfarm'
|
320
|
+
@shell_class = GfarmShell
|
321
|
+
@shell_opt.merge!({
|
322
|
+
:work_dir => Dir.pwd,
|
323
|
+
:disable_steal => @opts['DISABLE_STEAL'],
|
324
|
+
:single_mp => @opts['GFARM_SINGLE_MP'],
|
325
|
+
:basedir => @opts['GFARM_BASEDIR'],
|
326
|
+
:prefix => @opts['GFARM_PREFIX']
|
327
|
+
})
|
328
|
+
@queue_class = GfarmQueue
|
329
|
+
# @queue_class = TaskQueue
|
330
|
+
else
|
331
|
+
@filesystem = 'nfs'
|
332
|
+
@shell_class = Shell
|
333
|
+
@queue_class = TaskQueue
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def mount_type(d=nil)
|
338
|
+
mtab = '/etc/mtab'
|
339
|
+
if File.exist?(mtab)
|
340
|
+
d ||= mountpoint_of_cwd
|
341
|
+
open(mtab,'r') do |f|
|
342
|
+
f.each_line do |l|
|
343
|
+
if /#{d} (?:type )?(\S+)/o =~ l
|
344
|
+
return $1
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
nil
|
350
|
+
end
|
351
|
+
|
352
|
+
def mountpoint_of_cwd
|
353
|
+
d = Pathname.pwd
|
354
|
+
while !d.mountpoint?
|
355
|
+
d = d.parent
|
356
|
+
end
|
357
|
+
d
|
358
|
+
end
|
359
|
+
|
360
|
+
# ----- finish -----
|
361
|
+
|
362
|
+
def finish_option
|
363
|
+
Log.close
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
367
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
class Profiler
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@lock = Mutex.new
|
7
|
+
@separator = ","
|
8
|
+
@gnu_time = false
|
9
|
+
@id = 0
|
10
|
+
@io = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :separator, :gnu_time
|
14
|
+
|
15
|
+
def open(file,gnu_time)
|
16
|
+
@gnu_time = gnu_time
|
17
|
+
@lock.synchronize do
|
18
|
+
@io.close if @io != nil
|
19
|
+
@io = File.open(file,"w")
|
20
|
+
end
|
21
|
+
_puts table_header
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@lock.synchronize do
|
26
|
+
@io.close if @io != nil
|
27
|
+
@io = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def _puts(s)
|
32
|
+
@lock.synchronize do
|
33
|
+
@io.puts(s) if @io
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def table_header
|
38
|
+
a = %w[id task command start end elap status]
|
39
|
+
if @gnu_time
|
40
|
+
a.concat %w[realtime systime usrtime maxrss averss memsz
|
41
|
+
datasz stcksz textsz pagesz majflt minflt nswap ncswinv
|
42
|
+
ncswvol ninp nout msgrcv msgsnd signum]
|
43
|
+
end
|
44
|
+
a.join(@separator)
|
45
|
+
end
|
46
|
+
|
47
|
+
def command(cmd,terminator)
|
48
|
+
if @gnu_time
|
49
|
+
if /\*|\?|\{|\}|\[|\]|<|>|\(|\)|\~|\&|\||\\|\$|;|`|\n/ =~ cmd
|
50
|
+
cmd = cmd.gsub(/'/,"'\"'\"'")
|
51
|
+
cmd = "sh -c '#{cmd}'"
|
52
|
+
end
|
53
|
+
f = %w[%x %e %S %U %M %t %K %D %p %X %Z %F %R %W %c %w %I %O %r
|
54
|
+
%s %k].join(@separator)
|
55
|
+
"/usr/bin/time -o /dev/stdout -f '#{terminator}:#{f}' #{cmd}"
|
56
|
+
else
|
57
|
+
"#{cmd}\necho '#{terminator}':$? "
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def format_time(t)
|
62
|
+
t.utc.strftime("%F %T.%L").inspect
|
63
|
+
end
|
64
|
+
|
65
|
+
def profile(task, cmd, start_time, end_time, status)
|
66
|
+
id = @lock.synchronize do
|
67
|
+
id = @id
|
68
|
+
@id += 1
|
69
|
+
id
|
70
|
+
end
|
71
|
+
if @io
|
72
|
+
_puts [id, task && task.name.inspect,
|
73
|
+
cmd.inspect,
|
74
|
+
format_time(start_time),
|
75
|
+
format_time(end_time),
|
76
|
+
"%.3f" % (end_time-start_time),
|
77
|
+
status].join(@separator)
|
78
|
+
end
|
79
|
+
if @gnu_time
|
80
|
+
/^([^,]*),/ =~ status
|
81
|
+
Integer($1)
|
82
|
+
else
|
83
|
+
Integer(status)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/lib/pwrake/shell.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
module Pwrake
|
2
|
+
|
3
|
+
class Shell
|
4
|
+
CHARS='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
5
|
+
TLEN=32
|
6
|
+
|
7
|
+
OPEN_LIST={}
|
8
|
+
|
9
|
+
def self.nice=(nice)
|
10
|
+
@@nice=nice
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.reset_id
|
14
|
+
@@current_id = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
@@nice = "nice"
|
18
|
+
@@shell = "sh"
|
19
|
+
@@current_id = 0
|
20
|
+
@@profiler = Profiler.new
|
21
|
+
|
22
|
+
def self.profiler
|
23
|
+
@@profiler
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(host,opt={})
|
27
|
+
@host = host || 'localhost'
|
28
|
+
@lock = Mutex.new
|
29
|
+
@@current_id += 1
|
30
|
+
@id = @@current_id
|
31
|
+
@option = opt
|
32
|
+
@work_dir = @option[:work_dir] || Dir.pwd
|
33
|
+
@pass_env = @option[:pass_env]
|
34
|
+
@ssh_opt = @option[:ssh_opt]
|
35
|
+
@terminator = ""
|
36
|
+
TLEN.times{ @terminator << CHARS[rand(CHARS.length)] }
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :id
|
40
|
+
attr_accessor :current_task
|
41
|
+
|
42
|
+
def system_cmd(*arg)
|
43
|
+
if ['localhost','localhost.localdomain','127.0.0.1'].include? @host
|
44
|
+
[@@nice,@@shell].join(' ')
|
45
|
+
else
|
46
|
+
"ssh -x -T -q #{@ssh_opt} #{@host} #{@@nice} #{@@shell}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def start
|
51
|
+
open(system_cmd)
|
52
|
+
cd_work_dir
|
53
|
+
end
|
54
|
+
|
55
|
+
def open(cmd,path=nil)
|
56
|
+
if path.nil?
|
57
|
+
path = ENV['PATH']
|
58
|
+
end
|
59
|
+
@io = IO.popen( cmd, "r+" )
|
60
|
+
OPEN_LIST[__id__] = self
|
61
|
+
_system "export PATH='#{path}'"
|
62
|
+
if @pass_env
|
63
|
+
@pass_env.each do |k,v|
|
64
|
+
_system "export #{k}='#{v}'"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :host, :status, :profile
|
70
|
+
|
71
|
+
def finish
|
72
|
+
close
|
73
|
+
end
|
74
|
+
|
75
|
+
def close
|
76
|
+
@lock.synchronize do
|
77
|
+
if !@io.closed?
|
78
|
+
@io.puts("exit")
|
79
|
+
@io.close
|
80
|
+
end
|
81
|
+
OPEN_LIST.delete(__id__)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def backquote(*command)
|
86
|
+
command = command.join(' ')
|
87
|
+
@lock.synchronize do
|
88
|
+
a = []
|
89
|
+
_execute(command){|x| a << x}
|
90
|
+
a.join("\n")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def system(*command)
|
95
|
+
command = command.join(' ')
|
96
|
+
Log.debug "--- command=#{command.inspect}"
|
97
|
+
@lock.synchronize do
|
98
|
+
_execute(command){|x| LOCK.synchronize{puts x}}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def cd_work_dir
|
103
|
+
_system("cd #{@work_dir}")
|
104
|
+
end
|
105
|
+
|
106
|
+
def cd(dir="")
|
107
|
+
_system("cd #{dir}")
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
END {
|
112
|
+
OPEN_LIST.map do |k,v|
|
113
|
+
v.close
|
114
|
+
end
|
115
|
+
Shell.profiler.close
|
116
|
+
}
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def _system(cmd)
|
121
|
+
raise "@io is closed" if @io.closed?
|
122
|
+
@lock.synchronize do
|
123
|
+
@io.puts(cmd+"\necho '#{@terminator}':$? ")
|
124
|
+
status = io_read_loop{}
|
125
|
+
Integer(status) == 0
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def _execute(cmd,quote=nil,&block)
|
130
|
+
raise "@io is closed" if @io.closed?
|
131
|
+
start_time = Time.now
|
132
|
+
@io.puts @@profiler.command(cmd,@terminator)
|
133
|
+
status = io_read_loop(&block)
|
134
|
+
end_time = Time.now
|
135
|
+
@status = @@profiler.profile(@current_task, cmd,
|
136
|
+
start_time, end_time, status)
|
137
|
+
@status == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
def io_read_loop
|
141
|
+
while x = @io.gets
|
142
|
+
x.chomp!
|
143
|
+
if x[0,TLEN] == @terminator
|
144
|
+
return x[TLEN+1..-1]
|
145
|
+
end
|
146
|
+
yield x
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end # module Pwrake
|