vete 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/vete.rb +84 -45
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c68c30f1f9ce2177fb7c5a83ac8fa9f402b387203e2e1de2321a04ec3effa0c
4
- data.tar.gz: 246eed50879a2fd260d1f0b18aab85d3ffe953cd6980d9bb5cca1311a789b202
3
+ metadata.gz: 31328c3602f1174d697b56c9d0b8049986b68151975ed05c2febe3bab04d0c00
4
+ data.tar.gz: e4d99dd8303a7bcc8d589f66bb6ad0a0e2b79bfb718c7f2856f2e3a7aa558e63
5
5
  SHA512:
6
- metadata.gz: 55b4b6dd945930575cf37a814ce1c9d7b7dbfbab6e8a306887841d48dd49331f6b302cfbac0d1741e409fd6bac57153fa52d5bbabe5fab4110f736f3e7660136
7
- data.tar.gz: 992cd2007a936f4f7ef53b0741011c916aa3b90802a8794c31a48577fb551fadb50adbcb98e6521d0f5e2716a29e74ca650b5b0dd01c0b023585ecabf89696bc
6
+ metadata.gz: 0df917b8b8bb7cc72e0903130543e4e700b4264e8119b9f65d5c038cfa2dfb3538804945df489fcc27fa781deb18c923a2c540087dbf95b60c50f8a1eca48890
7
+ data.tar.gz: d05bac44008d71d71738b234d0d2f750fdfdaa4c5d3de24263dd72e1888039165c5d902bdb01510712e0741750ae57dca16a679728c9cf5e97384227d1af80b2
data/lib/vete.rb CHANGED
@@ -4,6 +4,8 @@
4
4
  # Author: Steve Shreeve (steve.shreeve@gmail.com)
5
5
  # Date: Mar 21, 2023
6
6
  # ============================================================================
7
+ # TODO: 1) progress should update until all workers have *finished*
8
+ # ============================================================================
7
9
 
8
10
  STDOUT.sync = true
9
11
 
@@ -13,16 +15,20 @@ require "fileutils"
13
15
  require "optparse"
14
16
  require "thread"
15
17
 
16
- trap("INT" ) { print clear + go; abort "\n" }
18
+ @pid = Process.pid
19
+
20
+ trap("INT" ) { print clear + go; abort "\n" }
21
+ trap("WINCH") { print clear or draw if @pid == Process.pid }
17
22
 
18
23
  OptionParser.new.instance_eval do
19
- @version = "0.1.0"
24
+ @version = "0.3.0"
20
25
  @banner = "usage: #{program_name} [options]"
21
26
 
22
27
  on "-b", "--bar <width>" , "Progress bar width, in characters", Integer
23
28
  on "-c", "--char <character>" , "Character to use for progress bar", String
24
- on "-r", "--reset" , "Remove directory used for job processing and quit"
29
+ on "-d", "--delay <mode>" , "Delay mode (rand, task, numeric)"
25
30
  on "-h", "--help" , "Show help and command usage" do Kernel.abort to_s; end
31
+ on "-r", "--reset" , "Remove directory used for job processing and quit"
26
32
  on "-v", "--version" , "Show version number" do Kernel.abort "#{program_name} #{@version}"; end
27
33
  on "-w", "--workers <count>" , "Set the number of workers (default is 1)", Integer
28
34
 
@@ -30,10 +36,21 @@ OptionParser.new.instance_eval do
30
36
  end.parse!(into: opts={}) rescue abort($!.message)
31
37
 
32
38
  # populate CLI options
33
- @bar = opts[:bar ] || 20
34
- @chr = opts[:char ] || "•"; @chr = @chr[0]
35
- @rmf = opts[:reset ]
36
- @wrk = opts[:workers] || 1
39
+ @char = opts[:char ] || "•"; @char = @char[0]
40
+ @wait = opts[:delay ]
41
+ @nuke = opts[:reset ]
42
+ @wide = opts[:bar ] || 20
43
+ @work = opts[:workers] || 1
44
+
45
+ # handle wait mode
46
+ case @wait
47
+ when "rand", "task", nil
48
+ when /\A(?:0|[1-9]\d*|(?:0?\.|[1-9]\d*\.)\d*)\z/
49
+ @wait = @wait.to_f
50
+ @wait > 0 or abort "invalid delay time (#{@wait.to_f} secs)"
51
+ else
52
+ abort "invalid delay mode '#{@wait}'"
53
+ end
37
54
 
38
55
  # define job directories
