IDEBuildLogger.cs :  » Development » StyleCop » Microsoft » VisualStudio » Package » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » StyleCop 
StyleCop » Microsoft » VisualStudio » Package » IDEBuildLogger.cs
/***************************************************************************

Copyright (c) Microsoft Corporation. All rights reserved.
This code is licensed under the Visual Studio SDK license terms.
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.

***************************************************************************/

using System;
using System.Diagnostics;
using System.Globalization;
using System.CodeDom.Compiler;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.Win32;
using IOleServiceProviderMicrosoft.VisualStudio.OLE.Interop.IServiceProvider;

namespace Microsoft.VisualStudio.Package{

  /// <summary>
  /// This class implements an MSBuild logger that output events to VS outputwindow and tasklist.
  /// </summary>
  [ComVisible(true)]
  internal sealed class IDEBuildLogger : Logger
  {
    #region fields
    // TODO: Remove these constants when we have a version that suppoerts getting the verbosity using automation.
    private string buildVerbosityRegistryRoot = @"Software\Microsoft\VisualStudio\9.0";
    private const string buildVerbosityRegistrySubKey = @"General";
    private const string buildVerbosityRegistryKey = "MSBuildLoggerVerbosity";
    // TODO: Re-enable this constants when we have a version that suppoerts getting the verbosity using automation.
    //private const string EnvironmentCategory = "Environment";
    //private const string ProjectsAndSolutionSubCategory = "ProjectsAndSolution";
    //private const string BuildAndRunPage = "BuildAndRun";

    private int currentIndent;
    private IVsOutputWindowPane outputWindowPane;
    private string errorString = SR.GetString(SR.Error, CultureInfo.CurrentUICulture);
    private string warningString = SR.GetString(SR.Warning, CultureInfo.CurrentUICulture);
    private bool isLogTaskDone;
    private TaskProvider taskProvider;
    private IVsHierarchy hierarchy;
    private IServiceProvider serviceProvider;

    #endregion

    #region properties
    public string WarningString
    {
      get { return this.warningString; }
      set { this.warningString = value; }
    }
    public string ErrorString
    {
      get { return this.errorString; }
      set { this.errorString = value; }
    }
    public bool IsLogTaskDone
    {
      get { return this.isLogTaskDone; }
      set { this.isLogTaskDone = value; }
    }
    /// <summary>
    /// When building from within VS, setting this will
    /// enable the logger to retrive the verbosity from
    /// the correct registry hive.
    /// </summary>
    internal string BuildVerbosityRegistryRoot
    {
      get { return buildVerbosityRegistryRoot; }
      set { buildVerbosityRegistryRoot = value; }
    }
    /// <summary>
    /// Set to null to avoid writing to the output window
    /// </summary>
    internal IVsOutputWindowPane OutputWindowPane
    {
      get { return outputWindowPane; }
      set { outputWindowPane = value; }
    }
    #endregion

    #region ctors
    /// <summary>
    /// Constructor.  Inititialize member data.
    /// </summary>
    public IDEBuildLogger(IVsOutputWindowPane output, TaskProvider taskProvider, IVsHierarchy hierarchy)
    {
      if (taskProvider == null)
        throw new ArgumentNullException("taskProvider");
      if (hierarchy == null)
        throw new ArgumentNullException("hierarchy");

      this.taskProvider = taskProvider;
      this.outputWindowPane = output;
      this.hierarchy = hierarchy;
      IOleServiceProvider site;
      Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hierarchy.GetSite(out site));
      this.serviceProvider = new ServiceProvider(site);
    }
    #endregion

