Browse Source

Allow SharpDevelop AddIn to filter the logger output. Removed mutable 'CurrentErrorOrWarning' in BuildEngine and use logger filters instead.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5643 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Daniel Grunwald 15 years ago
parent
commit
0b8d32fb61
  1. 1
      AddIns/ICSharpCode.SharpDevelop.addin
  2. 4
      clean.bat
  3. 70
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/VbcEncodingFixingLogger.cs
  4. 4
      src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin
  5. 4
      src/AddIns/Misc/CodeAnalysis/CodeAnalysis.addin
  6. 106
      src/AddIns/Misc/CodeAnalysis/Src/FxCopLogger.cs
  7. 3
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  8. 4
      src/Main/Base/Project/Src/Project/BuildEngine.cs
  9. 12
      src/Main/Base/Project/Src/Project/BuildError.cs
  10. 32
      src/Main/Base/Project/Src/Project/MSBuildEngine/BuildWorkerManager.cs
  11. 0
      src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildAdditionalLogger.cs
  12. 153
      src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs
  13. 136
      src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildLoggerFilter.cs
  14. 2
      src/Main/ICSharpCode.Core.Presentation/NumericUpDown.cs

1
AddIns/ICSharpCode.SharpDevelop.addin

@ -46,6 +46,7 @@ @@ -46,6 +46,7 @@
<Doozer name="Debugger" class="ICSharpCode.SharpDevelop.Debugging.DebuggerDoozer"/>
<Doozer name="Directory" class="ICSharpCode.SharpDevelop.DirectoryDoozer"/>
<Doozer name="TaskBoundAdditionalLogger" class="ICSharpCode.SharpDevelop.Project.TaskBoundAdditionalLoggerDoozer"/>
<Doozer name="TaskBoundLoggerFilter" class="ICSharpCode.SharpDevelop.Project.TaskBoundLoggerFilterDoozer"/>
</Import>
</Runtime>

4
clean.bat

@ -1,2 +1,4 @@ @@ -1,2 +1,4 @@
%windir%\microsoft.net\framework\v4.0.30128\msbuild /m SharpDevelop.sln /t:clean "/p:Platform=Any CPU"
%windir%\microsoft.net\framework\v4.0.30128\msbuild /m SharpDevelop.sln /t:clean "/p:Platform=Any CPU" /p:Configuration=Debug
@IF %ERRORLEVEL% NEQ 0 PAUSE
%windir%\microsoft.net\framework\v4.0.30128\msbuild /m SharpDevelop.sln /t:clean "/p:Platform=Any CPU" /p:Configuration=Release
@IF %ERRORLEVEL% NEQ 0 PAUSE

70
src/AddIns/BackendBindings/VBNetBinding/Project/Src/VbcEncodingFixingLogger.cs