39
56
  @vete = File.expand_path(".vete")
@@ -42,24 +59,43 @@ end.parse!(into: opts={}) rescue abort($!.message)
42
59
  @done = File.join(@vete, "done")
43
60
  @bomb = File.join(@vete, "bomb")
44
61
 
45
- if @rmf
46
- FileUtils.rm_rf @vete
62
+ def move(path, dest)
63
+ dest = File.join(dest, File.basename(path))
64
+ FileUtils.mv(path, dest, force: true, secure: true)
65
+ end
66
+
67
+ def nuke
68
+ FileUtils.rm_rf(@vete)
69
+ end
70
+
71
+ if @nuke
72
+ nuke
47
73
  exit
48
74
  end
49
75
 
50
- def move(path, dest)
51
- dest = File.join(dest, File.basename(path))
52
- FileUtils.mv(path, dest)
76
+ def vete_init
77
+ nuke
78
+ list = [@todo, @live, @done, @bomb]
79
+ list.each {|path| File.mkdir_p(path, force: true, secure: true) }
80
+ end
81
+
82
+ def vete_retry
83
+ list = Dir.glob(File.join(@bomb, "*")).sort.each {|path| FileUtils.touch(path) }
84
+ move(list, @todo)
85
+ end
86
+
87
+ def vete_todo(path)
88
+ FileUtils.touch(path, force: true, secure: true)
53
89
  end
54
90
 
55
91
  # ==[ Drawing ]===============================================================
56
92
 
57
93
  # https://www.cse.psu.edu/~kxc104/class/cmpen472/16f/hw/hw8/vt100ansi.htm
58
94
 
59
- def clear ; "\e[2J" ; end
60
- def cursor(on) ; print on ? "\e[?25h": "\e[?25l"; end
61
- def go(r=1,c=1); "\e[#{r};#{c}H" ; end
62
- def go!(...) ; print go(...) ; end
95
+ def clear(line=nil); line ? "\e[K" : "\e[2J" ; end
96
+ def cursor(on) ; print on ? "\e[?25h": "\e[?25l"; end
97
+ def go(r=1,c=1) ; "\e[#{r};#{c}H" ; end
98
+ def go!(...) ; print go(...) ; end
63
99
 
64
100
  def fg(rgb=nil); rgb ? "\e[38;2;#{hx(rgb)}m" : "\e[39m"; end
65
101
  def bg(rgb=nil); rgb ? "\e[48;2;#{hx(rgb)}m" : "\e[49m"; end
@@ -68,39 +104,39 @@ def hx(str=nil); str =~ /\A#?(?:(\h\h)(\h\h)(\h\h)|(\h)(\h)(\h))\z/ or return
68
104
  [r.hex, g.hex, b.hex] * ";"
69
105
  end
70
106
 
71
- def draw(rows, done=0, live=0, bomb=0, jobs=0, info=nil)
107
+ def draw(live=0, done=0, bomb=0, jobs=0, info=nil)
72
108
 
73
109
  # outer box
74
110
  unless info
75
111
  print [
76
112
  clear,
77
- go(2 + rows, @len + 3) + "└" + "─" * (@bar + 2) + "┘\n",
78
- go(1 , @len + 3) + "┌" + "─" * (@bar + 2) + "┐\n",
113
+ go(2 + @work, @len + 3) + "└" + "─" * (@wide + 2) + "┘\n",
114
+ go(1 , @len + 3) + "┌" + "─" * (@wide + 2) + "┐\n",
79
115
  ].join
80
- rows.times {|i| print " %*d │ %*s │\n" % [@len, i + 1, @bar, ""] }
116
+ @work.times {|i| print " %*d │ %*s │\n" % [@len, i + 1, @wide, ""] }
81
117
  return
82
118
  end
83
119
 
84
120
  # worker bars
85
- dpct = done.to_f / jobs
86
121
  lpct = live.to_f / jobs
122
+ dpct = done.to_f / jobs
87
123
  most = info.values.max
88
124
  info.each do |slot, this|
89
125
  tpct = this.to_f / most
90
- cols = dpct * tpct * @bar
91
- print go(slot + 1, @len + 5) + bg("5383ec") + @chr * cols
126
+ cols = dpct * tpct * @wide
127
+ print go(slot + 1, @len + 5) + bg("5383ec") + @char * cols
92
128
  end
93
129
 
94
130
  # summary bar
95
- gcol = dpct * @bar
96
- ycol = lpct * @bar
131
+ gcol = dpct * @wide
132
+ ycol = lpct * @wide
97
133
  print [
98
- go(rows + 3, @len + 5),
134
+ go(@work + 3, @len + 5),
99
135
  fg("fff"),
100
- bg("58a65c") + @chr * ( gcol ) , # green (done)
101
- bg("f1bf42") + @chr * ( ycol) , # yellow (live) <= Add live
102
- bg("d85140") + " " * (@bar - gcol - ycol).ceil, # red (left)
103
- go(rows + 3, @len + 5 + @bar + 3) + " %.1f%% done " % [dpct * 100],
136
+ bg("58a65c") + @char * ( gcol ) , # green (done)
137
+ bg("f1bf42") + @char * ( ycol) , # yellow (live)
138
+ bg("d85140") + " " * (@wide - gcol - ycol).ceil, # red (left)
139
+ go(@work + 3, @len + 5 + @wide + 3) + " %.1f%% done " % [dpct * 100],
104
140
  bomb == 0 ? nil : (bg + " " + bg("f1bf42") + " #{bomb} bombed "),
105
141
  ].join
106
142
 
@@ -116,64 +152,67 @@ FileUtils.mkdir_p @live
116
152
  FileUtils.mkdir_p @done
117
153
  FileUtils.mkdir_p @bomb
118
154
 
119
- 1.upto(100) {|i| FileUtils.touch(File.join(@todo, i.to_s)) }
155
+ 100.times {|i| FileUtils.touch(File.join(@todo, (i + 1).to_s)) }
120
156
 
121
157
  # ==[ Configure workers ]=====================================================
122
158
 
123
- @len = @wrk.to_s.size
159
+ @len = @work.to_s.size
124
160
  @mtx = Mutex.new
125
- @que = Thread::Queue.new; @wrk.times {|slot| @que << (slot + 1) }
161
+ @que = Thread::Queue.new; @work.times {|slot| @que << (slot + 1) }
126
162
 
127
163
  begin
128
164
  list = Dir[File.join(@todo, "*")]
129
165
  jobs = list.size
130
166
  info = Hash.new(0)
131
167
 
132
- setup
168
+ setup if defined?(setup)
133
169
 
134
170
  cursor(false)
135
- draw(@wrk)
136
-
137
- time = Time.now
138
- done = 0
171
+ draw
139
172
  live = 0
173
+ done = 0
140
174
  bomb = 0
175
+ time = Time.now
141
176
  Thread.new do
142
- list.each do |path|
177
+ list.each_with_index do |path, task|
143
178
  slot = @que.pop
144
179
  @mtx.synchronize {
145
180
  live += 1
146
181
  }
147
182
  show = "Working on task " + File.basename(path)
148
- print go(slot + 1, @len + 5 + @bar + 3) + show
183
+ print go(slot + 1, @len + 5 + @wide + 3) + show + clear(true)
149
184
  if chld = fork # parent
150
185
  Thread.new do
151
186
  okay = Process.waitpid2(chld)[1] == 0
152
187
  move(path, okay ? @done : @bomb)
153
188
  @que.push(slot)
154
189
  @mtx.synchronize {
155
- done += 1
156
190
  live -= 1
191
+ done += 1
157
192
  bomb += 1 unless okay
158
193
  info[slot] += 1
159
194
  }
160
195
  end
161
- draw(@wrk, done, live, bomb, jobs, info.dup)
196
+ draw(live, done, bomb, jobs, info.dup)
162
197
  else
198
+ case @wait
199
+ when "rand" then sleep rand(@work)
200
+ when "task" then sleep task
201
+ when Numeric then sleep task * @wait
202
+ end if task < @work
163
203
  perform(slot, path)
164
204
  exit
165
205
  end
166
206
  end
167
207
  end.join
168
- draw(@wrk, done, live, bomb, jobs, info)
169
208
  secs = Time.now.to_f - time.to_f
170
209
 
171
210
  # summary
172
211
  print [
173
- go(@wrk + 5, 1),
212
+ go(@work + 5, 1),
174
213
  "%.2f secs" % secs,
175
214
  " for #{jobs} jobs",
176
- " by #{@wrk} workers",
215
+ " by #{@work} workers",
177
216
  " @ %.2f jobs/sec" % [jobs / secs]
178
217
  ].join + "\n\n"
179
218
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vete
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Shreeve
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-21 00:00:00.000000000 Z
11
+ date: 2023-03-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby CLI to spawn processes to get work done
14
14
  email: steve.shreeve@gmail.com