Exemple #1
0
    def test_replace_file(self):
        workdir = fileutil.abspath_expanduser_unicode(u"test_replace_file")
        fileutil.make_dirs(workdir)

        replaced_path = os.path.join(workdir, "replaced")
        replacement_path = os.path.join(workdir, "replacement")

        # when none of the files exist
        self.failUnlessRaises(fileutil.ConflictError, fileutil.replace_file,
                              replaced_path, replacement_path)

        # when only replaced exists
        fileutil.write(replaced_path, b"foo")
        self.failUnlessRaises(fileutil.ConflictError, fileutil.replace_file,
                              replaced_path, replacement_path)
        self.failUnlessEqual(fileutil.read(replaced_path), b"foo")

        # when both replaced and replacement exist
        fileutil.write(replacement_path, b"bar")
        fileutil.replace_file(replaced_path, replacement_path)
        self.failUnlessEqual(fileutil.read(replaced_path), b"bar")
        self.failIf(os.path.exists(replacement_path))

        # when only replacement exists
        os.remove(replaced_path)
        fileutil.write(replacement_path, b"bar")
        fileutil.replace_file(replaced_path, replacement_path)
        self.failUnlessEqual(fileutil.read(replaced_path), b"bar")
        self.failIf(os.path.exists(replacement_path))
Exemple #2
0
    def _write_downloaded_file(self,
                               local_path_u,
                               abspath_u,
                               file_contents,
                               is_conflict=False,
                               now=None):
        self._log(
            "_write_downloaded_file(%r, <%d bytes>, is_conflict=%r, now=%r)" %
            (abspath_u, len(file_contents), is_conflict, now))

        # 1. Write a temporary file, say .foo.tmp.
        # 2. is_conflict determines whether this is an overwrite or a conflict.
        # 3. Set the mtime of the replacement file to be T seconds before the
        #    current local time.
        # 4. Perform a file replacement with backup filename foo.backup,
        #    replaced file foo, and replacement file .foo.tmp. If any step of
        #    this operation fails, reclassify as a conflict and stop.
        #
        # Returns the path of the destination file.

        precondition_abspath(abspath_u)
        replacement_path_u = abspath_u + u".tmp"  # FIXME more unique
        backup_path_u = abspath_u + u".backup"
        if now is None:
            now = time.time()

        initial_path_u = os.path.dirname(abspath_u)
        fileutil.make_dirs_with_absolute_mode(local_path_u, initial_path_u,
                                              (~self._umask) & 0777)
        fileutil.write(replacement_path_u, file_contents)
        os.chmod(replacement_path_u, (~self._umask) & 0777)

        # FUDGE_SECONDS is used to determine if another process
        # has written to the same file concurrently. This is described
        # in the Earth Dragon section of our design document:
        # docs/proposed/magic-folder/remote-to-local-sync.rst
        os.utime(replacement_path_u, (now, now - self.FUDGE_SECONDS))
        if is_conflict:
            return self._rename_conflicted_file(abspath_u, replacement_path_u)
        else:
            try:
                fileutil.replace_file(abspath_u, replacement_path_u,
                                      backup_path_u)
                return abspath_u
            except fileutil.ConflictError:
                return self._rename_conflicted_file(abspath_u,
                                                    replacement_path_u)
    def _write_downloaded_file(self, local_path_u, abspath_u, file_contents, is_conflict=False, now=None):
        self._log("_write_downloaded_file(%r, <%d bytes>, is_conflict=%r, now=%r)"
                  % (abspath_u, len(file_contents), is_conflict, now))

        # 1. Write a temporary file, say .foo.tmp.
        # 2. is_conflict determines whether this is an overwrite or a conflict.
        # 3. Set the mtime of the replacement file to be T seconds before the
        #    current local time.
        # 4. Perform a file replacement with backup filename foo.backup,
        #    replaced file foo, and replacement file .foo.tmp. If any step of
        #    this operation fails, reclassify as a conflict and stop.
        #
        # Returns the path of the destination file.

        precondition_abspath(abspath_u)
        replacement_path_u = abspath_u + u".tmp"  # FIXME more unique
        backup_path_u = abspath_u + u".backup"
        if now is None:
            now = time.time()

        initial_path_u = os.path.dirname(abspath_u)
        fileutil.make_dirs_with_absolute_mode(local_path_u, initial_path_u, (~ self._umask) & 0777)
        fileutil.write(replacement_path_u, file_contents)
        os.chmod(replacement_path_u, (~ self._umask) & 0777)

        # FUDGE_SECONDS is used to determine if another process
        # has written to the same file concurrently. This is described
        # in the Earth Dragon section of our design document:
        # docs/proposed/magic-folder/remote-to-local-sync.rst
        os.utime(replacement_path_u, (now, now - self.FUDGE_SECONDS))
        if is_conflict:
            return self._rename_conflicted_file(abspath_u, replacement_path_u)
        else:
            try:
                fileutil.replace_file(abspath_u, replacement_path_u, backup_path_u)
                return abspath_u
            except fileutil.ConflictError:
                return self._rename_conflicted_file(abspath_u, replacement_path_u)