'Copy file atomically (or at least try to).
This method tries to ensure that a file copy operation will not fail
if the destination file is removed during copy operation. The problem
is that copying a file is typically not an atomic operation.
Luckily moving files is atomic in almost every platform, assuming files
are on the same filesystem, and we can use that as a workaround:
- First move the source to a temporary directory that is ensured to
be on the same filesystem as the destination.
- Move the temporary file over the real destination.
See also https://github.com/robotframework/robotframework/issues/1502'

def _atomic_copy(self, source, destination):

    temp_directory = tempfile.mkdtemp(dir=os.path.dirname(destination))
    temp_file = os.path.join(temp_directory, os.path.basename(source))
    try:
        shutil.copy(source, temp_file)
        if os.path.exists(destination):
            os.remove(destination)
        shutil.move(temp_file, destination)
    finally:
        shutil.rmtree(temp_directory)
    return (source, destination)
