def copytree_with_hash(
    src_path: Union[Path, str],
    dst_path: Union[Path, str],
    buffer_size=1024 * 1024,
    hash: Optional[hashlib.sha256] = None,
    max_depth: int = 20,
) -> Optional[str]:
    """Copy a directory and its contents recursively, while at the same time calculating a hash over each file and filename.

    :param src_path: Path: The path to the source directory.
    :param dst_path: Path: The path to the destination directory.
    :param buffer_size: int: The buffer size to read and write data in.
    :param hash: Optional[hashlib.sha256]: The hash to use for calculating the hash. ( Default: None)
    :max_depth: int : The maximum recursion depth. Default: 20
    :return: None, if a hash instance was passed. Otherwise, the hash of the copied data and path names.
    """

    if hash is None:
        hash_obj = hashlib.sha256()
    else:
        hash_obj = hash
    if isinstance(src_path, str):
        src_path = Path(src_path)
    if isinstance(dst_path, str):
        dst_path = Path(dst_path)
    if dst_path.exists():
        dst_path = dst_path.resolve()
        if not dst_path.is_dir():
            raise OSError("Target path exists and is not a directory.")
        dst_path = dst_path / src_path.name
    if src_path.is_file():
        hash_obj.update(dst_path.name.encode("utf-8"))
        # Copy the file to the destination
        with open(dst_path, "wb") as dst_file:
            with open(src_path, "rb") as src_file:
                while True:
                    data = src_file.read(buffer_size)
                    if not data:
                        break
                    hash_obj.update(data)
                    dst_file.write(data)
    elif src_path.is_symlink():
        new_src_path = src_path.resolve()
        copytree_with_hash(new_src_path, dst_path, buffer_size, hash_obj, max_depth - 1)
    elif src_path.is_dir():
        # Recursively copy the directory contents
        os.makedirs(dst_path, exist_ok=True)
        for sub_path in sorted(src_path.iterdir()):
            sub_dst_path = dst_path / sub_path.name
            copytree_with_hash(
                sub_path, sub_dst_path, buffer_size, hash_obj, max_depth - 1
            )
    else:
        raise OSError(f"Source path {src_path} is neither file, directory nor symlink.")
    if hash is None:
        return hash_obj.hexdigest()
Copy a directory and its contents recursively, while at the same time calculating a hash over each file and filename.

:param src_path: Path: The path to the source directory.
:param dst_path: Path: The path to the destination directory.
:param buffer_size: int: The buffer size to read and write data in.
:param hash: Optional[hashlib.sha256]: The hash to use for calculating the hash. ( Default: None)
:max_depth: int : The maximum recursion depth. Default: 20
:return: None, if a hash instance was passed. Otherwise, the hash of the copied data and path names.
python/aitemplate/utils/io.py