    #region overridden methods
    /// <summary>
    /// Overridden from the Logger class.
    /// </summary>
    public override void Initialize(IEventSource eventSource)
    {
      if (null == eventSource)
      {
        throw new ArgumentNullException("eventSource");
      }
      eventSource.BuildStarted += new BuildStartedEventHandler(BuildStartedHandler);
      eventSource.BuildFinished += new BuildFinishedEventHandler(BuildFinishedHandler);
      eventSource.ProjectStarted += new ProjectStartedEventHandler(ProjectStartedHandler);
      eventSource.ProjectFinished += new ProjectFinishedEventHandler(ProjectFinishedHandler);
      eventSource.TargetStarted += new TargetStartedEventHandler(TargetStartedHandler);
      eventSource.TargetFinished += new TargetFinishedEventHandler(TargetFinishedHandler);
      eventSource.TaskStarted += new TaskStartedEventHandler(TaskStartedHandler);
      eventSource.TaskFinished += new TaskFinishedEventHandler(TaskFinishedHandler);
      eventSource.CustomEventRaised += new CustomBuildEventHandler(CustomHandler);
      eventSource.ErrorRaised += new BuildErrorEventHandler(ErrorHandler);
      eventSource.WarningRaised += new BuildWarningEventHandler(WarningHandler);
      eventSource.MessageRaised += new BuildMessageEventHandler(MessageHandler);
    }
    #endregion

    #region event delegates
    /// <summary>
    /// This is the delegate for error events.
    /// </summary>
    private void ErrorHandler(object sender, BuildErrorEventArgs errorEvent)
    {
      AddToErrorList(
        errorEvent,
        errorEvent.Code,
        errorEvent.File,
        errorEvent.LineNumber,
        errorEvent.ColumnNumber);
    }

    /// <summary>
    /// This is the delegate for warning events.
    /// </summary>
    private void WarningHandler(object sender, BuildWarningEventArgs errorEvent)
    {
      AddToErrorList(
        errorEvent,
        errorEvent.Code,
        errorEvent.File,
        errorEvent.LineNumber,
        errorEvent.ColumnNumber);
    }

    /// <summary>
    /// Add the error/warning to the error list and potentially to the output window.
    /// </summary>
    private void AddToErrorList(
      BuildEventArgs errorEvent,
      string errorCode,
      string file,
      int line,
      int column)
    {
      TaskPriority priority = (errorEvent is BuildErrorEventArgs) ? TaskPriority.High : TaskPriority.Normal;
      if (OutputWindowPane != null
        && (this.Verbosity != LoggerVerbosity.Quiet || errorEvent is BuildErrorEventArgs))
      {
        // Format error and output it to the output window
        string message = this.FormatMessage(errorEvent.Message);
        CompilerError e = new CompilerError(file,
                          line,
                          column,
                          errorCode,
                          message);
        e.IsWarning = (errorEvent is BuildWarningEventArgs);

        Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(OutputWindowPane.OutputStringThreadSafe(GetFormattedErrorMessage(e)));
      }

      // Add error to task list
      ErrorTask task = new ErrorTask();
      task.Document = file;
      task.Line = line - 1; // The task list does +1 before showing this number.
      task.Column = column;
      task.Text = errorEvent.Message;
      task.Priority = priority;
      task.Category = TaskCategory.BuildCompile;
      task.HierarchyItem = hierarchy;
      task.Navigate += new EventHandler(NavigateTo);
      if (errorEvent is BuildWarningEventArgs)
        task.ErrorCategory = TaskErrorCategory.Warning;
      this.taskProvider.Tasks.Add(task);
    }


    /// <summary>
    /// This is the delegate for Message event types
    /// </summary>    
    private void MessageHandler(object sender, BuildMessageEventArgs messageEvent)
    {
      if (LogAtImportance(messageEvent.Importance))
      {
        LogEvent(sender, messageEvent);
      }
    }

    private void NavigateTo(object sender, EventArgs arguments)
    {
      Microsoft.VisualStudio.Shell.Task task = sender as Microsoft.VisualStudio.Shell.Task;
      if (task == null)
        throw new ArgumentException("sender");

      // Get the doc data for the task's document
      if (String.IsNullOrEmpty(task.Document))
        return;

      IVsUIShellOpenDocument openDoc = serviceProvider.GetService(typeof(IVsUIShellOpenDocument)) as IVsUIShellOpenDocument;
      if (openDoc == null)
        return;

      IVsWindowFrame frame;
      IOleServiceProvider sp;
      IVsUIHierarchy hier;
      uint itemid;
      Guid logicalView = VSConstants.LOGVIEWID_Code;

            if (Microsoft.VisualStudio.ErrorHandler.Failed(openDoc.OpenDocumentViaProject(task.Document, ref logicalView, out sp, out hier, out itemid, out frame)) || frame == null)
        return;

      object docData;
      frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out docData);

