rbbt-util 5.12.3 → 5.13.0

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