import os
import errno
from math import log


def human_size(num):
    """Human friendly file size"""
    unit_list = list(zip(['bytes', 'kiB', 'MiB', 'GiB', 'TiB'],
                         [0, 0, 1, 2, 2]))
    if num == 0:
        return '0 bytes'
    if num == 1:
        return '1 byte'
    exponent = min(int(log(num, 1024)), len(unit_list) - 1)
    quotient = float(num) / 1024**exponent
    unit, num_decimals = unit_list[exponent]
    format_string = '{:.%sf} {}' % (num_decimals)
    return format_string.format(quotient, unit)


def du(path):
    """Like du -sb, returns total size of path in bytes.  Ignore
    errors that might occur if we encounter broken symlinks or
    files in the process of being removed."""
    try:
        st = os.stat(path)
        size = st.st_blocks * 512
        if os.path.isdir(path):
            for thisfile in os.listdir(path):
                filepath = os.path.join(path, thisfile)
                size += du(filepath)
        return size
    except OSError as e:
        if e.errno != errno.ENOENT:
            raise
        return 0
