Compare commits
3 commits
988a4aac4c
...
105839d8cf
Author | SHA1 | Date | |
---|---|---|---|
xenofem | 105839d8cf | ||
xenofem | 918b3bf10b | ||
xenofem | 6fec8076b4 |
54
README.md
Normal file
54
README.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# impatient
|
||||||
|
|
||||||
|
A general purpose utility for estimating when a task will complete
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`impatient` is sort of like `pv` for tasks where you can't insert
|
||||||
|
extra commands into a pipeline, and sort of like `progress` for tasks
|
||||||
|
that aren't reading/writing a specific file on the local system. If
|
||||||
|
you give it any shell command that outputs a number (possibly with a
|
||||||
|
K/M/G/T suffix), it will repeatedly run the command and show you how
|
||||||
|
fast that number is changing. If you give it the expected final value
|
||||||
|
of the number, it'll also estimate how much longer you have to wait.
|
||||||
|
It also has a specific option for tracking the total size of a
|
||||||
|
file or directory as given by `du`.
|
||||||
|
|
||||||
|
For example, here's `impatient` tracking an in-progress `zfs send` to
|
||||||
|
a remote machine:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ impatient -f "$(zfs list -pH -o used pool/home)" -c 'ssh remote-server zfs list -pH -o used remote-pool/backups/pool/home' -i 60
|
||||||
|
109.8G - 2.8M/s - 263.7G total - 41.6% complete - 15h03m remaining - ETA 2021-11-23 11:34
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `-f` is given the value output by `zfs list`; we could
|
||||||
|
give it a number directly, this just simplifies things in this
|
||||||
|
particular scenario. The `-p` flag for `zfs list` isn't strictly
|
||||||
|
necessary, `impatient` can parse values like `50.7G`, but
|
||||||
|
using the exact byte value provides more precision.
|
||||||
|
|
||||||
|
`-c`, on the other hand, is given a quoted string containing a
|
||||||
|
command, which will output the current progress value each time it's
|
||||||
|
run. The command given to `-c` can be an arbitrary shell one-liner,
|
||||||
|
use responsibly.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: impatient [-h] [-f FINAL] [-i INTERVAL] [-w WINDOW] (-p PATH | -c COMMAND)
|
||||||
|
|
||||||
|
Display progress and time estimates for arbitrary tasks
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-f FINAL, --final FINAL
|
||||||
|
Expected final size/value at completion, optionally with a K/M/G/T suffix
|
||||||
|
-i INTERVAL, --interval INTERVAL
|
||||||
|
Interval in seconds between samples (default 10)
|
||||||
|
-w WINDOW, --window WINDOW
|
||||||
|
Number of samples to keep for the sliding window (default 100)
|
||||||
|
-p PATH, --path PATH Track total disk usage of a given path
|
||||||
|
-c COMMAND, --command COMMAND
|
||||||
|
Track value returned by a shell command; this should return a single number, optionally with a K/M/G/T suffix
|
||||||
|
```
|
15
impatient
15
impatient
|
@ -6,16 +6,15 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
WINDOW_SIZE = 100
|
|
||||||
|
|
||||||
SUFFIXES = 'KMGT'
|
SUFFIXES = 'KMGT'
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Display progress and time estimates for arbitrary tasks')
|
parser = argparse.ArgumentParser(description='Display progress and time estimates for arbitrary tasks')
|
||||||
parser.add_argument('-f', '--final', type=str, help='Expected final size/value at completion.')
|
parser.add_argument('-f', '--final', type=str, help='Expected final size/value at completion, optionally with a K/M/G/T suffix')
|
||||||
parser.add_argument('-i', '--interval', type=int, default=10, help='Interval in seconds between samples (default 10)')
|
parser.add_argument('-i', '--interval', type=int, default=10, help='Interval in seconds between samples (default 10)')
|
||||||
|
parser.add_argument('-w', '--window', type=int, default=100, help='Number of samples to keep for the sliding window (default 100)')
|
||||||
tracker_types = parser.add_mutually_exclusive_group(required=True)
|
tracker_types = parser.add_mutually_exclusive_group(required=True)
|
||||||
tracker_types.add_argument('-p', '--path', type=str, help='Track total disk usage of a given path')
|
tracker_types.add_argument('-p', '--path', type=str, help='Track total disk usage of a given path')
|
||||||
tracker_types.add_argument('-c', '--command', type=str, help='Track value returned by a shell command; this should return a single number, optionally followed by K/M/G/T')
|
tracker_types.add_argument('-c', '--command', type=str, help='Track value returned by a shell command; this should return a single number, optionally with a K/M/G/T suffix')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -23,9 +22,9 @@ def parse_value(v):
|
||||||
suffix = v[-1].upper()
|
suffix = v[-1].upper()
|
||||||
if suffix in SUFFIXES:
|
if suffix in SUFFIXES:
|
||||||
exponent = 3*(SUFFIXES.find(suffix)+1)
|
exponent = 3*(SUFFIXES.find(suffix)+1)
|
||||||
return int(v[:-1])*(10**exponent)
|
return float(v[:-1])*(10**exponent)
|
||||||
else:
|
else:
|
||||||
return int(v)
|
return float(v)
|
||||||
|
|
||||||
def display_value(v):
|
def display_value(v):
|
||||||
suffix = ''
|
suffix = ''
|
||||||
|
@ -67,8 +66,8 @@ while True:
|
||||||
samples.append(current)
|
samples.append(current)
|
||||||
if len(samples) < 2:
|
if len(samples) < 2:
|
||||||
continue
|
continue
|
||||||
if len(samples) > WINDOW_SIZE:
|
if len(samples) > args.window:
|
||||||
samples = samples[-WINDOW_SIZE:]
|
samples = samples[-args.window:]
|
||||||
|
|
||||||
rate = (current - samples[0])/((len(samples)-1)*args.interval)
|
rate = (current - samples[0])/((len(samples)-1)*args.interval)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue