public async Task BuildSolutionsAsync(IEnumerable <ISolutionProjectModel> projectViewModels, IServiceSettings settings, CancellationToken cancellationToken = default(CancellationToken)) { bool delphiCancelRegistered = false, allDone = false; IDictionary <string, string> envVars = null; var projects = projectViewModels.ToList(); await cancellationToken.WaitWhenPaused(); #region Merge Solutions perhaps var mergedResult = await MergeContingentAsync(projects.ToArray(), settings, cancellationToken); if (mergedResult != null && mergedResult.Item1.Any()) // Something is merged { projects.RemoveRange(mergedResult.Item2); await serviceProvider.Get <NugetRestoreService>().ExecuteAsync(mergedResult.Item1, settings, cancellationToken); projects.AddRange(mergedResult.Item1); } #endregion if (!IsCancelled(projects, cancellationToken)) { try { statusService.InitOrAttach(projects.Count, $"Building {projects.Count} Solutions"); var externalActionService = serviceProvider.Get <ExternalActionService>(); await cancellationToken.WaitWhenPaused(); projects.SetOperations(Operations.Queued); envVars = await RegisterBDSRequiredEnvVarsAsync(projects.Any(model => model.IsDelphiProject), settings); Output.ClearTasks(!serviceProvider.Get <MainLogic>().IsCompleteRunning); var buildManager = new BuildManager("CheckoutAndBuildBuilder"); cancellationToken.Register(() => { if (!allDone) { buildManager.CancelAllSubmissions(); } }); var logger = new TraceLogger(settings.LogLevel, cancellationToken); BuildParameters buildParameters = GetBuildParameters(logger); buildManager.BeginBuild(buildParameters); foreach (IGrouping <int, ISolutionProjectModel> g in from m in projects orderby m.BuildPriority group m by m.BuildPriority) { if (cancellationToken.IsCancellationRequested) { break; } var submissions = new Dictionary <BuildSubmission, ISolutionProjectModel>(); var buildResults = new List <Task <BuildResult> >(); await cancellationToken.WaitWhenPaused(); foreach (ISolutionProjectModel solution in g.Where(model => !IsCancelled(model))) { await cancellationToken.WaitWhenPaused(); if (cancellationToken.IsCancellationRequested) { break; } var properties = GetBuildProperties(solution, settings); var buildRequestData = new BuildRequestData(solution.ItemPath, properties, null, GetBuildTargets(solution), buildParameters.HostServices); submissions.Add(buildManager.PendBuildRequest(buildRequestData), solution); } using (TrackProgress(submissions, logger)) { foreach (KeyValuePair <BuildSubmission, ISolutionProjectModel> pair in submissions.Where(pair => !IsCancelled(pair.Value))) { var project = pair.Value; var buildServiceSettings = settings.GetSettingsFromProvider <BuildServiceSettings>(project); await cancellationToken.WaitWhenPaused(); if (cancellationToken.IsCancellationRequested) { Output.WriteLine("Cancelled Build for " + project.ItemPath); project.CurrentOperation = Operations.None; break; } await cancellationToken.WaitWhenPaused(); project.CurrentOperation = !project.IsDelphiProject ? Operations.Build : Operations.BuildIndeterminate; await externalActionService.RunExternalPreActions(project, this, cancellationToken : cancellationToken); if (buildServiceSettings.KillDependendProcesses) { await project.KillRunningInstancesAsync(true, cancellationToken); } if (project.IsDelphiProject && !delphiCancelRegistered) { delphiCancelRegistered = true; cancellationToken.Register(KillDelphiCompiler); } TaskCompletionSource <BuildResult> tcs = new TaskCompletionSource <BuildResult>(); if (!IsCancelled(pair.Value)) { pair.Key.ExecuteAsync(buildSubmission => SetTaskCompletionResult(buildSubmission, tcs), null); await cancellationToken.WaitWhenPaused(); var task = tcs.Task.ContinueWith(async t => { var buildResult = t.Result; await externalActionService.RunExternalPostActions(project, this, t.Result, settings, cancellationToken); await cancellationToken.WaitWhenPaused(); statusService.IncrementStep(); Output.WriteLine("Finished Build for " + project.ItemPath + " " + buildResult.OverallResult); project.CurrentOperation = Operations.None; if (buildResult.OverallResult == BuildResultCode.Failure) { project.SetResult(new ValidationResult(false, GetErrorsViewModel(project, buildResult))); if (buildServiceSettings.CancelQueuedOnFailures) { serviceProvider.Get <MainViewModel>().CompleteCancelCommand.Execute(null); } } else { project.SetResult(ValidationResult.ValidResult); } return(buildResult); }, cancellationToken, TaskContinuationOptions.NotOnCanceled, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()).Unwrap(); buildResults.Add(task); } } await Check.TryCatchAsync <TaskCanceledException>(Task.WhenAll(buildResults)); } } allDone = true; if (!cancellationToken.IsCancellationRequested) { await buildManager.EndBuildAsync(cancellationToken); } } catch (Exception e) { Output.Exception(e); } finally { #region Finalize #pragma warning disable 4014 // Result doesn't matter EnvironmentHelper.RemoveVariablesAsync(envVars); #pragma warning restore 4014 await cancellationToken.WaitWhenPaused(); projects.Where(model => model.ErrorContent == null).Apply(model => model.SetDefaultImageValues()); projects.SetOperations(Operations.None); mergedResult?.Item2.SetOperations(Operations.None); mergedResult?.Item1.Apply(model => { model.ParentWorkingFolder.RemoveCustomProject(model, true); if (model.Result == ValidationResult.ValidResult) { File.Delete(model.ItemPath); } else { Output.ActionLink($"Build Failed: delete Temporary Build Solution {model.SolutionFileName}?", () => File.Delete(model.ItemPath), NotificationType.Error, $"Click here to delete temporary merged Build Solution {model.SolutionFileName}"); } }); #endregion } } }