rbbt-util 5.12.3 → 5.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,11 +4,12 @@ require 'rbbt/util/concurrency/processes/socket'
4
4
  class RbbtProcessQueue
5
5
  #{{{ RbbtProcessQueue
6
6
 
7
- attr_accessor :num_processes, :processes, :queue, :process_monitor, :cleanup
8
- def initialize(num_processes, cleanup = nil)
7
+ attr_accessor :num_processes, :processes, :queue, :process_monitor, :cleanup, :join
8
+ def initialize(num_processes, cleanup = nil, join = nil)
9
9
  @num_processes = num_processes
10
10
  @processes = []
11
11
  @cleanup = cleanup
12
+ @join = join
12
13
  @queue = RbbtProcessSocket.new
13
14
  end
14
15
 
@@ -90,6 +91,8 @@ class RbbtProcessQueue
90
91
  ensure
91
92
  @queue.swrite.close
92
93
  end
94
+
95
+ @join.call if @join
93
96
  end
94
97
 
95
98
  def clean
@@ -4,26 +4,28 @@ class RbbtThreadQueue
4
4
  class RbbtThreadQueueWorker < Thread
5
5
  def initialize(queue, mutex = nil, &block)
6
6
  if mutex.nil?
7
- super(Thread.current) do |current|
7
+ super(Thread.current) do |parent|
8
8
  begin
9
9
  loop do
10
10
  p = queue.pop
11
11
  block.call *p
12
12
  end
13
+ rescue Aborted
13
14
  rescue Exception
14
- current.raise $! unless Aborted === $!
15
+ parent.raise $!
15
16
  end
16
17
  end
17
18
  else
18
- super(Thread.current) do |current|
19
+ super(Thread.current) do |parent|
19
20
  begin
20
21
  loop do
21
22
  p = queue.pop
22
23
  p = Array === p ? p << mutex : [p,mutex]
23
24
  block.call *p
24
25
  end
26
+ rescue Aborted
25
27
  rescue Exception
26
- current.raise $! unless Aborted === $!
28
+ parent.raise $!
27
29
  end
28
30
  end
29
31
  end
data/lib/rbbt/util/log.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'term/ansicolor'
2
2
  require 'rbbt/util/color'
3
+ require 'rbbt/util/log/progress'
3
4
 
4
5
  module Log
5
6
  extend Term::ANSIColor
