mar10 / pyftpsync

Synchronize directories using FTP(S), SFTP, or file system access.
https://pyftpsync.readthedocs.io
MIT License
117 stars 25 forks source link

Cannot share local and remote targets for both upload and download synchronizers #20

Closed SeanDS closed 6 years ago

SeanDS commented 6 years ago

If I create:

local_target = FsTarget("/path/to/local/dir")
remote_target = FtpTarget(path="/path/to/remote/dir", host="ftp.example.com")

then use these targets for both an upload and a download synchronizer:

ftp_downloader = DownloadSynchronizer(local_target, remote_target)
ftp_uploader = UploadSynchronizer(local_target, remote_target)
ftp_downloader.run()
ftp_uploader.run()

this leads to the following error on the ftp_uploader.run() line:

RuntimeError: target is read-only: <ftp:ftp.example.com/path/to/remote/dir + .>

This is because the constructors for DownloadSynchronizer and UploadSynchronizer set the remote/local targets as readonly, respectively, without making a copy of the provided object. A simple hack to fix this is to explicitly set the local/remote targets in this case to non-readonly in between:

ftp_downloader = DownloadSynchronizer(local_target, remote_target)
ftp_uploader = UploadSynchronizer(local_target, remote_target)
ftp_downloader.run()
# HACK: set remote to non-readonly
remote_target.readonly = False
ftp_uploader.run()

It would probably be better if the constructor explicitly sets the read/write status of both the remote and local targets. For example, the DownloadSynchronizer would have:

def __init__(self, local, remote, options):
    super(DownloadSynchronizer, self).__init__(local, remote, options)
    local.readonly = False
    remote.readonly = True
mar10 commented 6 years ago

You're right, I didn't consider that targets could be re-used. (I set these flags as kind of paranoia guard.) Targets aren't thread safe either, maybe they should be locked by the synchronizer and the flags be reset after use...