docs: def _file_op(source, destination, func, adapter, fatal, logger, must_exist=True, ignore=None):
      """Call func(source, destination)
  
      Args:
          source (str | None): Source file or folder
          destination (str | None): Destination file or folder
          func (callable): Implementation function
          adapter (callable | None): Optional function to call on 'source' before copy
          fatal (bool | None): Abort execution on failure if True
          logger (callable | None): Logger to use
          must_exist (bool): If True, verify that source does indeed exist
          ignore (callable | list | str | None): Names to be ignored
  
      Returns:
          (int): 1 if effectively done, 0 if no-op, -1 on failure
      """
      if not source or not destination or source == destination:
          return 0
  
      action = func.__name__[1:]
      indicator = "<-" if action == "symlink" else "->"
      psource = parent_folder(source)
      pdest = resolved_path(destination)
      if psource != pdest and psource.startswith(pdest):
          return abort(
              "Can't %s %s %s %s: source contained in destination", action, short(source), indicator, short(destination), fatal=(fatal, -1)
          )
  
      if is_dryrun():
          LOG.debug("Would %s %s %s %s", action, short(source), indicator, short(destination))
          return 1
  
      if must_exist and not os.path.exists(source):
          return abort("%s does not exist, can't %s to %s", short(source), action.title(), short(destination), fatal=(fatal, -1))
  
      try:
          # Delete destination, but ensure that its parent folder exists
          delete(destination, fatal=fatal, logger=None)
          ensure_folder(destination, fatal=fatal, logger=None)
  
          if logger:
              note = adapter(source, destination, fatal=fatal, logger=logger) if adapter else ""
              if logger:
                  logger("%s %s %s %s%s", action.title(), short(source), indicator, short(destination), note)
  
          if ignore is not None:
              if callable(ignore):
                  func(source, destination, ignore=ignore)
  
              else:
                  func(source, destination, ignore=lambda *_: ignore)
  
          else:
              func(source, destination)
  
          return 1
  
      except Exception as e:
          return abort("Can't %s %s %s %s: %s", action, short(source), indicator, short(destination), e, fatal=(fatal, -1))