@@ -0,0 +1,163 @@
1
+ require 'rbbt/util/log'
2
+ module Log
3
+ class ProgressBar
4
+
5
+ attr_accessor :depth, :num_reports, :desc, :io, :severity
6
+
7
+ # Creates a new instance. Max is the total number of iterations of the
8
+ # loop. The depth represents how many other loops are above this one,
9
+ # this information is used to find the place to print the progress
10
+ # report.
11
+ def initialize(max, options = {})
12
+ options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :desc => "Progress", :io => STDERR, :severity => Log.severity
13
+ depth, num_reports, desc, io, severity = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity
14
+
15
+ @max = max
16
+ @max = 1 if @max and @max < 1
17
+ @current = 0
18
+ @time = Time.now
19
+ @last_report = -1
20
+ @num_reports = num_reports
21
+ @severity = severity
22
+ @depth = depth
23
+ @desc = desc
24
+ end
25
+
26
+ # Used to register a new completed loop iteration.
27
+ def tick(step = nil)
28
+
29
+ if step.nil?
30
+ @current += 1
31
+ else
32
+ @current = step
33
+ end
34
+
35
+ if @max
36
+ if percent - @last_report > 1.to_f/@num_reports.to_f
37
+ report
38
+ @last_report=percent
39
+ end
40
+ else
41
+ @last_report = Time.now if @last_report == -1
42
+ if Time.now - @last_report >= 1.0
43
+ throughput
44
+ end
45
+ end
46
+
47
+ nil
48
+ end
49
+
50
+
51
+ def progress
52
+ @current.to_f/ @max
53
+ end
54
+
55
+ def percent
56
+ (self.progress * 100).to_i
57
+ end
58
+
59
+ def eta
60
+ (Time.now - @time)/progress * (1-progress)
61
+ end
62
+
63
+ def used
64
+ (Time.now - @time).to_i
65
+ end
66
+
67
+
68
+ def up_lines(depth)
69
+ "\033[#{depth + 2}F\033[2K"
70
+ end
71
+
72
+ def down_lines(depth)
73
+ "\n\033[#{depth + 3}E"
74
+ end
75
+
76
+ def report_msg
77
+ progress = self.progress
78
+ percent = self.percent
79
+
80
+ indicator = Log.color(:magenta, @desc) << " "
81
+ 10.times{|i|
82
+ if i < progress * 10 then
83
+ indicator << Log.color(:yellow, ".")
84
+ else
85
+ indicator << " "
86
+ end
87
+ }
88
+ done = progress == 1
89
+
90
+ used = self.used
91
+ used = [used/3600, used/60 % 60, used % 60].map{|t| "%02i" % t }.join(':')
92
+
93
+ if progress == 1
94
+ indicator << Log.color(:green, " done ")
95
+
96
+
97
+ indicator << Log.color(:blue, " #{used}")
98
+ else
99
+ indicator << " done #{Log.color(:blue, percent.to_s << "%")}"
100
+
101
+ eta = self.eta
102
+ eta = [eta/3600, eta/60 % 60, eta % 60].map{|t| "%02i" % t }.join(':')
103
+
104
+ indicator << " (Time left #{eta} seconds) (Started #{used} seconds ago)"
105
+ end
106
+
107
+ end
108
+
109
+ def throughput_msg
110
+ indicator = Log.color(:magenta, @desc)
111
+ time = Time.now - @last_report
112
+ thr = (@current / time).to_i
113
+ indicator << " #{ Log.color :blue, thr } per second"
114
+ indicator
115
+ end
116
+
117
+ # Prints de progress report. It backs up as many lines as the meters
118
+ # depth. Prints the progress as a line of dots, a percentage, time
119
+ # spent, and time left. And then goes moves the cursor back to its
120
+ # original line. Everything is printed to stderr.
121
+ def report(io = STDERR)
122
+ io.print(up_lines(@depth) << report_msg << down_lines(@depth)) if severity >= Log.severity
123
+ end
124
+
125
+ def throughput(io = STDERR)
126
+ io.print(up_lines(@depth) << throughput_msg << down_lines(@depth)) if severity >= Log.severity
127
+ @last_report = Time.now
128
+ @current = 0
129
+ end
130
+ BAR_MUTEX = Mutex.new
131
+ BARS = []
132
+ def self.new_bar(max, options = {})
133
+ options = Misc.add_defaults options, :depth => BARS.length
134
+ BAR_MUTEX.synchronize do
135
+ BARS << (bar = ProgressBar.new(max, options))
136
+ bar
137
+ end
138
+ end
139
+
140
+ def self.remove_bar(bar)
141
+ BAR_MUTEX.synchronize do
142
+ index = BARS.index bar
143
+ if index
144
+ (index+1..BARS.length-1).each do |pos|
145
+ bar = BARS[pos]
146
+ bar.depth = pos - 1
147
+ BARS[pos-1] = bar
148
+ end
149
+ BARS.pop
150
+ end
151
+ end
152
+ end
153
+
154
+ def self.with_bar(max, options = {})
155
+ bar = new_bar(max, options)
156
+ begin
157
+ yield bar
158
+ ensure
159
+ remove_bar(bar)
160
+ end
161
+ end
162
+ end
163
+ end
@@ -110,6 +110,7 @@ module Misc
110
110
  end
111
111
 
112
112
  def self.add_defaults(options, defaults = {})
113
+ options ||= {}
113
114
  case
114
115
  when Hash === options
115
116
  new_options = options.dup
@@ -73,65 +73,74 @@ module Misc
73
73
  sout
74
74
  end
75
75
 
