internal bool ShouldExecute(IExecuteContext executeContext, CommandResultEntry[] previousResultCollection, ObjectId commandHash, out CommandResultEntry matchingResult) { IndexFileCommand.MountDatabases(executeContext); try { matchingResult = FindMatchingResult(executeContext, previousResultCollection); } finally { IndexFileCommand.UnmountDatabases(executeContext); } if (matchingResult == null || Command.ShouldForceExecution()) { // Ensure we ignore existing results if the execution is forced matchingResult = null; return(true); } return(false); }
/// <summary> /// Associate the given <see cref="ResultStatus" /> object as the result of the current step and execute the <see cref="StepProcessed"/> event. /// </summary> /// <param name="executeContext">The execute context.</param> /// <param name="status">The result status.</param> internal void RegisterResult(IExecuteContext executeContext, ResultStatus status) { Status = status; //executeContext.Logger.Debug("Step timer for {0}: callbacks: {1}ms, total: {2}ms", this, CallbackWatch.ElapsedMilliseconds, MicroThreadWatch.ElapsedMilliseconds); if (StepProcessed != null) { try { IndexFileCommand.MountDatabases(executeContext); StepProcessed(this, new BuildStepEventArgs(this, executeContext.Logger)); } catch (Exception ex) { executeContext.Logger.Error("Exception in command " + this + ": " + ex); } finally { IndexFileCommand.UnmountDatabases(executeContext); } } }
private void ScheduleBuildStep(BuilderContext builderContext, BuildStep instigator, BuildStep buildStep, IDictionary <string, string> variables) { if (buildStep.ExecutionId == 0) { if (buildStep.Parent != null && buildStep.Parent != instigator) { throw new InvalidOperationException("Scheduling a BuildStep with a different instigator that its parent"); } if (buildStep.Parent == null) { buildStep.Parent = instigator; } var executeContext = new ExecuteContext(this, builderContext, buildStep) { Variables = new Dictionary <string, string>(variables) }; //buildStep.ExpandStrings(executeContext); if (runMode == Mode.Build) { MicroThread microThread = scheduler.Create(); // Find priority from this build step, or one of its parent. var buildStepPriority = buildStep; while (buildStepPriority != null) { if (buildStepPriority.Priority.HasValue) { microThread.Priority = buildStepPriority.Priority.Value; break; } buildStepPriority = buildStepPriority.Parent; } buildStep.ExecutionId = microThread.Id; foreach (var threadMonitor in threadMonitors) { threadMonitor.RegisterBuildStep(buildStep, ((BuildStepLogger)executeContext.Logger).StepLogger); } microThread.Name = buildStep.ToString(); // Default: // Schedule continuations as early as possible to help EnumerableBuildStep finish when all its task are finished. // Otherwise, it would wait for all leaf to finish first before finishing parent EnumerableBuildStep. // This should also reduce memory usage, and might improve cache coherency as well. microThread.ScheduleMode = ScheduleMode.First; microThread.Start(async() => { // Wait for prerequisites await Task.WhenAll(buildStep.PrerequisiteSteps.Select(x => x.ExecutedAsync()).ToArray()); // Check for failed prerequisites var status = ResultStatus.NotProcessed; if (buildStep.ArePrerequisitesSuccessful) { try { IndexFileCommand.MountDatabases(executeContext); // Execute status = await buildStep.Execute(executeContext, builderContext); } catch (TaskCanceledException e) { // Benlitz: I'm NOT SURE this is the correct explanation, it might be a more subtle race condition, but I can't manage to reproduce it again executeContext.Logger.Warning("A child task of build step " + buildStep + " triggered a TaskCanceledException that was not caught by the parent task. The command has not handled cancellation gracefully."); executeContext.Logger.Warning(e.Message); status = ResultStatus.Cancelled; } catch (Exception e) { executeContext.Logger.Error("Exception in command " + buildStep + ": " + e); status = ResultStatus.Failed; } finally { IndexFileCommand.UnmountDatabases(executeContext); // Ensure the command set at least the result status if (status == ResultStatus.NotProcessed) { throw new InvalidDataException("The build step " + buildStep + " returned ResultStatus.NotProcessed after completion."); } } if (microThread.Exception != null) { executeContext.Logger.Error("Exception in command " + buildStep + ": " + microThread.Exception); status = ResultStatus.Failed; } } else { status = ResultStatus.NotTriggeredPrerequisiteFailed; } buildStep.RegisterResult(executeContext, status); stepCounter.AddStepResult(status); //if (completedTask.IsCanceled) //{ // completedStep.Status = ResultStatus.Cancelled; //} var logType = LogMessageType.Info; string logText = null; switch (buildStep.Status) { case ResultStatus.Successful: logType = LogMessageType.Info; logText = "BuildStep {0} was successful.".ToFormat(buildStep.ToString()); break; case ResultStatus.Failed: logType = LogMessageType.Error; logText = "BuildStep {0} failed.".ToFormat(buildStep.ToString()); break; case ResultStatus.Cancelled: logType = LogMessageType.Warning; logText = "BuildStep {0} cancelled.".ToFormat(buildStep.ToString()); break; case ResultStatus.NotProcessed: throw new InvalidDataException("BuildStep has neither succeeded, failed, nor been cancelled"); } if (logText != null) { var logMessage = new LogMessage(buildStep.Module, logType, logText); executeContext.Logger.Log(logMessage); } }); } else { buildStep.Clean(executeContext, builderContext, runMode == Mode.CleanAndDelete); } } }