commit af7bb62a13095006fa28169ec6a55eb911fbcaa8 Author: xenofem Date: Mon Nov 22 20:04:12 2021 -0500 time estimator script diff --git a/impatient b/impatient new file mode 100755 index 0000000..eeaea7f --- /dev/null +++ b/impatient @@ -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