76
- def self.tee_stream_fork(stream)
77
- stream_out1, stream_in1 = Misc.pipe
78
- stream_out2, stream_in2 = Misc.pipe
79
-
80
- splitter_pid = Process.fork do
81
- Misc.purge_pipes(stream_in1, stream_in2)
82
- stream_out1.close
83
- stream_out2.close
84
- begin
85
- filename = stream.respond_to?(:filename)? stream.filename : nil
86
- skip1 = skip2 = false
87
- while block = stream.read(2048)
88
- begin stream_in1.write block; rescue Exception; Log.exception $!; skip1 = true end unless skip1
89
- begin stream_in2.write block; rescue Exception; Log.exception $!; skip2 = true end unless skip2
90
- end
91
- raise "Error writing in stream_in1" if skip1
92
- raise "Error writing in stream_in2" if skip2
93
- stream.join if stream.respond_to? :join
94
- stream_in1.close
95
- stream_in2.close
96
- rescue Aborted
97
- stream.abort if stream.respond_to? :abort
98
- raise $!
99
- rescue IOError
100
- Log.exception $!
101
- rescue Exception
102
- Log.exception $!
103
- end
104
- end
105
- stream.close
106
- stream_in1.close
107
- stream_in2.close
108
-
109
- ConcurrentStream.setup stream_out1, :pids => [splitter_pid]
110
- ConcurrentStream.setup stream_out2, :pids => [splitter_pid]
111
-
112
- [stream_out1, stream_out2]
113
- end
76
+ #def self.tee_stream_fork(stream)
77
+ # stream_out1, stream_in1 = Misc.pipe
78
+ # stream_out2, stream_in2 = Misc.pipe
79
+
80
+ # splitter_pid = Process.fork do
81
+ # Misc.purge_pipes(stream_in1, stream_in2)
82
+ # stream_out1.close
83
+ # stream_out2.close
84
+ # begin
85
+ # filename = stream.respond_to?(:filename)? stream.filename : nil
86
+ # skip1 = skip2 = false
87
+ # while block = stream.read(2048)
88
+ # begin stream_in1.write block; rescue Exception; Log.exception $!; skip1 = true end unless skip1
89
+ # begin stream_in2.write block; rescue Exception; Log.exception $!; skip2 = true end unless skip2
90
+ # end
91
+ # raise "Error writing in stream_in1" if skip1
92
+ # raise "Error writing in stream_in2" if skip2
93
+ # stream.join if stream.respond_to? :join
94
+ # stream_in1.close
95
+ # stream_in2.close
96
+ # rescue Aborted
97
+ # stream.abort if stream.respond_to? :abort
98
+ # raise $!
99
+ # rescue IOError
100
+ # Log.exception $!
101
+ # rescue Exception
102
+ # Log.exception $!
103
+ # end
104
+ # end
105
+ # stream.close
106
+ # stream_in1.close
107
+ # stream_in2.close
108
+
109
+ # ConcurrentStream.setup stream_out1, :pids => [splitter_pid]
110
+ # ConcurrentStream.setup stream_out2, :pids => [splitter_pid]
111
+
112
+ # [stream_out1, stream_out2]
113
+ #end
114
114
 
115
115
  def self.tee_stream_thread(stream)
116
116
  stream_out1, stream_in1 = Misc.pipe
117
117
  stream_out2, stream_in2 = Misc.pipe
118
118
 
119
- splitter_thread = Thread.new(Thread.current, stream_in1, stream_in2) do |parent,stream_in1,stream_in2|
119
+ splitter_thread = Thread.new(Thread.current) do |parent|
120
120
  begin
121
121
  filename = stream.respond_to?(:filename)? stream.filename : nil
122
122
  skip1 = skip2 = false
123
123
  while block = stream.read(2048)
124
- begin stream_in1.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip1 = true end unless skip1
125
- begin stream_in2.write block; rescue Exception; Aborted === $! ? raise($!): Log.exception($!); skip2 = true end unless skip2
124
+ begin
125
+ stream_in1.write block;
126
+ rescue IOError
127
+ Log.error("Tee stream 1 #{stream} IOError: #{$!.message}");
128
+ skip1 = true
129
+ end unless skip1
130
+
131
+ begin
132
+ stream_in2.write block
133
+ rescue IOError
134
+ Log.error("Tee stream 2 #{stream} IOError: #{$!.message}");
135
+ skip2 = true
136
+ end unless skip2
126
137
  end
127
- stream_in1.close
128
- stream_in2.close
138
+ stream_in1.close unless stream_in1.closed?
139
+ stream_in2.close unless stream_in2.closed?
129
140
  stream.join if stream.respond_to? :join
130
141
  rescue Aborted
142
+ Log.error("Tee stream #{stream} Aborted");
131
143
  stream.abort if stream.respond_to? :abort
132
- parent.raise $!
133
- rescue IOError
134
- Log.exception $!
135
144
  rescue Exception
136
145
  Log.exception $!
137
146
  parent.raise $!
@@ -207,10 +216,11 @@ module Misc
207
216
  end
208
217
 
209
218
  def self.sensiblewrite(path, content = nil, &block)
210
- return if File.exists? path
219
+
220
+ return if Open.exists? path
211
221
  tmp_path = Persist.persistence_path(path, {:dir => Misc.sensiblewrite_dir})
212
222
  Misc.lock tmp_path do
213
- if not File.exists? path
223
+ if not Open.exists? path
214
224
  FileUtils.rm_f tmp_path if File.exists? tmp_path
