# Path: pybatch/removeBatchCommands.py
# class RmFileOrDir(PythonBatchCommandBase):
#     """ remove a file or directory.
#     - it's OK if the path does not exist.
#     - all files and directory under path will be removed recursively
#     """
#     def __init__(self, path: os.PathLike, **kwargs):
#         super().__init__(**kwargs)
#         self.path: os.PathLike = path
#         self.exceptions_to_ignore.append(FileNotFoundError)
# 
#     def repr_own_args(self, all_args: List[str]) -> None:
#         all_args.append(self.unnamed__init__param(self.path))
# 
#     def progress_msg_self(self):
#         return f"""Remove '{self.path}'"""
# 
#     def __call__(self, *args, **kwargs):
#         resolved_path = None
#         retry = kwargs.get("retry", True)
#         try:
#             PythonBatchCommandBase.__call__(self, *args, **kwargs)
#             resolved_path = utils.ExpandAndResolvePath(self.path)
#             if resolved_path.is_symlink() or resolved_path.is_file():
#                 self.doing = f"""removing file'{resolved_path}'"""
#                 resolved_path.unlink()
#             elif resolved_path.is_dir():
#                 self.doing = f"""removing folder'{resolved_path}'"""
#                 shutil.rmtree(resolved_path, onerror=self.who_locks_file_error_dict)
#         except Exception as ex:
#             if retry and resolved_path is not None:
#                 kwargs["retry"] = False
#                 log.info(f"Fixing permission for removing {resolved_path}")
#                 from pybatch import FixAllPermissions
#                 with FixAllPermissions(resolved_path, recursive=True, report_own_progress=False) as allower:
#                     allower()
#                 self.__call__(*args, **kwargs)
#             else:
#                 raise


import os
import shutil
import utils
from collections import defaultdict
from pathlib import Path
from typing import List
from .fileSystemBatchCommands import *
from .removeBatchCommands import RmFileOrDir
            for no_hard_link_pattern in self.__all_no_hard_link_patterns:
                file_path = Path(a_file)  # todo: avoid using Path.match, since converting DirEntry toPath is not efficient
                if file_path.match(no_hard_link_pattern):
                    log.debug(f"not hard linking {a_file.path} because it matches pattern {no_hard_link_pattern}")
                    break
            else:
                retVal = True
        return retVal

    def should_no_flags_file(self, file_path: Path):
        retVal = True
        for no_flags_pattern in self.__all_no_flags_patterns:
            if file_path.match(no_flags_pattern):
                log.debug(f"removing flags from {file_path} because it matches pattern {no_flags_pattern}")
                break
        else:
            retVal = False
        return retVal

    def remove_extraneous_files(self, dst: Path, src_item_names):
        """ remove files in destination that are not in source.
            files in the ignore list are not removed even if they do not
            appear in the source.
        """

        for dst_item in os.scandir(dst):
            if dst_item.name not in src_item_names and not self.should_ignore_file(dst_item.path):
                self.last_step, self.last_src, self.last_dst = "remove redundant file", "", os.fspath(dst_item)
                log.info(f"delete {dst_item.path}")
                if not self.dry_run:

# Path: pybatch/removeBatchCommands.py
# class RmFileOrDir(PythonBatchCommandBase):
#     """ remove a file or directory.
#     - it's OK if the path does not exist.
#     - all files and directory under path will be removed recursively
#     """
#     def __init__(self, path: os.PathLike, **kwargs):
#         super().__init__(**kwargs)
#         self.path: os.PathLike = path
#         self.exceptions_to_ignore.append(FileNotFoundError)
# 
#     def repr_own_args(self, all_args: List[str]) -> None:
#         all_args.append(self.unnamed__init__param(self.path))
# 
#     def progress_msg_self(self):
#         return f"""Remove '{self.path}'"""
# 
#     def __call__(self, *args, **kwargs):
#         resolved_path = None
#         retry = kwargs.get("retry", True)
#         try:
#             PythonBatchCommandBase.__call__(self, *args, **kwargs)
#             resolved_path = utils.ExpandAndResolvePath(self.path)
#             if resolved_path.is_symlink() or resolved_path.is_file():
#                 self.doing = f"""removing file'{resolved_path}'"""
#                 resolved_path.unlink()
#             elif resolved_path.is_dir():
#                 self.doing = f"""removing folder'{resolved_path}'"""
#                 shutil.rmtree(resolved_path, onerror=self.who_locks_file_error_dict)
#         except Exception as ex:
#             if retry and resolved_path is not None:
#                 kwargs["retry"] = False
#                 log.info(f"Fixing permission for removing {resolved_path}")
#                 from pybatch import FixAllPermissions
#                 with FixAllPermissions(resolved_path, recursive=True, report_own_progress=False) as allower:
#                     allower()
#                 self.__call__(*args, **kwargs)
#             else:
#                 raise


# Path: pybatch/copyBatchCommands.py
import os
import shutil
import utils
from collections import defaultdict
from pathlib import Path
from typing import List
from .fileSystemBatchCommands import *
from .removeBatchCommands import RmFileOrDir

            for no_hard_link_pattern in self.__all_no_hard_link_patterns:
                file_path = Path(a_file)  # todo: avoid using Path.match, since converting DirEntry toPath is not efficient
                if file_path.match(no_hard_link_pattern):
                    log.debug(f"not hard linking {a_file.path} because it matches pattern {no_hard_link_pattern}")
                    break
            else:
                retVal = True
        return retVal

    def should_no_flags_file(self, file_path: Path):
        retVal = True
        for no_flags_pattern in self.__all_no_flags_patterns:
            if file_path.match(no_flags_pattern):
                log.debug(f"removing flags from {file_path} because it matches pattern {no_flags_pattern}")
                break
        else:
            retVal = False
        return retVal

    def remove_extraneous_files(self, dst: Path, src_item_names):
        """ remove files in destination that are not in source.
            files in the ignore list are not removed even if they do not
            appear in the source.
        """

        for dst_item in os.scandir(dst):
            if dst_item.name not in src_item_names and not self.should_ignore_file(dst_item.path):
                self.last_step, self.last_src, self.last_dst = "remove redundant file", "", os.fspath(dst_item)
                log.info(f"delete {dst_item.path}")
                if not self.dry_run:

                    with RmFileOrDir(dst_item, report_own_progress=False, resolve_path=not dst_item.is_symlink()) as rfod: