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.
- checksums.yaml +4 -4
- data/lib/vete.rb +84 -45
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31328c3602f1174d697b56c9d0b8049986b68151975ed05c2febe3bab04d0c00
|
4
|
+
data.tar.gz: e4d99dd8303a7bcc8d589f66bb6ad0a0e2b79bfb718c7f2856f2e3a7aa558e63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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.
|
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 "-
|
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
|
-
@
|
34
|
-
@
|
35
|
-
@
|
36
|
-
@
|
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
|
-
|
46
|
-
|
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
|
51
|
-
|
52
|
-
|
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
|
60
|
-
def cursor(on)
|
61
|
-
def go(r=1,c=1); "\e[#{r};#{c}H" ; end
|
62
|
-
def go!(...)
|
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(
|
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 +
|
78
|
-
go(1
|
113
|
+
go(2 + @work, @len + 3) + "└" + "─" * (@wide + 2) + "┘\n",
|
114
|
+
go(1 , @len + 3) + "┌" + "─" * (@wide + 2) + "┐\n",
|
79
115
|
].join
|
80
|
-
|
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 * @
|
91
|
-
print go(slot + 1, @len + 5) + bg("5383ec") + @
|
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 * @
|
96
|
-
ycol = lpct * @
|
131
|
+
gcol = dpct * @wide
|
132
|
+
ycol = lpct * @wide
|
97
133
|
print [
|
98
|
-
go(
|
134
|
+
go(@work + 3, @len + 5),
|
99
135
|
fg("fff"),
|
100
|
-
bg("58a65c") + @
|
101
|
-
bg("f1bf42") + @
|
102
|
-
bg("d85140") + " " * (@
|
103
|
-
go(
|
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
|
-
|
155
|
+
100.times {|i| FileUtils.touch(File.join(@todo, (i + 1).to_s)) }
|
120
156
|
|
121
157
|
# ==[ Configure workers ]=====================================================
|
122
158
|
|
123
|
-
@len = @
|
159
|
+
@len = @work.to_s.size
|
124
160
|
@mtx = Mutex.new
|
125
|
-
@que = Thread::Queue.new; @
|
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
|
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.
|
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 + @
|
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(
|
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(@
|
212
|
+
go(@work + 5, 1),
|
174
213
|
"%.2f secs" % secs,
|
175
214
|
" for #{jobs} jobs",
|
176
|
-
" by #{@
|
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.
|
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-
|
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
|