      // Get the VsTextBuffer
      VsTextBuffer buffer = docData as VsTextBuffer;
      if (buffer == null)
      {
        IVsTextBufferProvider bufferProvider = docData as IVsTextBufferProvider;
        if (bufferProvider != null)
        {
          IVsTextLines lines;
                    Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(bufferProvider.GetTextBuffer(out lines));
          buffer = lines as VsTextBuffer;
          Debug.Assert(buffer != null, "IVsTextLines does not implement IVsTextBuffer");
          if (buffer == null)
            return;
        }
      }

      // Finally, perform the navigation.
      IVsTextManager mgr = serviceProvider.GetService(typeof(VsTextManagerClass)) as IVsTextManager;
      if (mgr == null)
        return;

      mgr.NavigateToLineAndColumn(buffer, ref logicalView, task.Line, task.Column, task.Line, task.Column);
    }

    /// <summary>
    /// This is the delegate for BuildStartedHandler events.
    /// </summary>
    private void BuildStartedHandler(object sender, BuildStartedEventArgs buildEvent)
    {
      if (LogAtImportance(MessageImportance.Low))
      {
        LogEvent(sender, buildEvent);
      }
      // Remove all errors and warnings since we are rebuilding
      taskProvider.Tasks.Clear();
    }

    /// <summary>
    /// This is the delegate for BuildFinishedHandler events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="buildEvent"></param>
    private void BuildFinishedHandler(object sender, BuildFinishedEventArgs buildEvent)
    {
      if (LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low :
                             MessageImportance.High))
      {
        if (this.outputWindowPane != null)
          this.outputWindowPane.OutputStringThreadSafe(Environment.NewLine);
        LogEvent(sender, buildEvent);
      }
    }


    /// <summary>
    /// This is the delegate for ProjectStartedHandler events.
    /// </summary>
    private void ProjectStartedHandler(object sender, ProjectStartedEventArgs buildEvent)
    {
      if (LogAtImportance(MessageImportance.Low))
      {
        LogEvent(sender, buildEvent);
      }
    }

    /// <summary>
    /// This is the delegate for ProjectFinishedHandler events.
    /// </summary>
    private void ProjectFinishedHandler(object sender, ProjectFinishedEventArgs buildEvent)
    {
      if (LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low
                           : MessageImportance.High))
      {
        LogEvent(sender, buildEvent);
      }
    }

    /// <summary>
    /// This is the delegate for TargetStartedHandler events.
    /// </summary>
    private void TargetStartedHandler(object sender, TargetStartedEventArgs buildEvent)
    {
      if (LogAtImportance(MessageImportance.Normal))
      {
        LogEvent(sender, buildEvent);
      }
      ++this.currentIndent;
    }


    /// <summary>
    /// This is the delegate for TargetFinishedHandler events.
    /// </summary>
    private void TargetFinishedHandler(object sender, TargetFinishedEventArgs buildEvent)
    {
      --this.currentIndent;
      if ((isLogTaskDone) &&
        LogAtImportance(buildEvent.Succeeded ? MessageImportance.Low
                           : MessageImportance.High))
      {
        LogEvent(sender, buildEvent);
      }
    }


    /// <summary>
    /// This is the delegate for TaskStartedHandler events.
    /// </summary>
    private void TaskStartedHandler(object sender, TaskStartedEventArgs buildEvent)
    {
      if (LogAtImportance(MessageImportance.Normal))
      {
        LogEvent(sender, buildEvent);
      }
      ++this.currentIndent;
    }


    /// <summary>
    /// This is the delegate for TaskFinishedHandler events.
    /// </summary>
    private void TaskFinishedHandler(object sender, TaskFinishedEventArgs buildEvent)
    {
      --this.currentIndent;
      if ((isLogTaskDone) &&
        LogAtImportance(buildEvent.Succeeded ? MessageImportance.Normal
                           : MessageImportance.High))
      {
        LogEvent(sender, buildEvent);
      }
    }


    /// <summary>
    /// This is the delegate for CustomHandler events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="buildEvent"></param>
    private void CustomHandler(object sender, CustomBuildEventArgs buildEvent)
    {
      LogEvent(sender, buildEvent);
    }

    #endregion

    #region helpers
    /// <summary>
    /// This method takes a MessageImportance and returns true if messages
    /// at importance i should be loggeed.  Otherwise return false.
    /// </summary>
    private bool LogAtImportance(MessageImportance importance)
    {
      // If importance is too low for current settings, ignore the event
      bool logIt = false;

      this.SetVerbosity();

      switch (this.Verbosity)
      {
        case LoggerVerbosity.Quiet:
          logIt = false;
          break;
        case LoggerVerbosity.Minimal:
          logIt = (importance == MessageImportance.High);
          break;
        case LoggerVerbosity.Normal:
        // Falling through...
        case LoggerVerbosity.Detailed:
          logIt = (importance != MessageImportance.Low);
          break;
        case LoggerVerbosity.Diagnostic:
          logIt = true;
          break;
        default:
          Debug.Fail("Unknown Verbosity level. Ignoring will cause everything to be logged");
          break;
      }

      return logIt;
    }

    /// <summary>
    /// This is the method that does the main work of logging an event
    /// when one is sent to this logger.
    /// </summary>
    private void LogEvent(object sender, BuildEventArgs buildEvent)
    {
      // Fill in the Message text
      if (OutputWindowPane != null && !String.IsNullOrEmpty(buildEvent.Message))
      {
        StringBuilder msg = new StringBuilder(this.currentIndent + buildEvent.Message.Length + 1);
        if (this.currentIndent > 0)
        {
          msg.Append('\t', this.currentIndent);
        }
        msg.AppendLine(buildEvent.Message);
        this.OutputWindowPane.OutputStringThreadSafe(msg.ToString());
      }
    }

    /// <summary>
    /// This is called when the build complete.
    /// </summary>
    private void ShutdownLogger()
    {
    }


    /// <summary>
    /// Format error messages for the task list
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    private string GetFormattedErrorMessage(CompilerError e)
    {
      if (e == null) return String.Empty;

      string errCode = (e.IsWarning) ? this.warningString : this.errorString;
      StringBuilder fileRef = new StringBuilder();

      if (!string.IsNullOrEmpty(e.FileName))
      {
        fileRef.AppendFormat(CultureInfo.CurrentUICulture, "{0}({1},{2}):",
                                        e.FileName, e.Line, e.Column);
      }
      fileRef.AppendFormat(CultureInfo.CurrentUICulture, " {0} {1}: {2}", errCode, e.ErrorNumber, e.ErrorText);

      return fileRef.ToString();
    }

    /// <summary>
    /// Formats the message that is to be output.
    /// </summary>
    /// <param name="message">The message string.</param>
    /// <returns>The new message</returns>
    private string FormatMessage(string message)
    {
      if (string.IsNullOrEmpty(message))
      {
        return Environment.NewLine;
      }

      StringBuilder sb = new StringBuilder(message.Length + Environment.NewLine.Length);

      sb.AppendLine(message);
      return sb.ToString();
    }

    /// <summary>
    /// Sets the verbosity level.
    /// </summary>
    private void SetVerbosity()
    {
      // TODO: This should be replaced when we have a version that supports automation.

      string verbosityKey = String.Format(CultureInfo.InvariantCulture, @"{0}\{1}", BuildVerbosityRegistryRoot, buildVerbosityRegistrySubKey);
      using (RegistryKey subKey = Registry.CurrentUser.OpenSubKey(verbosityKey))
      {
        if (subKey != null)
        {
          object valueAsObject = subKey.GetValue(buildVerbosityRegistryKey);
          if (valueAsObject != null)
          {
            this.Verbosity = (LoggerVerbosity)((int)valueAsObject);
          }
        }
      }

      // TODO: Continue this code to get the Verbosity when we have a version that supports automation to get the Verbosity.
      //EnvDTE.DTE dte = this.serviceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
      //EnvDTE.Properties properties = dte.get_Properties(EnvironmentCategory, ProjectsAndSolutionSubCategory);
    }
    #endregion
  }

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.