Returns a hash of all of the given files at the given root.

    Args:
        files (list[str]): file names to include in the hash calculation,
            relative to ``root``.
        root (str): base directory to analyze files in.

    Returns:
        str: A hash of the hashes of the given files.

def _calculate_hash(files, root):
    """ Returns a hash of all of the given files at the given root.

    Args:
        files (list[str]): file names to include in the hash calculation,
            relative to ``root``.
        root (str): base directory to analyze files in.

    Returns:
        str: A hash of the hashes of the given files.
    """
    file_hash = hashlib.md5()
    for fname in sorted(files):
        f = os.path.join(root, fname)
        file_hash.update((fname + "\0").encode())
        with open(f, "rb") as fd:
            for chunk in iter(lambda: fd.read(4096), ""):
                if not chunk:
                    break
                file_hash.update(chunk)
            file_hash.update("\0".encode())

    return file_hash.hexdigest()