private void ApplyChanges(DropboxHandler.DropboxInfo deploymentInfo) { DropboxDeployInfo info = deploymentInfo.DeployInfo; Semaphore sem = new Semaphore(MaxConcurrentRequests, MaxConcurrentRequests); List<Task> tasks = new List<Task>(); string parent = info.Path.TrimEnd('/') + '/'; DateTime updateMessageTime = DateTime.UtcNow; int totals = info.Deltas.Count(); var rateLimiter = new RateLimiter(MaxFilesPerSecs * 10, TimeSpan.FromSeconds(10)); foreach (DropboxDeltaInfo delta in info.Deltas) { if (!delta.Path.StartsWith(parent, StringComparison.OrdinalIgnoreCase)) { Interlocked.Increment(ref _successCount); continue; } // Ignore .git and .hg files and folders string pathWithSlash = delta.Path + "/"; if (pathWithSlash.StartsWith(parent + ".git/", StringComparison.OrdinalIgnoreCase) || pathWithSlash.StartsWith(parent + ".hg/", StringComparison.OrdinalIgnoreCase)) { continue; } var path = delta.Path; if (delta.IsDeleted) { SafeDelete(parent, path); Interlocked.Increment(ref _successCount); } else if (delta.IsDirectory) { SafeCreateDir(parent, path); Interlocked.Increment(ref _successCount); } else { DateTime modified = DateTime.Parse(delta.Modified).ToUniversalTime(); if (!IsFileChanged(parent, path, modified)) { LogInfo("file unchanged {0}", path); Interlocked.Increment(ref _successCount); continue; } // throttle concurrent get file dropbox sem.WaitOne(); Task task; try { // Using ContinueWith instead of Then to avoid SyncContext deadlock in 4.5 task = GetFileAsync(info, delta).ContinueWith(t => { rateLimiter.Throtte(); sem.Release(); if (!t.IsFaulted && !t.IsCanceled) { using (StreamInfo streamInfo = t.Result) { SafeWriteFile(parent, path, streamInfo.Stream, modified); } Interlocked.Increment(ref _successCount); Interlocked.Increment(ref _fileCount); } else { Interlocked.Increment(ref _failedCount); } if (DateTime.UtcNow.Subtract(updateMessageTime) > TimeSpan.FromSeconds(5)) { lock (_status) { _status.Open(deploymentInfo.TargetChangeset.Id).UpdateProgress( String.Format(CultureInfo.CurrentUICulture, _failedCount == 0 ? Resources.Dropbox_SynchronizingProgress : Resources.Dropbox_SynchronizingProgressWithFailure, ((_successCount + _failedCount) * 100) / totals, totals, _failedCount)); } updateMessageTime = DateTime.UtcNow; } return t; }).FastUnwrap(); } catch (Exception ex) { sem.Release(); LogError("{0}", ex); Task.WaitAll(tasks.ToArray(), _timeout); throw; } tasks.Add(task); } } if (!Task.WaitAll(tasks.ToArray(), _timeout)) { throw new TimeoutException(RS.Format(Resources.Error_SyncDropboxTimeout, (int)_timeout.TotalSeconds)); } }
internal ChangeSet Sync(DropboxHandler.DropboxInfo deploymentInfo, string branch, ILogger logger, IRepository repository) { DropboxDeployInfo info = deploymentInfo.DeployInfo; _logger = logger; _successCount = 0; _fileCount = 0; _failedCount = 0; _retriedCount = 0; if (_settings.GetValue(CursorKey) != info.OldCursor) { throw new InvalidOperationException(Resources.Error_MismatchDropboxCursor); } if (!repository.IsEmpty()) { // git checkout --force <branch> repository.ClearLock(); repository.Update(branch); } ChangeSet changeSet; string message = null; try { using (_tracer.Step("Synch with Dropbox")) { // Sync dropbox => repository directory ApplyChanges(deploymentInfo); } message = String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_Synchronized, deploymentInfo.DeployInfo.Deltas.Count()); } catch (Exception) { message = String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_SynchronizedWithFailure, _successCount, deploymentInfo.DeployInfo.Deltas.Count(), _failedCount); throw; } finally { _logger.Log(message); _logger.Log(String.Format("{0} downloaded files, {1} successful retries.", _fileCount, _retriedCount)); _status.Open(deploymentInfo.TargetChangeset.Id).UpdateMessage(message); _status.Open(deploymentInfo.TargetChangeset.Id).UpdateProgress(String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_Committing, _successCount)); // Commit anyway even partial change changeSet = repository.Commit(message, String.Format("{0} <{1}>", info.UserName, info.Email)); } // Save new dropboc cursor LogInfo("Update dropbox cursor"); _settings.SetValue(CursorKey, info.NewCursor); return changeSet; }
private async Task ApplyChanges(DropboxHandler.DropboxInfo deploymentInfo) { DropboxDeployInfo info = deploymentInfo.DeployInfo; _totals = info.Deltas.Count; using (new Timer(UpdateStatusFile, state: deploymentInfo.TargetChangeset.Id, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5))) { await ApplyChangesCore(info); } }