@ -16,77 +16,39 @@ namespace VBNetBinding @@ -16,77 +16,39 @@ namespace VBNetBinding
/// <summary>
/// Fixes SD2-995 : Special characters not correctly encoded for languages others than English
/// </summary>
public class VbcEncodingFixingLogger : IMSBuildAdditionalLogger
public sealed class VbcEncodingFixingLogger : IMSBuildLoggerFilter
{
public ILogger CreateLogger(MSBuildEngine engineWorker)
public IMSBuildChainedLoggerFilter CreateFilter(MSBuildEngine engine, IMSBuildChainedLoggerFilter nextFilter)
{
return new VbcLoggerImpl(engineWorker);
return new VbcLoggerImpl(engine, nextFilter);
}
private class VbcLoggerImpl : ILogger
sealed class VbcLoggerImpl : IMSBuildChainedLoggerFilter
{
MSBuildEngine engineWorker;
readonly MSBuildEngine engineWorker;
readonly IMSBuildChainedLoggerFilter nextFilter;
public VbcLoggerImpl(MSBuildEngine engineWorker)
public VbcLoggerImpl(MSBuildEngine engineWorker, IMSBuildChainedLoggerFilter nextFilter)
{
this.engineWorker = engineWorker;
this.nextFilter = nextFilter;
}
public LoggerVerbosity Verbosity {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public string Parameters {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
IEventSource eventSource;
public void Initialize(IEventSource eventSource)
{
this.eventSource = eventSource;
eventSource.ErrorRaised += OnError;
eventSource.WarningRaised += OnWarning;
}
public void Shutdown()
{
if (eventSource != null) {
eventSource.ErrorRaised -= OnError;
eventSource.WarningRaised -= OnWarning;
eventSource = null;
}
}
void OnError(object sender, BuildErrorEventArgs e)
{
FixMessage();
}
void OnWarning(object sender, BuildWarningEventArgs e)
static string FixEncoding(string text)
{
FixMessage();
return Encoding.Default.GetString(ICSharpCode.SharpDevelop.Util.ProcessRunner.OemEncoding.GetBytes(text));
}
void FixMessage()
public void HandleError(BuildError error)
{
engineWorker.CurrentErrorOrWarning.ErrorText = FixEncoding(engineWorker.CurrentErrorOrWarning.ErrorText);
engineWorker.CurrentErrorOrWarning.FileName = FixEncoding(engineWorker.CurrentErrorOrWarning.FileName);
error.ErrorText = FixEncoding(error.ErrorText);
error.FileName = FixEncoding(error.FileName);
nextFilter.HandleError(error);
}
static string FixEncoding(string text)
public void HandleBuildEvent(Microsoft.Build.Framework.BuildEventArgs e)
{
return Encoding.Default.GetString(ICSharpCode.SharpDevelop.Util.ProcessRunner.OemEncoding.GetBytes(text));
nextFilter.HandleBuildEvent(e);
}
}
}

4
src/AddIns/BackendBindings/VBNetBinding/Project/VBNetBinding.addin

@ -39,8 +39,8 @@ @@ -39,8 +39,8 @@
<String id="vbc" text = "vbc"/>
</Path>
<Path name = "/SharpDevelop/MSBuildEngine/AdditionalLoggers">
<TaskBoundAdditionalLogger
<Path name = "/SharpDevelop/MSBuildEngine/LoggerFilters">
<TaskBoundLoggerFilter
id = "VbcEncodingFixingLogger"
taskname = "vbc"
class = "VBNetBinding.VbcEncodingFixingLogger"/>

4
src/AddIns/Misc/CodeAnalysis/CodeAnalysis.addin

@ -42,8 +42,8 @@ @@ -42,8 +42,8 @@
</ComplexCondition>
</Path>
<Path name = "/SharpDevelop/MSBuildEngine/AdditionalLoggers">
<TaskBoundAdditionalLogger
<Path name = "/SharpDevelop/MSBuildEngine/LoggerFilters">
<TaskBoundLoggerFilter
id = "FxCopLogger"
taskname = "FxCop"
class = "ICSharpCode.CodeAnalysis.FxCopLogger"/>

106
src/AddIns/Misc/CodeAnalysis/Src/FxCopLogger.cs

@ -20,114 +20,80 @@ namespace ICSharpCode.CodeAnalysis @@ -20,114 +20,80 @@ namespace ICSharpCode.CodeAnalysis
/// so this logger fixes the position.
/// Additionally, it registers the context menu containing the 'suppress message' command.
/// </summary>
public class FxCopLogger : IMSBuildAdditionalLogger
public class FxCopLogger : IMSBuildLoggerFilter
{
public ILogger CreateLogger(MSBuildEngine engineWorker)
public IMSBuildChainedLoggerFilter CreateFilter(MSBuildEngine engine, IMSBuildChainedLoggerFilter nextFilter)
{
return new FxCopLoggerImpl(engineWorker);
engine.OutputTextLine(StringParser.Parse("${res:ICSharpCode.CodeAnalysis.RunningFxCopOn} " + Path.GetFileNameWithoutExtension(engine.ProjectFileName)));
return new FxCopLoggerImpl(engine, nextFilter);
}
private class FxCopLoggerImpl : ILogger
sealed class FxCopLoggerImpl : IMSBuildChainedLoggerFilter
{
MSBuildEngine engineWorker;
readonly MSBuildEngine engineWorker;
readonly IMSBuildChainedLoggerFilter nextChainElement;
public FxCopLoggerImpl(MSBuildEngine engineWorker)
public FxCopLoggerImpl(MSBuildEngine engineWorker, IMSBuildChainedLoggerFilter nextChainElement)
{
this.engineWorker = engineWorker;
this.nextChainElement = nextChainElement;
}
public LoggerVerbosity Verbosity { get; set; }
public string Parameters { get; set; }
IEventSource eventSource;
public void Initialize(IEventSource eventSource)
{
this.eventSource = eventSource;
engineWorker.OutputText(StringParser.Parse("${res:ICSharpCode.CodeAnalysis.RunningFxCopOn} " + Path.GetFileNameWithoutExtension(engineWorker.CurrentProjectFile)));
eventSource.ErrorRaised += OnError;
eventSource.WarningRaised += OnWarning;
}
public void Shutdown()
{
if (eventSource != null) {
eventSource.ErrorRaised -= OnError;
eventSource.WarningRaised -= OnWarning;
eventSource = null;
}
}
void OnError(object sender, BuildErrorEventArgs e)
public void HandleError(BuildError error)
{
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Message, false,
e.HelpKeyword, e.Code, e.Subcategory);
}
void OnWarning(object sender, BuildWarningEventArgs e)
{
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Message, true,
e.HelpKeyword, e.Code, e.Subcategory);
}
void AppendError(string file, int lineNumber, int columnNumber,
string message, bool isWarning,
string category, string checkId, string subcategory)
{
LoggingService.Debug("Got " + (isWarning ? "warning" : "error") + ":\n"
+ " file: " + file + "\n"
+ " line: " + lineNumber + ", col: " + columnNumber + "\n"
+ " message: " + message + "\n"
+ " category: " + category + "\n"
+ " checkId: " + checkId + "\n"
+ " subcategory: " + subcategory);
LoggingService.Debug("FxCopLogger got " + error.ToString());
string[] moreData = (subcategory ?? "").Split('|');
BuildError err = engineWorker.CurrentErrorOrWarning;
err.ErrorCode = (checkId != null) ? checkId.Split(':')[0] : null;
if (FileUtility.IsValidPath(file) &&
Path.GetFileName(file) == "SharpDevelop.CodeAnalysis.targets")
string[] moreData = (error.Subcategory ?? "").Split('|');
string checkId = error.ErrorCode;
error.ErrorCode = (error.ErrorCode != null) ? error.ErrorCode.Split(':')[0] : null;
if (FileUtility.IsValidPath(error.FileName) &&
Path.GetFileName(error.FileName) == "SharpDevelop.CodeAnalysis.targets")
{
err.FileName = null;
error.FileName = null;
}
IProject project = ProjectService.GetProject(engineWorker.CurrentProjectFile);
IProject project = ProjectService.GetProject(engineWorker.ProjectFileName);
if (project != null) {
IProjectContent pc = ParserService.GetProjectContent(project);
if (pc != null) {
if (file.StartsWith("positionof#")) {
string memberName = file.Substring(11);
file = "";
if (error.FileName != null && error.FileName.StartsWith("positionof#")) {
string memberName = error.FileName.Substring(11);
FilePosition pos = GetPosition(pc, memberName);
if (pos.IsEmpty == false && pos.CompilationUnit != null) {
err.FileName = pos.FileName ?? "";
err.Line = pos.Line;
err.Column = pos.Column;
error.FileName = pos.FileName ?? "";
error.Line = pos.Line;
error.Column = pos.Column;
} else {
err.FileName = null;
error.FileName = null;
}
}
if (moreData.Length > 1 && !string.IsNullOrEmpty(moreData[0])) {
err.Tag = new FxCopTaskTag {
error.Tag = new FxCopTaskTag {
ProjectContent = pc,
TypeName = moreData[0],
MemberName = moreData[1],
Category = category,
Category = error.HelpKeyword,
CheckID = checkId
};
} else {
err.Tag = new FxCopTaskTag {
error.Tag = new FxCopTaskTag {
ProjectContent = pc,
Category = category,
Category = error.HelpKeyword,
CheckID = checkId
};
}
err.ContextMenuAddInTreeEntry = "/SharpDevelop/Pads/ErrorList/CodeAnalysisTaskContextMenu";
error.ContextMenuAddInTreeEntry = "/SharpDevelop/Pads/ErrorList/CodeAnalysisTaskContextMenu";
if (moreData.Length > 2) {
(err.Tag as FxCopTaskTag).MessageID = moreData[2];
(error.Tag as FxCopTaskTag).MessageID = moreData[2];
}
}
}
nextChainElement.HandleError(error);
}
public void HandleBuildEvent(Microsoft.Build.Framework.BuildEventArgs e)
{
nextChainElement.HandleBuildEvent(e);
}
static FilePosition GetPosition(IProjectContent pc, string memberName)

3
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -260,6 +260,8 @@ @@ -260,6 +260,8 @@
<Compile Include="Src\Project\Converter\UpgradeViewContent.cs" />
<Compile Include="Src\Project\IBuildFeedbackSink.cs" />
<Compile Include="Src\Project\IProjectItemBackendStore.cs" />
<Compile Include="Src\Project\MSBuildEngine\MSBuildAdditionalLogger.cs" />
<Compile Include="Src\Project\MSBuildEngine\MSBuildLoggerFilter.cs" />
<Compile Include="Src\Project\MSBuildEngine\SDConsoleLogger.cs" />
<Compile Include="Src\Project\MSBuildEngine\BuildWorkerManager.cs" />
<Compile Include="Src\Project\MSBuildEngine\MSBuildEngine.cs" />
@ -711,7 +713,6 @@ @@ -711,7 +713,6 @@
<Compile Include="Src\TextEditor\Gui\Editor\TextNavigationPoint.cs" />
<Compile Include="Src\Project\BuildResults.cs" />
<Compile Include="Src\Project\BuildError.cs" />
<Compile Include="Src\Project\MSBuildAdditionalLogger.cs" />
<Compile Include="Src\Services\HelpProvider.cs" />
<Compile Include="Src\Services\ParserService\CodeCompletionOptions.cs" />
<Compile Include="Src\Services\RefactoringService\TextEditorDocument.cs" />

4
src/Main/Base/Project/Src/Project/BuildEngine.cs

@ -45,7 +45,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -45,7 +45,9 @@ namespace ICSharpCode.SharpDevelop.Project
if (guiBuildCancellation != null) {
BuildResults results = new BuildResults();
StatusBarService.ShowErrorMessage(Core.ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning"));
results.Add(new BuildError(null, Core.ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning")));
BuildError error = new BuildError(null, Core.ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning"));
results.Add(error);
TaskService.Add(new Task(error));
results.Result = BuildResultCode.MSBuildAlreadyRunning;
if (options.Callback != null) {
options.Callback(results);

12
src/Main/Base/Project/Src/Project/BuildError.cs

@ -50,6 +50,18 @@ namespace ICSharpCode.SharpDevelop.Project @@ -50,6 +50,18 @@ namespace ICSharpCode.SharpDevelop.Project
[NonSerialized]
object tag;
string contextMenuAddInTreeEntry;
string subcategory;
string helpKeyword;
public string HelpKeyword {
get { return helpKeyword; }
set { helpKeyword = value; }
}
public string Subcategory {
get { return subcategory; }
set { subcategory = value; }
}
public int Column {
get {

32
src/Main/Base/Project/Src/Project/MSBuildEngine/BuildWorkerManager.cs

@ -31,10 +31,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -31,10 +31,10 @@ namespace ICSharpCode.SharpDevelop.Project
this.workerProcessName = workerProcessName;
}
public void RunBuildJob(BuildJob job, IEnumerable<ILogger> loggers, IBuildFeedbackSink reportWhenDone)
public void RunBuildJob(BuildJob job, IMSBuildChainedLoggerFilter loggerChain, Action<bool> reportWhenDone, CancellationToken cancellationToken)
{
BuildWorker worker = GetFreeWorker();
worker.RunJob(job, loggers, reportWhenDone);
worker.RunJob(job, loggerChain, reportWhenDone, cancellationToken);
}
BuildWorker GetFreeWorker()
@ -70,26 +70,21 @@ namespace ICSharpCode.SharpDevelop.Project @@ -70,26 +70,21 @@ namespace ICSharpCode.SharpDevelop.Project
process.Start(startInfo);
}
EventSource source;
IEnumerable<ILogger> loggers;
IBuildFeedbackSink reportWhenDone;
IMSBuildChainedLoggerFilter loggerChain;
Action<bool> reportWhenDone;
CancellationTokenRegistration cancellationRegistration;
public void RunJob(BuildJob job, IEnumerable<ILogger> loggers, IBuildFeedbackSink reportWhenDone)
public void RunJob(BuildJob job, IMSBuildChainedLoggerFilter loggerChain, Action<bool> reportWhenDone, CancellationToken cancellationToken)
{
this.source = new EventSource();
this.loggers = loggers;
this.loggerChain = loggerChain;
this.reportWhenDone = reportWhenDone;
foreach (var logger in loggers) {
logger.Initialize(source);
}
try {
process.Writer.Write("StartBuild");
job.WriteTo(process.Writer);
this.cancellationRegistration = reportWhenDone.ProgressMonitor.CancellationToken.Register(OnCancel);
this.cancellationRegistration = cancellationToken.Register(OnCancel);
} catch (IOException ex) {
// "Pipe is broken"
source.ForwardEvent(new BuildErrorEventArgs(null, null, null, 0, 0, 0, 0, "Error talking to build worker: " + ex.Message, null, null));
loggerChain.HandleError(new BuildError(null, 0, 0, null, "Error talking to build worker: " + ex.Message));
BuildDone(false);
}
}
@ -105,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -105,7 +100,7 @@ namespace ICSharpCode.SharpDevelop.Project
LoggingService.Debug("Received command " + command);
switch (command) {
case "ReportEvent":
source.ForwardEvent(EventSource.DecodeEvent(reader));
loggerChain.HandleBuildEvent(EventSource.DecodeEvent(reader));
break;
case "BuildDone":
bool success = reader.ReadBoolean();
@ -127,10 +122,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -127,10 +122,7 @@ namespace ICSharpCode.SharpDevelop.Project
if (reportWhenDone == null)
return;
cancellationRegistration.Dispose();
foreach (var logger in loggers) {
logger.Shutdown();
}
reportWhenDone.Done(success);
reportWhenDone(success);
reportWhenDone = null;
}
}
@ -163,11 +155,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -163,11 +155,11 @@ namespace ICSharpCode.SharpDevelop.Project
parentManager.freeWorkers.Remove(this);
MarkAsInUse();
} else {
reportBuildError = true;
reportBuildError = (reportWhenDone != null); // only if not done
}
}
if (reportBuildError) {
source.ForwardEvent(new BuildErrorEventArgs(null, null, null, 0, 0, 0, 0, "Build worker process exited unexpectedly.", null, null));
loggerChain.HandleError(new BuildError(null, 0, 0, null, "Build worker process exited unexpectedly."));
BuildDone(false);
}
process.Dispose();

0
src/Main/Base/Project/Src/Project/MSBuildAdditionalLogger.cs → src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildAdditionalLogger.cs

153
src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -34,6 +34,7 @@ namespace ICSharpCode.SharpDevelop.Project
const string CompileTaskNamesPath = "/SharpDevelop/MSBuildEngine/CompileTaskNames";
const string AdditionalTargetFilesPath = "/SharpDevelop/MSBuildEngine/AdditionalTargetFiles";
const string AdditionalLoggersPath = "/SharpDevelop/MSBuildEngine/AdditionalLoggers";
const string LoggerFiltersPath = "/SharpDevelop/MSBuildEngine/LoggerFilters";
internal const string AdditionalPropertiesPath = "/SharpDevelop/MSBuildEngine/AdditionalProperties";
/// <summary>
@ -75,6 +76,13 @@ namespace ICSharpCode.SharpDevelop.Project @@ -75,6 +76,13 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public static readonly IList<IMSBuildAdditionalLogger> AdditionalMSBuildLoggers;
/// <summary>
/// Gets a list of MSBuild logger filter.
/// You can register your loggers by putting them into
/// "/SharpDevelop/MSBuildEngine/LoggerFilters"
/// </summary>
public static readonly IList<IMSBuildLoggerFilter> MSBuildLoggerFilters;
public static string SharpDevelopBinPath {
get {
return Path.GetDirectoryName(typeof(MSBuildEngine).Assembly.Location);
@ -89,6 +97,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -89,6 +97,7 @@ namespace ICSharpCode.SharpDevelop.Project
);
AdditionalTargetFiles = AddInTree.BuildItems<string>(AdditionalTargetFilesPath, null, false);
AdditionalMSBuildLoggers = AddInTree.BuildItems<IMSBuildAdditionalLogger>(AdditionalLoggersPath, null, false);
MSBuildLoggerFilters = AddInTree.BuildItems<IMSBuildLoggerFilter>(LoggerFiltersPath, null, false);
}
public static void StartBuild(IProject project, ThreadSafeServiceContainer serviceContainer, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IEnumerable<string> additionalTargetFiles)
@ -110,7 +119,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -110,7 +119,8 @@ namespace ICSharpCode.SharpDevelop.Project
engine.StartBuild();
}
IProject project;
readonly string projectFileName;
readonly int projectMinimumSolutionVersion;
ProjectBuildOptions options;
IBuildFeedbackSink feedbackSink;
IEnumerable<string> additionalTargetFiles;
@ -118,7 +128,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -118,7 +128,8 @@ namespace ICSharpCode.SharpDevelop.Project
private MSBuildEngine(IProject project, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
this.project = project;
this.projectFileName = project.FileName;
this.projectMinimumSolutionVersion = project.MinimumSolutionVersion;
this.options = options;
this.feedbackSink = feedbackSink;
}
@ -163,6 +174,13 @@ namespace ICSharpCode.SharpDevelop.Project @@ -163,6 +174,13 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public bool ReportUnknownEvents { get; set; }
/// <summary>
/// Gets the name of the project file being compiled by this engine.
/// </summary>
public string ProjectFileName {
get { return projectFileName; }
}
List<string> interestingTasks = new List<string>();
string temporaryFileName;
@ -175,6 +193,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -175,6 +193,10 @@ namespace ICSharpCode.SharpDevelop.Project
get { return interestingTasks; }
}
readonly EventSource eventSource = new EventSource();
List<ILogger> loggers = new List<ILogger>();
IMSBuildChainedLoggerFilter loggerChain;
void StartBuild()
{
Dictionary<string, string> globalProperties = new Dictionary<string, string>();
@ -192,7 +214,6 @@ namespace ICSharpCode.SharpDevelop.Project @@ -192,7 +214,6 @@ namespace ICSharpCode.SharpDevelop.Project
InterestingTasks.AddRange(MSBuildEngine.CompileTaskNames);
List<ILogger> loggers = new List<ILogger>();
loggers.Add(new SharpDevelopLogger(this));
if (options.BuildOutputVerbosity == BuildOutputVerbosity.Diagnostic) {
this.ReportMessageEvents = true;
@ -207,10 +228,16 @@ namespace ICSharpCode.SharpDevelop.Project @@ -207,10 +228,16 @@ namespace ICSharpCode.SharpDevelop.Project
foreach (IMSBuildAdditionalLogger loggerProvider in MSBuildEngine.AdditionalMSBuildLoggers) {
loggers.Add(loggerProvider.CreateLogger(this));
}
loggerChain = new EndOfChain(this);
foreach (IMSBuildLoggerFilter loggerFilter in MSBuildEngine.MSBuildLoggerFilters) {
loggerChain = loggerFilter.CreateFilter(this, loggerChain) ?? loggerChain;
}
WriteAdditionalTargetsToTempFile(globalProperties);
BuildJob job = new BuildJob();
job.ProjectFileName = project.FileName;
job.ProjectFileName = projectFileName;
job.Target = options.Target.TargetName;
// First remove the flags for the controllable events.
@ -237,13 +264,25 @@ namespace ICSharpCode.SharpDevelop.Project @@ -237,13 +264,25 @@ namespace ICSharpCode.SharpDevelop.Project
job.Properties.Add(pair.Key, pair.Value);
}
if (project.MinimumSolutionVersion <= Solution.SolutionVersionVS2008) {
BuildWorkerManager.MSBuild35.RunBuildJob(job, loggers, feedbackSink);
foreach (ILogger logger in loggers) {
logger.Initialize(eventSource);
}
if (projectMinimumSolutionVersion <= Solution.SolutionVersionVS2008) {
BuildWorkerManager.MSBuild35.RunBuildJob(job, loggerChain, OnDone, feedbackSink.ProgressMonitor.CancellationToken);
} else {
BuildWorkerManager.MSBuild40.RunBuildJob(job, loggers, feedbackSink);
BuildWorkerManager.MSBuild40.RunBuildJob(job, loggerChain, OnDone, feedbackSink.ProgressMonitor.CancellationToken);
}
}
void OnDone(bool success)
{
foreach (ILogger logger in loggers) {
logger.Shutdown();
}
feedbackSink.Done(success);
}
void WriteAdditionalTargetsToTempFile(Dictionary<string, string> globalProperties)
{
// Using projects with in-memory modifications doesn't work with parallel build.
@ -273,7 +312,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -273,7 +312,7 @@ namespace ICSharpCode.SharpDevelop.Project
// 'MsTestToolsTargets' is preferred because it's at the end of the MSBuild 3.5 and 4.0 target file,
// but on MSBuild 2.0 we need to fall back to 'CodeAnalysisTargets'.
string hijackedProperty = "MsTestToolsTargets";
if (project.MinimumSolutionVersion == Solution.SolutionVersionVS2005)
if (projectMinimumSolutionVersion == Solution.SolutionVersionVS2005)
hijackedProperty = "CodeAnalysisTargets";
// because we'll replace the hijackedProperty, manually write the corresponding include
@ -295,33 +334,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -295,33 +334,7 @@ namespace ICSharpCode.SharpDevelop.Project
#endif
}
BuildError currentErrorOrWarning;
/// <summary>
/// Gets the last build error/warning created by the default
/// SharpDevelop logger.
/// </summary>
public BuildError CurrentErrorOrWarning {
get {
return currentErrorOrWarning;
}
}
Stack<string> projectFiles = new Stack<string>();
/// <summary>
/// Gets the name of the currently building project file.
/// </summary>
public string CurrentProjectFile {
get {
if (projectFiles.Count == 0)
return null;
else
return projectFiles.Peek();
}
}
public void OutputText(string message)
public void OutputTextLine(string message)
{
feedbackSink.ReportMessage(message);
}
@ -331,40 +344,33 @@ namespace ICSharpCode.SharpDevelop.Project @@ -331,40 +344,33 @@ namespace ICSharpCode.SharpDevelop.Project
feedbackSink.ReportError(error);
}
class SharpDevelopLogger : ILogger
sealed class EndOfChain : IMSBuildChainedLoggerFilter
{
MSBuildEngine worker;
public SharpDevelopLogger(MSBuildEngine engine)
{
this.worker = engine;
}
readonly MSBuildEngine engine;
void AppendLine(string text)
public EndOfChain(MSBuildEngine engine)
{
worker.OutputText(text);
this.engine = engine;
}
internal void FlushCurrentError()
public void HandleError(BuildError error)
{
if (worker.currentErrorOrWarning != null) {
worker.ReportError(worker.currentErrorOrWarning);
worker.currentErrorOrWarning = null;
}
engine.ReportError(error);
}
void OnProjectStarted(object sender, ProjectStartedEventArgs e)
public void HandleBuildEvent(Microsoft.Build.Framework.BuildEventArgs e)
{
worker.projectFiles.Push(e.ProjectFile);
engine.eventSource.ForwardEvent(e);
}
}
sealed class SharpDevelopLogger : ILogger
{
MSBuildEngine engine;
void OnProjectFinished(object sender, ProjectFinishedEventArgs e)
public SharpDevelopLogger(MSBuildEngine engine)
{
FlushCurrentError();
// it's possible that MSBuild raises ProjectFinished without a matching
// ProjectStarted - e.g. if an additional import is missing
if (worker.projectFiles.Count > 0)
worker.projectFiles.Pop();
this.engine = engine;
}
string activeTaskName;
@ -373,34 +379,28 @@ namespace ICSharpCode.SharpDevelop.Project @@ -373,34 +379,28 @@ namespace ICSharpCode.SharpDevelop.Project
{
activeTaskName = e.TaskName;
if (MSBuildEngine.CompileTaskNames.Contains(e.TaskName.ToLowerInvariant())) {
AppendLine(StringParser.Parse("${res:MainWindow.CompilerMessages.CompileVerb} " + Path.GetFileNameWithoutExtension(e.ProjectFile)));
engine.OutputTextLine(StringParser.Parse("${res:MainWindow.CompilerMessages.CompileVerb} " + Path.GetFileNameWithoutExtension(e.ProjectFile)));
}
}
void OnTaskFinished(object sender, TaskFinishedEventArgs e)
{
FlushCurrentError();
}
void OnError(object sender, BuildErrorEventArgs e)
{
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, false);
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile, e.Subcategory, e.HelpKeyword, false);
}
void OnWarning(object sender, BuildWarningEventArgs e)
{
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, true);
AppendError(e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile, e.Subcategory, e.HelpKeyword, true);
}
// TODO: Add XmlDocBloc to MSBuildError.AppendError()
void AppendError(string file, int lineNumber, int columnNumber, string code, string message, bool isWarning)
void AppendError(string file, int lineNumber, int columnNumber, string code, string message, string projectFile, string subcategory, string helpKeyword, bool isWarning)
{
if (string.Equals(file, activeTaskName, StringComparison.OrdinalIgnoreCase)) {
file = "";
} else if (FileUtility.IsValidPath(file)) {
bool isShortFileName = file == Path.GetFileNameWithoutExtension(file);
if (worker.CurrentProjectFile != null) {
file = Path.Combine(Path.GetDirectoryName(worker.CurrentProjectFile), file);
if (projectFile != null) {
file = Path.Combine(Path.GetDirectoryName(projectFile), file);
}
if (isShortFileName && !File.Exists(file)) {
file = "";
@ -413,10 +413,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -413,10 +413,11 @@ namespace ICSharpCode.SharpDevelop.Project
file = "";
}
}
FlushCurrentError();
BuildError error = new BuildError(file, lineNumber, columnNumber, code, message);
error.IsWarning = isWarning;
worker.currentErrorOrWarning = error;
error.Subcategory = subcategory;
error.HelpKeyword = helpKeyword;
engine.loggerChain.HandleError(error);
}
#region ILogger interface implementation
@ -425,10 +426,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -425,10 +426,7 @@ namespace ICSharpCode.SharpDevelop.Project
public void Initialize(IEventSource eventSource)
{
eventSource.ProjectStarted += OnProjectStarted;
eventSource.ProjectFinished += OnProjectFinished;
eventSource.TaskStarted += OnTaskStarted;
eventSource.TaskFinished += OnTaskFinished;
eventSource.ErrorRaised += OnError;
eventSource.WarningRaised += OnWarning;
@ -436,10 +434,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -436,10 +434,9 @@ namespace ICSharpCode.SharpDevelop.Project
public void Shutdown()
{
FlushCurrentError();
if (worker.temporaryFileName != null) {
File.Delete(worker.temporaryFileName);
worker.temporaryFileName = null;
if (engine.temporaryFileName != null) {
File.Delete(engine.temporaryFileName);
engine.temporaryFileName = null;
}
}
#endregion

136
src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildLoggerFilter.cs

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.Core;
using Microsoft.Build.Framework;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// Interface for elements in /SharpDevelop/MSBuildEngine/LoggerFilters
/// </summary>
public interface IMSBuildLoggerFilter
{
IMSBuildChainedLoggerFilter CreateFilter(MSBuildEngine engine, IMSBuildChainedLoggerFilter nextFilter);
}
/// <summary>
/// Element in the logger filter chain.
/// Receives build events and errors and forwards them to the next element in the chain (possibly after modifying the event).
/// </summary>
public interface IMSBuildChainedLoggerFilter
{
void HandleError(BuildError error);
void HandleBuildEvent(Microsoft.Build.Framework.BuildEventArgs e);
}
/// <summary>
/// Creates <see cref="IMSBuildLoggerFilter"/> objects that are only
/// activated when a specific MSBuild task is running.
/// </summary>
/// <attribute name="class" use="required">
/// Name of the IMSBuildLoggerFilter class.
/// </attribute>
/// <attribute name="taskname" use="required">
/// Specifies the name of the MSBuild task that must be running for
/// this logger to be active.
/// </attribute>
/// <example>
/// &lt;TaskBoundLoggerFilter
/// id = "FxCopLogger"
/// taskname = "FxCop"
/// class = "ICSharpCode.CodeAnalysis.FxCopLoggerFilter"/&gt;
/// </example>
/// <usage>Only in /SharpDevelop/MSBuildEngine/LoggerFilters</usage>
/// <returns>
/// A IMSBuildLoggerFilter object that lazy-loads the specified
/// IMSBuildLoggerFilter when the specified task is running.
/// </returns>
public class TaskBoundLoggerFilterDoozer : IDoozer
{
public bool HandleConditions {
get {
return false;
}
}
public object BuildItem(object caller, Codon codon, System.Collections.ArrayList subItems)
{
return new TaskBoundLoggerFilterDescriptor(codon);
}
sealed class TaskBoundLoggerFilterDescriptor : IMSBuildLoggerFilter
{
internal string taskname;
internal string classname;
internal AddIn addIn;
public TaskBoundLoggerFilterDescriptor(Codon codon)
{
classname = codon.Properties["class"];
taskname = codon.Properties["taskname"];
addIn = codon.AddIn;
}
public IMSBuildChainedLoggerFilter CreateFilter(MSBuildEngine engine, IMSBuildChainedLoggerFilter nextFilter)
{
if (nextFilter == null)
throw new ArgumentNullException("nextFilter");
// Create a Filter that tracks whether the task is active.
// If active, forward to 'baseFilter', otherwise forward to 'nextFilter'.
return new TaskBoundLoggerFilter(this, engine, nextFilter);
}
}
sealed class TaskBoundLoggerFilter : IMSBuildChainedLoggerFilter
{
readonly TaskBoundLoggerFilterDescriptor desc;
readonly MSBuildEngine engine;
readonly IMSBuildChainedLoggerFilter nextFilter;
IMSBuildChainedLoggerFilter baseFilter = null;
bool insideTask = false;
public TaskBoundLoggerFilter(TaskBoundLoggerFilterDescriptor desc, MSBuildEngine engine, IMSBuildChainedLoggerFilter nextFilter)
{
this.desc = desc;
this.engine = engine;
this.nextFilter = nextFilter;
}
public void HandleError(BuildError error)
{
if (insideTask)
baseFilter.HandleError(error);
else
nextFilter.HandleError(error);
}
public void HandleBuildEvent(Microsoft.Build.Framework.BuildEventArgs e)
{
TaskStartedEventArgs start = e as TaskStartedEventArgs;
if (start != null && string.Equals(start.TaskName, desc.taskname, StringComparison.OrdinalIgnoreCase)) {
insideTask = true;
if (baseFilter == null) {
IMSBuildLoggerFilter baseLoggerFilter = (IMSBuildLoggerFilter)desc.addIn.CreateObject(desc.classname);
if (baseLoggerFilter != null)
baseFilter = baseLoggerFilter.CreateFilter(engine, nextFilter) ?? nextFilter;
else
baseFilter = nextFilter;
}
}
if (insideTask)
baseFilter.HandleBuildEvent(e);
else
nextFilter.HandleBuildEvent(e);
if (insideTask && e is TaskFinishedEventArgs) {
insideTask = false;
}
}
}
}
}

2
src/Main/ICSharpCode.Core.Presentation/NumericUpDown.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Core.Presentation @@ -31,7 +31,7 @@ namespace ICSharpCode.Core.Presentation
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown),
new FrameworkPropertyMetadata(typeof(NumericUpDown)));
}
TextBox textBox;
DragRepeatButton upButton;
DragRepeatButton downButton;

Loading…
Cancel
Save