private void PushDirectory(LocalDirectory localDirectory, FtpPath ftpParentPath) { var ftpPath = ftpParentPath.GetChildPath(localDirectory.Name); FtpRetry.ConnectedCall(_mainClient, ftpParentPath.Absolute, c => c.CreateDirectory(localDirectory.Name)); PushDirectoryContents(localDirectory, ftpPath); }
private bool DeleteFtpDirectory(FtpPath path) { Log(path.Depth, ItemAction.Delete, path.Name); var parentWorkingDirectory = _remoteWorkingDirectory; var itemsRemain = false; foreach (var child in _mainClient.GetListing(path.Name, FtpListOption.AllFiles)) { var childPath = path.GetChildPath(child.Name); var exclude = MatchExcludes(childPath.Relative); if (exclude != null) { Log(path.Depth + 1, ItemAction.Skip, child.Name, $"excluded ({exclude.Original})"); itemsRemain = true; continue; } EnsureRemoteWorkingDirectory(path.Absolute); if (!DeleteFtpAny(childPath, child.Type)) { itemsRemain = true; } } EnsureRemoteWorkingDirectory(parentWorkingDirectory); if (itemsRemain) { Log(path.Depth + 1, ItemAction.Skip, $"# dir '{path.Name}' not deleted (items remain)"); return(false); } FtpRetry.ConnectedCall(_mainClient, parentWorkingDirectory, c => c.DeleteDirectory(path.Name)); return(true); }
private Task SynchronizeFileAsync(LocalFile localFile, FtpPath parentPath, FtpListItem remote) { if (remote == null) { Log(localFile.Depth, ItemAction.Add, localFile.Name); return(PushFileAsync(localFile)); } if (remote.Type == FtpFileSystemObjectType.Directory) { DeleteFtpDirectory(parentPath.GetChildPath(remote.Name)); Log(localFile.Depth, ItemAction.Replace, localFile.Name); return(PushFileAsync(localFile)); } if (remote.Type == FtpFileSystemObjectType.Link) { Log(localFile.Depth, ItemAction.Replace, localFile.Name, "remote is a link"); return(PushFileAsync(localFile)); } if (remote.Modified.ToLocalTime().TruncateToMinutes() != localFile.LastWriteTime.TruncateToMinutes()) { Log(localFile.Depth, ItemAction.Replace, localFile.Name); return(PushFileAsync(localFile)); } Log(localFile.Depth, ItemAction.Skip, localFile.Name); return(null); // I know it's bad style, but it optimizes the collection/wait for a common case when everything is up to date }
private void SynchronizeDirectory(LocalDirectory localDirectory, FtpPath ftpPath) { Log(localDirectory.Depth, ItemAction.Synchronize, localDirectory.Name); EnsureRemoteWorkingDirectory(ftpPath.Absolute); var allRemote = FtpRetry.ConnectedCall(_mainClient, ftpPath.Absolute, c => c.GetListing(".", FtpListOption.AllFiles)) .ToDictionary(l => l.Name, StringComparer.OrdinalIgnoreCase); var allRemoteFound = new HashSet <FtpListItem>(); var pushTasks = new List <Task>(); foreach (var local in localDirectory.EnumerateChildren()) { var remote = allRemote.GetValueOrDefault(local.Name); var exclude = MatchExcludes(local.RelativePath); if (exclude != null) { Log(localDirectory.Depth + 1, ItemAction.Skip, local.Name, $"excluded ({exclude.Original})"); allRemoteFound.Add(remote); continue; } EnsureRemoteWorkingDirectory(ftpPath.Absolute); if (remote != null) { allRemoteFound.Add(remote); } var localAsDirectory = local as LocalDirectory; if (localAsDirectory != null) { if (remote == null) { Log(localDirectory.Depth + 1, ItemAction.Add, localAsDirectory.Name); PushDirectory(localAsDirectory, ftpPath); continue; } if (remote.Type == FtpFileSystemObjectType.Directory) { SynchronizeDirectory(localAsDirectory, ftpPath.GetChildPath(remote.Name)); continue; } DeleteFtpFile(ftpPath.GetChildPath(remote.Name)); Log(localDirectory.Depth + 1, ItemAction.Add, localAsDirectory.Name); PushDirectory(localAsDirectory, ftpPath); continue; } var localAsFile = (LocalFile)local; var pushTask = SynchronizeFileAsync(localAsFile, ftpPath, remote); if (pushTask != null) { pushTasks.Add(pushTask); } } if (pushTasks.Count > 0) { Task.WaitAll(pushTasks.ToArray()); } EnsureRemoteWorkingDirectory(ftpPath.Absolute); foreach (var missing in allRemote.Values.Except(allRemoteFound)) { var missingPath = ftpPath.GetChildPath(missing.Name); var exclude = MatchExcludes(missingPath.Relative); if (exclude != null) { Log(localDirectory.Depth + 1, ItemAction.Skip, missing.Name, $"excluded ({exclude.Original})"); continue; } DeleteFtpAny(missingPath, missing.Type); } }