215
225
  begin
216
226
  case
@@ -227,10 +237,13 @@ module Misc
227
237
  else
228
238
  File.open(tmp_path, 'w') do |f| end
229
239
  end
230
- FileUtils.mv tmp_path, path
240
+
241
+ Open.mv tmp_path, path
242
+ rescue Aborted
243
+ Log.error "Aborted sensiblewrite -- #{ Log.color :blue, path }"
231
244
  rescue Exception
232
245
  Log.error "Exception in sensiblewrite: #{$!.message} -- #{ Log.color :blue, path }"
233
- FileUtils.rm_f path if File.exists? path
246
+ Open.rm_f path if File.exists? path
234
247
  raise $!
235
248
  ensure
236
249
  FileUtils.rm_f tmp_path if File.exists? tmp_path
File without changes
@@ -145,29 +145,34 @@ module Open
145
145
 
146
146
  def self.get_stream_from_repo(dir, sub_path)
147
147
  repo = get_repo_from_dir(dir)
148
- repo.read
149
- StringIO.new repo[sub_path]
148
+ repo.read_and_close do
149
+ StringIO.new repo[sub_path]
150
+ end
150
151
  end
151
152
 
152
153
  def self.save_content_in_repo(dir, sub_path, content)
153
154
  repo = get_repo_from_dir(dir)
154
- repo.write
155
- repo[sub_path] = content
155
+ repo.write_and_close do
156
+ repo[sub_path] = content
157
+ end
156
158
  end
157
159
 
158
160
  def self.remove_from_repo(dir, sub_path, recursive = false)
159
161
  repo = get_repo_from_dir(dir)
160
- repo.write
161
- if recursive
162
- repo.outlist repo.range sub_path, true, sub_path.sub(/.$/,('\1'.ord + 1).chr), false
163
- else
164
- repo.outlist sub_path
162
+ repo.write_and_close do
163
+ if recursive
164
+ repo.outlist repo.range sub_path, true, sub_path.sub(/.$/,('\1'.ord + 1).chr), false
165
+ else
166
+ repo.outlist sub_path
167
+ end
165
168
  end
166
169
  end
167
170
 
168
171
  def self.exists_in_repo(dir, sub_path, content)
169
172
  repo = get_repo_from_dir(dir)
170
- repo.include? sub_path
173
+ repo.read_and_close do
174
+ repo.include? sub_path
175
+ end
171
176
  end
172
177
 
173
178
  def self.find_repo_dir(file)
@@ -198,7 +203,7 @@ module Open
198
203
 
199
204
  def self.file_open(file, grep, mode = 'r', invert_grep = false)
200
205
  if (dir_sub_path = find_repo_dir(file))
201
- stream = get_stream_from_repo(*dir_sub_path)
206
+ stream = get_stream_from_repo(*dir_sub_path)
202
207
  else
203
208
  stream = File.open(file, mode)
204
209
  end
@@ -227,6 +232,34 @@ module Open
227
232
  end
228
233
  end
229
234
 
235
+ def self.mv(source, target)
236
+ dir_sub_path_source = find_repo_dir(source)
237
+ dir_sub_path_target = find_repo_dir(target)
238
+
239
+ return FileUtils.mv source, target if dir_sub_path_source.nil? and dir_sub_path_target.nil?
240
+
241
+ if dir_sub_path_source.nil?
242
+ save_content_in_repo(dir_sub_path_target[0], dir_sub_path_target[1], Open.read(source))
243
+ return nil
244
+ end
245
+
246
+ if dir_sub_path_target.nil?
247
+ Open.write(target, get_stream_from_repo(dir_sub_path_source))
248
+ return nil
249
+ end
250
+
251
+ repo_source = get_repo_from_dir(dir_sub_path_source[0])
252
+ repo_target = get_repo_from_dir(dir_sub_path_target[0])
253
+
254
+ repo_source.write do
255
+ repo_target.write do
256
+ repo_source[dir_sub_path_source[1]] = repo_target[dir_sub_path_target[1]]
257
+ end
258
+ end
259
+
260
+ return nil
261
+ end
262
+
230
263
  def self.exists?(file)
231
264
  if (dir_sub_path = find_repo_dir(file))
232
265
  dir_sub_path.push file
@@ -358,6 +391,7 @@ module Open
358
391
  end
359
392
 
360
393
  io.filename = url.to_s
394
+
361
395
  io
362
396
  end
363
397