time estimator script
This commit is contained in:
commit
af7bb62a13
90
impatient
Executable file
90
impatient
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
WINDOW_SIZE = 100
|
||||||
|
|
||||||
|
SUFFIXES = 'KMGT'
|
||||||
|
|
||||||
|
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('-i', '--interval', type=int, default=10, help='Interval in seconds between samples (default 10)')
|
||||||
|
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('-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')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
def parse_value(v):
|
||||||
|
suffix = v[-1].upper()
|
||||||
|
if suffix in SUFFIXES:
|
||||||
|
exponent = 3*(SUFFIXES.find(suffix)+1)
|
||||||
|
return int(v[:-1])*(10**exponent)
|
||||||
|
else:
|
||||||
|
return int(v)
|
||||||
|
|
||||||
|
def display_value(v):
|
||||||
|
suffix = ''
|
||||||
|
for c in SUFFIXES:
|
||||||
|
if v < 10**3:
|
||||||
|
break
|
||||||
|
v = v / 10**3
|
||||||
|
suffix = c
|
||||||
|
return '{:.1f}{}'.format(v, suffix)
|
||||||
|
|
||||||
|
def display_timedelta(d):
|
||||||
|
result = ''
|
||||||
|
if d.days != 0:
|
||||||
|
result += '{}d'.format(d.days)
|
||||||
|
result += '{}h'.format(d.seconds // 3600)
|
||||||
|
result += '{}m'.format((d.seconds % 3600) // 60)
|
||||||
|
return result
|
||||||
|
|
||||||
|
if args.path:
|
||||||
|
def current_val():
|
||||||
|
du = subprocess.run(['du', '--bytes', '--summarize', args.path], capture_output=True, text=True).stdout
|
||||||
|
return parse_value(du.split()[0])
|
||||||
|
else:
|
||||||
|
def current_val():
|
||||||
|
result = subprocess.run(args.command, shell=True, capture_output=True, text=True).stdout
|
||||||
|
return parse_value(result.strip())
|
||||||
|
|
||||||
|
if args.final:
|
||||||
|
final = parse_value(args.final)
|
||||||
|
else:
|
||||||
|
final = None
|
||||||
|
|
||||||
|
samples = [current_val()]
|
||||||
|
while True:
|
||||||
|
time.sleep(args.interval)
|
||||||
|
|
||||||
|
current = current_val()
|
||||||
|
|
||||||
|
samples.append(current)
|
||||||
|
if len(samples) < 2:
|
||||||
|
continue
|
||||||
|
if len(samples) > WINDOW_SIZE:
|
||||||
|
samples = samples[-WINDOW_SIZE:]
|
||||||
|
|
||||||
|
rate = (current - samples[0])/((len(samples)-1)*args.interval)
|
||||||
|
|
||||||
|
print('\033[2K\r', end='')
|
||||||
|
print('{} - {}/s'.format(display_value(current), display_value(rate)), end='', flush=True)
|
||||||
|
if final:
|
||||||
|
fraction = current / final
|
||||||
|
value_remaining = final - current
|
||||||
|
time_remaining = datetime.timedelta(seconds=(value_remaining / rate))
|
||||||
|
eta = datetime.datetime.now() + time_remaining
|
||||||
|
print(' - {} total - {:.1f}% complete - {} remaining - ETA {}'.format(
|
||||||
|
display_value(final),
|
||||||
|
100*fraction,
|
||||||
|
display_timedelta(time_remaining),
|
||||||
|
eta.isoformat(sep=' ', timespec='minutes'),
|
||||||
|
), end='', flush=True)
|
||||||
|
|
||||||
|
if final and current >= final:
|
||||||
|
print()
|
||||||
|
break
|
Loading…
Reference in a new issue