/// <summary> /// Creates an asynchronous Task object that executes the given critical phase and optional phases in a background thread /// and invokes all other callbacks on the UI thread. /// </summary> /// <param name="cancellationToken"></param> /// <param name="beforeStart">Invoked on UI thread</param> /// <param name="criticalPhase">First phase to run. Must succeed (by returning <c>true</c> and not throwing an exception) for the optional phases to run. Invoked on the background thread.</param> /// <param name="optionalPhases">Collection of phases that can fail (by throwing an exception) without preventing subsequent phases from running. Invoked on the background thread.</param> /// <param name="fail">Called if the operation is canceled or the critical phase throws an exception. Invoked on the UI thread.</param> /// <param name="succeed">Called if the operation completes successfully without being canceled. Invoked on the UI thread.</param> /// <returns> /// Task object that returns <c>false</c> if the operation was canceled by the user or /// the critical phase threw an exception; otherwise <c>true</c>. /// </returns> private Task <bool> CreateStageTask(CancellationToken cancellationToken, TaskStartedEventHandler beforeStart, CriticalPhase criticalPhase, IEnumerable <OptionalPhase> optionalPhases, ExceptionEventHandler fail, TaskSucceededEventHandler succeed) { var canContinue = CreateCanContinueFunc(cancellationToken); return(new TaskBuilder() .OnThread(_callbackScheduler) .CancelWith(cancellationToken) .BeforeStart(beforeStart) .Fail(fail) .DoWork(delegate(IThreadInvoker invoker, CancellationToken token) { cancellationToken.Register(() => Logger.Warn("User canceled current operation")); if (criticalPhase()) { foreach (var phase in optionalPhases.TakeWhile(phase => canContinue())) { phase(); } if (canContinue()) { invoker.InvokeOnUIThreadAsync(_ => succeed()); return; } } // TODO: How should we handle exceptions here? // The rest of the code assumes exceptions are being handled by the plugin runner. invoker.InvokeOnUIThreadAsync(_ => fail(new ExceptionEventArgs())); }) .Build() ); }
public Task <bool> CreateMetadataTask(CancellationToken cancellationToken, TaskStartedEventHandler start, ExceptionEventHandler fail, TaskSucceededEventHandler succeed, string mkvPath = null) { var token = cancellationToken; var optionalPhases = new[] { CreateGetMetadataPhase(token), CreateAutoDetectPhase(token), CreateRenamePhase(token, mkvPath) }; return(CreateStageTask( token, start, () => true, optionalPhases, fail, succeed )); }
public void EventsOutOfSequence() { // Make sure that the registry key is no present so that we can set the verbosity. DeleteVerbosityKey(); using (OleServiceProvider provider = new OleServiceProvider()) { using (TaskProvider task = new TaskProvider(new ServiceProvider(provider))) { IVsHierarchy hierarchy = MockFactories.HierarchyForLogger(provider); IVsOutputWindowPane output = MockFactories.OutputPaneWithStringFunctions(); BaseMock mockOutput = (BaseMock)output; // Create the logger and make sure that it points to the verbosity IDELoggerProxy logger = new IDELoggerProxy(output, task, hierarchy); logger.SetBuildVerbosityRegistryRoot(TestVerbosityRoot); // Create the IEventSource that will be used to send messages to the logger BaseMock mockSource = MockFactories.CreateMSBuildEventSource(); // Now initialize the logger. logger.Initialize(mockSource as IEventSource); // Verify that the logger has installed an event handler for messages and // build events. Assert.IsNotNull(mockSource["MessageRaised"]); BuildMessageEventHandler messageHandler = (BuildMessageEventHandler)mockSource["MessageRaised"]; Assert.IsNotNull(mockSource["BuildStarted"]); BuildStartedEventHandler buildStartedHandler = (BuildStartedEventHandler)mockSource["BuildStarted"]; Assert.IsNotNull(mockSource["BuildFinished"]); BuildFinishedEventHandler buildFinishedHandler = (BuildFinishedEventHandler)mockSource["BuildFinished"]; Assert.IsNotNull(mockSource["TaskStarted"]); TaskStartedEventHandler taskStartedHandler = (TaskStartedEventHandler)mockSource["TaskStarted"]; Assert.IsNotNull(mockSource["TaskFinished"]); TaskFinishedEventHandler taskFinishedHandler = (TaskFinishedEventHandler)mockSource["TaskFinished"]; // Create the arguments for the events and the delegates. BuildMessageEventArgs messageArgs = new BuildMessageEventArgs("Message", "help", "sender", MessageImportance.Normal); SendEventFunction sendMessage = delegate { messageHandler.Invoke(mockSource, messageArgs); }; // BuildStartedEventArgs startBuildArgs = new BuildStartedEventArgs("Start Build", "help"); SendEventFunction sendStartBuild = delegate { buildStartedHandler.Invoke(mockSource, startBuildArgs); }; // BuildFinishedEventArgs finishBuildArgs = new BuildFinishedEventArgs("End Build", "help", true); SendEventFunction sendEndBuild = delegate { buildFinishedHandler.Invoke(mockSource, finishBuildArgs); }; // TaskStartedEventArgs startTaskArgs = new TaskStartedEventArgs("Start Task", null, null, null, null); SendEventFunction sendStartTask = delegate { taskStartedHandler.Invoke(mockSource, startTaskArgs); }; // TaskFinishedEventArgs endTaskArgs = new TaskFinishedEventArgs("End Task", null, null, null, null, true); SendEventFunction sendEndTask = delegate { taskFinishedHandler.Invoke(mockSource, endTaskArgs); }; // Set the verbosity to Diagnostic so that all the messages are written. logger.Verbosity = LoggerVerbosity.Diagnostic; List <SendEventFunction>[] events = new List <SendEventFunction>[] { new List <SendEventFunction>(new SendEventFunction[] { sendMessage, sendEndBuild, sendStartBuild }), new List <SendEventFunction>(new SendEventFunction[] { sendStartBuild, sendEndTask, sendEndBuild, sendStartTask }), new List <SendEventFunction>(new SendEventFunction[] { sendStartTask, sendStartBuild, sendEndTask, sendEndBuild }), new List <SendEventFunction>(new SendEventFunction[] { sendEndBuild, sendStartTask, sendEndTask, sendStartBuild }), new List <SendEventFunction>(new SendEventFunction[] { sendEndBuild, sendEndTask, sendStartTask, sendStartBuild }), new List <SendEventFunction>(new SendEventFunction[] { sendEndTask, sendEndBuild, sendStartTask, sendStartBuild }), }; // Call the functions. Note that here we don't check for the actual text printed on the output, // but we simply verify that the logger can handle the events without exceptions. foreach (List <SendEventFunction> sendFunctions in events) { output.Clear(); foreach (SendEventFunction func in sendFunctions) { func(); } } } } }
/// <summary> /// Initialize the internal event source which is used to raise events on loggers registered to this submission /// </summary> private void InitializeInternalEventSource() { _anyEventHandler = new AnyEventHandler(RaiseAnyEvent); _buildFinishedEventHandler = new BuildFinishedEventHandler(RaiseBuildFinishedEvent); _buildStartedEventHandler = new BuildStartedEventHandler(RaiseBuildStartedEvent); _customBuildEventHandler = new CustomBuildEventHandler(RaiseCustomEvent); _buildErrorEventHandler = new BuildErrorEventHandler(RaiseErrorEvent); _buildMessageEventHandler = new BuildMessageEventHandler(RaiseMessageEvent); _projectFinishedEventHandler = new ProjectFinishedEventHandler(RaiseProjectFinishedEvent); _projectStartedEventHandler = new ProjectStartedEventHandler(RaiseProjectStartedEvent); _buildStatusEventHandler = new BuildStatusEventHandler(RaiseStatusEvent); _targetFinishedEventHandler = new TargetFinishedEventHandler(RaiseTargetFinishedEvent); _targetStartedEventHandler = new TargetStartedEventHandler(RaiseTargetStartedEvent); _taskFinishedEventHandler = new TaskFinishedEventHandler(RaiseTaskFinishedEvent); _taskStartedEventHandler = new TaskStartedEventHandler(RaiseTaskStartedEvent); _buildWarningEventHandler = new BuildWarningEventHandler(RaiseWarningEvent); _eventSourceForBuild.AnyEventRaised += _anyEventHandler; _eventSourceForBuild.BuildFinished += _buildFinishedEventHandler; _eventSourceForBuild.BuildStarted += _buildStartedEventHandler; _eventSourceForBuild.CustomEventRaised += _customBuildEventHandler; _eventSourceForBuild.ErrorRaised += _buildErrorEventHandler; _eventSourceForBuild.MessageRaised += _buildMessageEventHandler; _eventSourceForBuild.ProjectFinished += _projectFinishedEventHandler; _eventSourceForBuild.ProjectStarted += _projectStartedEventHandler; _eventSourceForBuild.StatusEventRaised += _buildStatusEventHandler; _eventSourceForBuild.TargetFinished += _targetFinishedEventHandler; _eventSourceForBuild.TargetStarted += _targetStartedEventHandler; _eventSourceForBuild.TaskFinished += _taskFinishedEventHandler; _eventSourceForBuild.TaskStarted += _taskStartedEventHandler; _eventSourceForBuild.WarningRaised += _buildWarningEventHandler; }
public void MessageFormattingTest() { // Make sure that the registry key is no present so that we can set the verbosity. DeleteVerbosityKey(); using (OleServiceProvider provider = new OleServiceProvider()) { using (TaskProvider task = new TaskProvider(new ServiceProvider(provider))) { IVsHierarchy hierarchy = MockFactories.HierarchyForLogger(provider); IVsOutputWindowPane output = MockFactories.OutputPaneWithStringFunctions(); BaseMock mockOutput = (BaseMock)output; // Create the logger and make sure that it points to the verbosity IDELoggerProxy logger = new IDELoggerProxy(output, task, hierarchy); logger.SetBuildVerbosityRegistryRoot(TestVerbosityRoot); // Create the IEventSource that will be used to send messages to the logger BaseMock mockSource = MockFactories.CreateMSBuildEventSource(); // Now initialize the logger. logger.Initialize(mockSource as IEventSource); // Verify that the logger has installed an event handler for messages and // build events. Assert.IsNotNull(mockSource["MessageRaised"]); BuildMessageEventHandler messageHandler = (BuildMessageEventHandler)mockSource["MessageRaised"]; Assert.IsNotNull(mockSource["BuildStarted"]); BuildStartedEventHandler buildStartedHandler = (BuildStartedEventHandler)mockSource["BuildStarted"]; Assert.IsNotNull(mockSource["BuildFinished"]); BuildFinishedEventHandler buildFinishedHandler = (BuildFinishedEventHandler)mockSource["BuildFinished"]; Assert.IsNotNull(mockSource["TaskStarted"]); TaskStartedEventHandler taskStartedHandler = (TaskStartedEventHandler)mockSource["TaskStarted"]; Assert.IsNotNull(mockSource["TaskFinished"]); TaskFinishedEventHandler taskFinishedHandler = (TaskFinishedEventHandler)mockSource["TaskFinished"]; // Set the verbosity to Diagnostic so that all the messages are written. logger.Verbosity = LoggerVerbosity.Diagnostic; // Create a message of the expected importance. BuildMessageEventArgs message = new BuildMessageEventArgs("message", "help", "sender", MessageImportance.Normal); messageHandler.Invoke(mockSource, message); // Add a second message with null text. message = new BuildMessageEventArgs(null, "help", "sender", MessageImportance.Normal); messageHandler.Invoke(mockSource, message); // Add another message with emty text. message = new BuildMessageEventArgs(string.Empty, "help", "sender", MessageImportance.Normal); messageHandler.Invoke(mockSource, message); System.Windows.Forms.Application.DoEvents(); string expected = "message" + Environment.NewLine; System.Text.StringBuilder builder = (System.Text.StringBuilder)mockOutput["StringBuilder"]; Assert.AreEqual(expected, builder.ToString(), false); // Clean up the text. output.Clear(); // Now verify the identation in case of start and end build events. string startText = "Test Started"; string messageText = "build message"; string endText = "Test Finished"; BuildStartedEventArgs startBuildArgs = new BuildStartedEventArgs(startText, "help"); buildStartedHandler.Invoke(mockSource, startBuildArgs); message = new BuildMessageEventArgs(messageText, "help", "sender", MessageImportance.Normal); messageHandler.Invoke(mockSource, message); BuildFinishedEventArgs finishBuildArgs = new BuildFinishedEventArgs(endText, "help", true); buildFinishedHandler.Invoke(mockSource, finishBuildArgs); System.Windows.Forms.Application.DoEvents(); // Get the text in the output pane. builder = (System.Text.StringBuilder)mockOutput["StringBuilder"]; expected = string.Format("{0}{1}{2}{1}{1}{3}{1}", startText, Environment.NewLine, messageText, endText); Assert.AreEqual(expected, builder.ToString(), false); // Clear the output and test the identation in case of start and end task. output.Clear(); TaskStartedEventArgs startTaskArgs = new TaskStartedEventArgs(startText, null, null, null, null); taskStartedHandler.Invoke(mockSource, startTaskArgs); message = new BuildMessageEventArgs(messageText, "help", "sender", MessageImportance.Normal); messageHandler.Invoke(mockSource, message); TaskFinishedEventArgs endTaskArgs = new TaskFinishedEventArgs(endText, null, null, null, null, true); taskFinishedHandler.Invoke(mockSource, endTaskArgs); System.Windows.Forms.Application.DoEvents(); // Verify the text in the output pane. expected = string.Format("{0}{1}\t{2}{1}{3}{1}", startText, Environment.NewLine, messageText, endText); builder = (System.Text.StringBuilder)mockOutput["StringBuilder"]; Assert.AreEqual(expected, builder.ToString(), false); } } }
/// <summary> /// Creates an asynchronous Task object that executes the given critical phase and optional phases in a background thread /// and invokes all other callbacks on the UI thread. /// </summary> /// <param name="cancellationToken"></param> /// <param name="beforeStart">Invoked on UI thread</param> /// <param name="criticalPhase">First phase to run. Must succeed (by returning <c>true</c> and not throwing an exception) for the optional phases to run. Invoked on the background thread.</param> /// <param name="optionalPhases">Collection of phases that can fail (by throwing an exception) without preventing subsequent phases from running. Invoked on the background thread.</param> /// <param name="fail">Called if the operation is canceled or the critical phase throws an exception. Invoked on the UI thread.</param> /// <param name="succeed">Called if the operation completes successfully without being canceled. Invoked on the UI thread.</param> /// <returns> /// Task object that returns <c>false</c> if the operation was canceled by the user or /// the critical phase threw an exception; otherwise <c>true</c>. /// </returns> private Task<bool> CreateStageTask(CancellationToken cancellationToken, TaskStartedEventHandler beforeStart, CriticalPhase criticalPhase, IEnumerable<OptionalPhase> optionalPhases, ExceptionEventHandler fail, TaskSucceededEventHandler succeed) { var canContinue = CreateCanContinueFunc(cancellationToken); return new TaskBuilder() .OnThread(_callbackScheduler) .CancelWith(cancellationToken) .BeforeStart(beforeStart) .Fail(fail) .DoWork(delegate(IThreadInvoker invoker, CancellationToken token) { cancellationToken.Register(() => Logger.Warn("User canceled current operation")); if (criticalPhase()) { foreach (var phase in optionalPhases.TakeWhile(phase => canContinue())) { phase(); } if (canContinue()) { invoker.InvokeOnUIThreadAsync(_ => succeed()); return; } } // TODO: How should we handle exceptions here? // The rest of the code assumes exceptions are being handled by the plugin runner. invoker.InvokeOnUIThreadAsync(_ => fail(new ExceptionEventArgs())); }) .Build() ; }
public Task<bool> CreateMetadataTask(CancellationToken cancellationToken, TaskStartedEventHandler start, ExceptionEventHandler fail, TaskSucceededEventHandler succeed, string mkvPath = null) { var token = cancellationToken; var optionalPhases = new[] { CreateGetMetadataPhase(token), CreateAutoDetectPhase(token), CreateRenamePhase(token, mkvPath) }; return CreateStageTask( token, start, () => true, optionalPhases, fail, succeed ); }
/// <summary> /// Runs the specified action in the UI thread before invoking the main <see cref="DoWork"/> action. /// If the <c>BeforeStart </c>action fails, the <c>DoWork</c> action will not be run. /// </summary> /// <param name="beforeStart">Action to run on the UI thread</param> /// <returns>Reference to this <c>TaskBuilder</c></returns> public TaskBuilder BeforeStart(TaskStartedEventHandler beforeStart) { _beforeStart = beforeStart; return(this); }
/// <summary> /// Runs the specified action in the UI thread before invoking the main <see cref="DoWork"/> action. /// If the <c>BeforeStart </c>action fails, the <c>DoWork</c> action will not be run. /// </summary> /// <param name="beforeStart">Action to run on the UI thread</param> /// <returns>Reference to this <c>TaskBuilder</c></returns> public TaskBuilder BeforeStart(TaskStartedEventHandler beforeStart) { _beforeStart = beforeStart; return this; }