vete 0.1.0 → 0.3.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.
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