Ejemplo n.º 1
0
        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
                }
            }
        }