#!/usr/bin/env python3 import argparse import sys import os import datetime def is_digit(d): try: d = int(d) return True except ValueError: return False def is_numerical(f): try: f = float(f) return True except ValueError: return False def get_files_size(path): if not os.path.exists(path): return None if os.path.isfile(path): return float(os.path.getsize(path)) total_size = 0 for dirpath, dirnames, filenames in os.walk(path): for f in filenames: fp = os.path.join(dirpath, f) total_size += os.path.getsize(fp) return float(total_size) def get_numerical(num_string): num_string = num_string.lower() numerical_part = "" last_digit = 0 for i, c in enumerate(num_string): if is_digit(c): last_digit = i + 1 numerical_part = num_string[0:last_digit] if not is_numerical(numerical_part): return None, None return numerical_part, last_digit def parse_options(): parser = argparse.ArgumentParser( description="Transfer time calculator", epilog="You may omit the 'b' to time events. ex. '20 minutes / task, 7 tasks to do': %(prog)s 3/h 7", ) parser.add_argument( "-r", dest="rate", help="Rate: inverse of speed. Instead of 10b/s, write 0.1s/b", action="store_true", default=False, ) parser.add_argument( "speed", help="Speed of transfer (ex. 3.2Mb/s). Time units: s, m, h, d, w" ) parser.add_argument( "size", help="Data size (ex. 4.55GB), or folder/file path. Units: b, kb, mb, gb, tb, pb or kib, mib ... ", ) return parser.parse_args() def parse_rate(rate_string): if not "/" in rate_string: return None (divisor_string, divider_string) = rate_string.split("/", 1) numerical_part, last_digit = get_numerical(divisor_string) if not is_numerical(numerical_part): return None numerical_part = float(numerical_part) multiplier = divisor_string[last_digit:] divider = parse_size("1" + divider_string) if divider == None: # Cannot parse return divider if multiplier == "s": return divider / 1 / numerical_part if multiplier == "m": return divider / 60 / numerical_part if multiplier == "h": return divider / 3600 / numerical_part if multiplier == "d": return divider / (24 * 3600) / numerical_part return None def parse_size(size_string): numerical_part, last_digit = get_numerical(size_string) if not is_numerical(numerical_part): return None numerical_part = float(numerical_part) multiplier_part = size_string[last_digit:] if multiplier_part in ("b", ""): return numerical_part if multiplier_part == "kb": return 1024 * numerical_part if multiplier_part == "mb": return 1024 ** 2 * numerical_part if multiplier_part == "gb": return 1024 ** 3 * numerical_part if multiplier_part == "tb": return 1024 ** 4 * numerical_part if multiplier_part == "pb": return 1024 ** 5 * numerical_part if multiplier_part == "kib": return 1000 * numerical_part if multiplier_part == "mib": return 1000 ** 2 * numerical_part if multiplier_part == "gib": return 1000 ** 3 * numerical_part if multiplier_part == "tib": return 1000 ** 4 * numerical_part if multiplier_part == "pib": return 1000 ** 5 * numerical_part return None def parse_speed(speed_string): if not "/" in speed_string: return None (divisor_string, divider_string) = speed_string.split("/", 1) divisor = parse_size(divisor_string) if divisor == None: # Cannot parse return divisor if divider_string == "s": return divisor if divider_string == "m": return divisor / 60 if divider_string == "h": return divisor / 3600 if divider_string == "d": return divisor / (24 * 3600) return None def print_err(s): sys.stderr.write(str(s) + "\n") sys.stderr.flush() def time_human(num): return str(datetime.timedelta(seconds=num)) if __name__ == "__main__": opts = parse_options() if opts.rate: speed = parse_rate(opts.speed.lower()) if speed == None: print_err("Cannot parse rate ( ex. 3.5s/kb )") print_err("Rate: %s" % (opts.speed,)) sys.exit(1) else: speed = parse_speed(opts.speed.lower()) if speed == None: print_err("Cannot parse speed ( ex. 3.5Mb/s )") print_err("Speed: %s" % (opts.speed,)) sys.exit(1) if os.path.isfile(opts.size): size = get_files_size(opts.size) else: size = parse_size(opts.size.lower()) if size == None: print_err( "Cannot parse size, and it's not a path either ( ex. 11Gb / file.name )" ) print_err("Size: %s" % (opts.size,)) sys.exit(1) print(time_human(round(size / speed)))