mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 21:43:09 +00:00
Refactoring to allow logging from _write_downloaded_file and _rename_conflicted_file.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
parent
6cb41cadf5
commit
a3fa1617c2
@ -400,7 +400,54 @@ class Uploader(QueueMixin):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
class Downloader(QueueMixin):
|
class WriteFileMixin(object):
|
||||||
|
FUDGE_SECONDS = 10.0
|
||||||
|
|
||||||
|
def _write_downloaded_file(self, 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()
|
||||||
|
|
||||||
|
# ensure parent directory exists
|
||||||
|
head, tail = os.path.split(abspath_u)
|
||||||
|
mode = 0777 # XXX
|
||||||
|
fileutil.make_dirs(head, mode)
|
||||||
|
|
||||||
|
fileutil.write(replacement_path_u, file_contents)
|
||||||
|
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 _rename_conflicted_file(self, abspath_u, replacement_path_u):
|
||||||
|
self._log("_rename_conflicted_file(%r, %r)" % (abspath_u, replacement_path_u))
|
||||||
|
|
||||||
|
conflict_path_u = abspath_u + u".conflict"
|
||||||
|
fileutil.rename_no_overwrite(replacement_path_u, conflict_path_u)
|
||||||
|
return conflict_path_u
|
||||||
|
|
||||||
|
|
||||||
|
class Downloader(QueueMixin, WriteFileMixin):
|
||||||
REMOTE_SCAN_INTERVAL = 3 # facilitates tests
|
REMOTE_SCAN_INTERVAL = 3 # facilitates tests
|
||||||
|
|
||||||
def __init__(self, client, local_path_u, db, collective_dircap, clock):
|
def __init__(self, client, local_path_u, db, collective_dircap, clock):
|
||||||
@ -589,45 +636,3 @@ class Downloader(QueueMixin):
|
|||||||
return res
|
return res
|
||||||
d.addBoth(remove_from_pending)
|
d.addBoth(remove_from_pending)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
FUDGE_SECONDS = 10.0
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _write_downloaded_file(cls, abspath_u, file_contents, is_conflict=False, now=None):
|
|
||||||
# 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()
|
|
||||||
|
|
||||||
# ensure parent directory exists
|
|
||||||
head, tail = os.path.split(abspath_u)
|
|
||||||
mode = 0777 # XXX
|
|
||||||
fileutil.make_dirs(head, mode)
|
|
||||||
|
|
||||||
fileutil.write(replacement_path_u, file_contents)
|
|
||||||
os.utime(replacement_path_u, (now, now - cls.FUDGE_SECONDS))
|
|
||||||
if is_conflict:
|
|
||||||
return cls._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 cls._rename_conflicted_file(abspath_u, replacement_path_u)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _rename_conflicted_file(self, abspath_u, replacement_path_u):
|
|
||||||
conflict_path_u = abspath_u + u".conflict"
|
|
||||||
fileutil.rename_no_overwrite(replacement_path_u, conflict_path_u)
|
|
||||||
return conflict_path_u
|
|
||||||
|
@ -16,7 +16,7 @@ from allmydata.test.common import ShouldFailMixin
|
|||||||
from .test_cli_magic_folder import MagicFolderCLITestMixin
|
from .test_cli_magic_folder import MagicFolderCLITestMixin
|
||||||
|
|
||||||
from allmydata.frontends import magic_folder
|
from allmydata.frontends import magic_folder
|
||||||
from allmydata.frontends.magic_folder import MagicFolder, Downloader
|
from allmydata.frontends.magic_folder import MagicFolder, Downloader, WriteFileMixin
|
||||||
from allmydata import magicfolderdb, magicpath
|
from allmydata import magicfolderdb, magicpath
|
||||||
from allmydata.util.fileutil import abspath_expanduser_unicode
|
from allmydata.util.fileutil import abspath_expanduser_unicode
|
||||||
|
|
||||||
@ -482,13 +482,19 @@ class MockTest(MagicFolderTestMixin, unittest.TestCase):
|
|||||||
workdir = u"cli/MagicFolder/write-downloaded-file"
|
workdir = u"cli/MagicFolder/write-downloaded-file"
|
||||||
local_file = fileutil.abspath_expanduser_unicode(os.path.join(workdir, "foobar"))
|
local_file = fileutil.abspath_expanduser_unicode(os.path.join(workdir, "foobar"))
|
||||||
|
|
||||||
|
class TestWriteFileMixin(WriteFileMixin):
|
||||||
|
def _log(self, msg):
|
||||||
|
pass
|
||||||
|
|
||||||
|
writefile = TestWriteFileMixin()
|
||||||
|
|
||||||
# create a file with name "foobar" with content "foo"
|
# create a file with name "foobar" with content "foo"
|
||||||
# write downloaded file content "bar" into "foobar" with is_conflict = False
|
# write downloaded file content "bar" into "foobar" with is_conflict = False
|
||||||
fileutil.make_dirs(workdir)
|
fileutil.make_dirs(workdir)
|
||||||
fileutil.write(local_file, "foo")
|
fileutil.write(local_file, "foo")
|
||||||
|
|
||||||
# if is_conflict is False, then the .conflict file shouldn't exist.
|
# if is_conflict is False, then the .conflict file shouldn't exist.
|
||||||
Downloader._write_downloaded_file(local_file, "bar", False, None)
|
writefile._write_downloaded_file(local_file, "bar", False, None)
|
||||||
conflicted_path = local_file + u".conflict"
|
conflicted_path = local_file + u".conflict"
|
||||||
self.failIf(os.path.exists(conflicted_path))
|
self.failIf(os.path.exists(conflicted_path))
|
||||||
|
|
||||||
@ -504,7 +510,7 @@ class MockTest(MagicFolderTestMixin, unittest.TestCase):
|
|||||||
self.failUnlessEqual(fileutil.read(local_file), "bar")
|
self.failUnlessEqual(fileutil.read(local_file), "bar")
|
||||||
|
|
||||||
# now a test for conflicted case
|
# now a test for conflicted case
|
||||||
Downloader._write_downloaded_file(local_file, "bar", True, None)
|
writefile._write_downloaded_file(local_file, "bar", True, None)
|
||||||
self.failUnless(os.path.exists(conflicted_path))
|
self.failUnless(os.path.exists(conflicted_path))
|
||||||
|
|
||||||
# .tmp file shouldn't exist
|
# .tmp file shouldn't exist
|
||||||
|
Loading…
Reference in New Issue
Block a user