@rip-lang/swarm 1.2.4 → 1.2.6
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.
- package/package.json +1 -1
- package/swarm.rip +46 -39
package/package.json
CHANGED
package/swarm.rip
CHANGED
|
@@ -87,8 +87,9 @@ hex = (str) ->
|
|
|
87
87
|
[parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)].join(';')
|
|
88
88
|
_hex[str] = result
|
|
89
89
|
|
|
90
|
-
fg
|
|
91
|
-
bg
|
|
90
|
+
fg = (rgb) -> if rgb then "\x1b[38;2;#{hex(rgb)}m" else "\x1b[39m"
|
|
91
|
+
bg = (rgb) -> if rgb then "\x1b[48;2;#{hex(rgb)}m" else "\x1b[49m"
|
|
92
|
+
fgw =! "\x1b[97m" # bright white — more reliable than 24-bit fg("fff")
|
|
92
93
|
|
|
93
94
|
# ==============================================================================
|
|
94
95
|
# Progress display
|
|
@@ -113,13 +114,14 @@ draw = (state) ->
|
|
|
113
114
|
ppct = (done + died) / jobs
|
|
114
115
|
most = Math.max(...Object.values(info), 1)
|
|
115
116
|
|
|
116
|
-
# worker bars
|
|
117
|
+
# worker bars — set colors once, just move cursor per row
|
|
118
|
+
write fgw + bg("5383ec")
|
|
117
119
|
for slot, count of info
|
|
118
120
|
tpct = count / most
|
|
119
121
|
cols = Math.floor(ppct * tpct * wide)
|
|
120
|
-
write go(parseInt(slot) + 1, len + 5) +
|
|
122
|
+
write go(parseInt(slot) + 1, len + 5) + char.repeat(cols)
|
|
121
123
|
|
|
122
|
-
# summary bar
|
|
124
|
+
# summary bar — one atomic write
|
|
123
125
|
dpct = done / jobs
|
|
124
126
|
lpct = live / jobs
|
|
125
127
|
gcol = Math.floor(dpct * wide)
|
|
@@ -129,12 +131,11 @@ draw = (state) ->
|
|
|
129
131
|
|
|
130
132
|
out = [
|
|
131
133
|
go(row, len + 5)
|
|
132
|
-
|
|
133
|
-
bg("
|
|
134
|
-
bg("
|
|
135
|
-
bg("d85140") + " ".repeat(rcol) # red (rest)
|
|
134
|
+
bg("58a65c") + char.repeat(gcol) # green (done)
|
|
135
|
+
bg("f1bf42") + char.repeat(ycol) # yellow (live)
|
|
136
|
+
bg("d85140") + " ".repeat(rcol) # red (rest)
|
|
136
137
|
go(row, len + 5 + wide + 3)
|
|
137
|
-
bg("5383ec") + " #{(ppct * 100).toFixed(1)}% "
|
|
138
|
+
bg("5383ec") + " #{(ppct * 100).toFixed(1)}% " # blue (pct)
|
|
138
139
|
if done > 0 then bg() + " " + bg("58a65c") + " #{done}/#{jobs} done "
|
|
139
140
|
if died > 0 then bg() + " " + bg("d85140") + " #{died} died "
|
|
140
141
|
].filter(Boolean).join('') + fg() + bg()
|
|
@@ -162,6 +163,7 @@ export swarm = (opts = {}) ->
|
|
|
162
163
|
char = (findArg(args, '-c', '--char') or opts.char or '•')[0]
|
|
163
164
|
doreset = args.includes('-r') or args.includes('--reset')
|
|
164
165
|
dosafe = args.includes('-s') or args.includes('--safe')
|
|
166
|
+
quiet = args.includes('-q') or args.includes('--quiet')
|
|
165
167
|
|
|
166
168
|
if workers < 1
|
|
167
169
|
console.error 'error: workers must be at least 1'
|
|
@@ -223,17 +225,19 @@ export swarm = (opts = {}) ->
|
|
|
223
225
|
|
|
224
226
|
# signal handlers
|
|
225
227
|
process.on 'SIGINT', ->
|
|
226
|
-
cursor(true)
|
|
227
|
-
write go(workers + 5, 1) + "\n"
|
|
228
|
+
cursor(true) unless quiet
|
|
229
|
+
write go(workers + 5, 1) + "\n" unless quiet
|
|
228
230
|
process.exit(1)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
unless quiet
|
|
232
|
+
process.on 'SIGWINCH', ->
|
|
233
|
+
drawFrame(workers)
|
|
234
|
+
draw({ live, done, died, jobs, workers, info })
|
|
232
235
|
|
|
233
236
|
# draw initial frame
|
|
234
237
|
startTime = Date.now()
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
unless quiet
|
|
239
|
+
cursor(false)
|
|
240
|
+
drawFrame(workers)
|
|
237
241
|
|
|
238
242
|
# create workers and dispatch tasks
|
|
239
243
|
allWorkers = []
|
|
@@ -254,8 +258,9 @@ export swarm = (opts = {}) ->
|
|
|
254
258
|
taskPath = tasks[taskIdx++]
|
|
255
259
|
inflight[slot] = taskPath
|
|
256
260
|
live++
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
unless quiet
|
|
262
|
+
write go(slot + 1, len + 5 + wide + 3) + " " + taskPath.split('/').pop() + clear(true)
|
|
263
|
+
draw({ live, done, died, jobs, workers, info })
|
|
259
264
|
worker.postMessage { type: 'task', taskPath }
|
|
260
265
|
else
|
|
261
266
|
inflight[slot] = null
|
|
@@ -272,6 +277,7 @@ export swarm = (opts = {}) ->
|
|
|
272
277
|
w.on 'message', (msg) ->
|
|
273
278
|
switch msg.type
|
|
274
279
|
when 'error'
|
|
280
|
+
console.error "\nswarm: worker #{slot} failed to start: #{msg.error}"
|
|
275
281
|
writeFileSync('.swarm/errors.log', "worker #{slot} startup: #{msg.error}\n", { flag: 'a' }) if existsSync(_dir)
|
|
276
282
|
when 'ready'
|
|
277
283
|
dispatchNext(w, slot)
|
|
@@ -282,7 +288,7 @@ export swarm = (opts = {}) ->
|
|
|
282
288
|
live--
|
|
283
289
|
done++
|
|
284
290
|
info[slot]++
|
|
285
|
-
draw({ live, done, died, jobs, workers, info })
|
|
291
|
+
draw({ live, done, died, jobs, workers, info }) unless quiet
|
|
286
292
|
dispatchNext(w, slot)
|
|
287
293
|
when 'failed'
|
|
288
294
|
move(msg.taskPath, _died)
|
|
@@ -292,7 +298,7 @@ export swarm = (opts = {}) ->
|
|
|
292
298
|
live--
|
|
293
299
|
died++
|
|
294
300
|
info[slot]++
|
|
295
|
-
draw({ live, done, died, jobs, workers, info })
|
|
301
|
+
draw({ live, done, died, jobs, workers, info }) unless quiet
|
|
296
302
|
dispatchNext(w, slot)
|
|
297
303
|
|
|
298
304
|
w.on 'error', (err) ->
|
|
@@ -307,7 +313,7 @@ export swarm = (opts = {}) ->
|
|
|
307
313
|
live--
|
|
308
314
|
died++
|
|
309
315
|
info[slot]++
|
|
310
|
-
draw({ live, done, died, jobs, workers, info })
|
|
316
|
+
draw({ live, done, died, jobs, workers, info }) unless quiet
|
|
311
317
|
# respawn if there's still work to do
|
|
312
318
|
if done + died < jobs
|
|
313
319
|
spawnWorker(slot)
|
|
@@ -319,23 +325,24 @@ export swarm = (opts = {}) ->
|
|
|
319
325
|
for slot in [1..count]
|
|
320
326
|
spawnWorker(slot)
|
|
321
327
|
|
|
322
|
-
# final redraw — fill all worker bars and show per-worker stats
|
|
323
|
-
secs = (Date.now() - startTime) / 1000
|
|
324
|
-
for slot of info
|
|
325
|
-
s = parseInt(slot)
|
|
326
|
-
n = info[slot]
|
|
327
|
-
rate = if secs > 0 then (n / secs).toFixed(1) else '—'
|
|
328
|
-
write go(s + 1, len + 5) + bg("5383ec") + char.repeat(wide) + bg() + " │ #{n} jobs @ #{rate}/sec" + clear(true)
|
|
329
|
-
draw({ live: 0, done, died, jobs, workers, info })
|
|
330
|
-
|
|
331
328
|
# summary
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
329
|
+
secs = (Date.now() - startTime) / 1000
|
|
330
|
+
if quiet
|
|
331
|
+
p "#{secs.toFixed(2)} secs for #{jobs} jobs by #{workers} workers" + (if secs > 0 then " @ #{(jobs / secs).toFixed(2)} jobs/sec" else "")
|
|
332
|
+
else
|
|
333
|
+
for slot of info
|
|
334
|
+
s = parseInt(slot)
|
|
335
|
+
n = info[slot]
|
|
336
|
+
rate = if secs > 0 then (n / secs).toFixed(1) else '—'
|
|
337
|
+
write go(s + 1, len + 5) + fgw + bg("5383ec") + char.repeat(wide) + fg() + bg() + " │ #{n} jobs @ #{rate}/sec" + clear(true)
|
|
338
|
+
draw({ live: 0, done, died, jobs, workers, info })
|
|
339
|
+
cursor(true)
|
|
340
|
+
write go(workers + 5, 1)
|
|
341
|
+
write "#{secs.toFixed(2)} secs"
|
|
342
|
+
write " for #{jobs} jobs"
|
|
343
|
+
write " by #{workers} workers"
|
|
344
|
+
write " @ #{(jobs / secs).toFixed(2)} jobs/sec" if secs > 0
|
|
345
|
+
write "\n\n"
|
|
339
346
|
|
|
340
347
|
# ==============================================================================
|
|
341
348
|
# CLI helpers
|
|
@@ -344,7 +351,7 @@ export swarm = (opts = {}) ->
|
|
|
344
351
|
# flags that swarm consumes (with value)
|
|
345
352
|
_flagsWithValue = ['-w', '--workers', '-b', '--bar', '-c', '--char']
|
|
346
353
|
# flags that swarm consumes (standalone)
|
|
347
|
-
_flagsAlone = ['-r', '--reset', '-s', '--safe', '-h', '--help', '-v', '--version']
|
|
354
|
+
_flagsAlone = ['-r', '--reset', '-s', '--safe', '-q', '--quiet', '-h', '--help', '-v', '--version']
|
|
348
355
|
|
|
349
356
|
findArg = (args, short, long) ->
|
|
350
357
|
for arg, i in args
|