vete 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|