MSBuild: как получить количество поднятых предупреждений?
Существует скрипт MSBuild, который включает в себя ряд проектов на Delphi и C#, модульные тесты и т. д.
Проблема заключается в следующем: как отметить неудавшуюся сборку, если были вызваны предупреждения (для целей тестирования, а не для сборок выпуска)? Использование LogError вместо LogWarning в пользовательских задачах кажется не очень хорошим вариантом, потому что сборка должна тестировать столько, сколько она может (до реальной ошибки) сообщить как можно больше предупреждений за один раз (проект сборки использует в CruiseControl.NET).
Может быть, решение состоит в том, чтобы создать свой собственный регистратор, который будет хранить флаг предупреждения внутри, но я не могу найти, есть ли способ прочитать этот флаг в конце сборки?
P.S. сразу после получения предупреждения выполнить сборку не проблема (вывод компилятора Delphi обрабатывается пользовательской задачей, и /warnaserror может быть использован для C#), но желаемое поведение - "построить все; собрать все предупреждения; не выполнить сборку", чтобы сообщить обо всех предупреждениях, а не только о первом предупреждении. один.
Поскольку мне действительно нужно не количество предупреждений, а просто флаг их наличия, я решил упростить механизм сигнализации и использовать тривиальный мьютекс вместо общей памяти. Код ниже:
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Threading;
namespace Intrahealth.Build.WarningLogger
{
public sealed class WarningLoggerCheck : Task
{
public override bool Execute()
{
Log.LogMessage("WarningLoggerCheck:" + mutexName + "...");
result = false;
Mutex m = null;
try
{
m = Mutex.OpenExisting(mutexName);
}
catch (WaitHandleCannotBeOpenedException)
{
result = true;
}
catch (Exception)
{
}
if (result)
Log.LogMessage("WarningLoggerCheck PASSED");
else
Log.LogError("Build log contains warnings. Build is FAILED");
return result;
}
private bool result = true;
[Output]
public bool Result
{
get { return result; }
}
private string mutexName = "WarningLoggerMutex";
public string MutexName
{
get { return mutexName; }
set { mutexName = value ?? "WarningLoggerMutex"; }
}
}
public class WarningLogger : Logger
{
internal static int warningsCount = 0;
private string mutexName = String.Empty;
private Mutex mutex = null;
public override void Initialize(IEventSource eventSource)
{
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
}
private void SetMutex()
{
if (mutexName == String.Empty)
{
mutexName = "WarningLoggerMutex";
if (this.Parameters != null && this.Parameters != String.Empty)
{
mutexName = this.Parameters;
}
}
mutex = new Mutex(false, mutexName);
}
void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
if (e.Message != null && e.Message.Contains("MSB3146"))
return;
if (e.Code != null && e.Code.Equals("MSB3146"))
return;
if (warningsCount == 0)
SetMutex();
warningsCount++;
}
}
}
3 ответа:
AFAIK MSBuild не имеет встроенной поддержки для получения количества предупреждений в заданной точке сценария сборки. Однако вы можете выполнить следующие шаги для достижения этой цели:
- создайте пользовательский регистратор, который прослушивает событие предупреждения и подсчитывает количество предупреждений
- создайте пользовательскую задачу, которая предоставляет свойство WarningCount [Output]
- пользовательская задача каким-то образом получает значение количества предупреждений от пользовательского регистратора
Самый трудный шаг-это шаг 3. Для этого есть несколько вариантов,и вы можете свободно искать их в разделе IPC-Inter Process Comunication. Ниже приведен рабочий пример того, как вы можете достичь этого. Каждый элемент-это отдельная библиотека классов .
SharedMemory
Http://weblogs.asp.net/rosherove/archive/2003/05/01/6295.aspx
Я создал оболочку для named общая память, которая была частью большой проект. Это в основном позволяет сериализованные типы и объект графики, чтобы храниться и извлекаться из общего доступа память (в том числе, как и следовало ожидать перекрестный процесс). Будь то крупнее проект когда-либо завершается-это другое вопрос ;-).
SampleLogger
Реализует пользовательский регистратор, который отслеживает количество предупреждений.
namespace SampleLogger { using System; using Microsoft.Build.Utilities; using Microsoft.Build.Framework; using DM.SharedMemory; public class MySimpleLogger : Logger { private Segment s; private int warningCount; public override void Initialize(IEventSource eventSource) { eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised); this.s = new Segment("MSBuildMetadata", SharedMemoryCreationFlag.Create, 65535); this.s.SetData(this.warningCount.ToString()); } void eventSource_WarningRaised(object sender, BuildWarningEventArgs e) { this.warningCount++; this.s.SetData(this.warningCount.ToString()); } public override void Shutdown() { this.s.Dispose(); base.Shutdown(); } } }
SampleTasks
Реализует пользовательскую задачу, считывающую количество предупреждений, вызванных в проекте MSbuild. Пользовательская задача считывает данные из общей памяти, записанной пользовательским регистратором, реализованным в библиотеке классовSampleLogger .
namespace SampleTasks { using System; using Microsoft.Build.Utilities; using Microsoft.Build.Framework; using DM.SharedMemory; public class BuildMetadata : Task { public int warningCount; [Output] public int WarningCount { get { Segment s = new Segment("MSBuildMetadata", SharedMemoryCreationFlag.Attach, 0); int warningCount = Int32.Parse(s.GetData() as string); return warningCount; } } public override bool Execute() { return true; } } }
Иду на спин.
<?xml version="1.0" encoding="UTF-8"?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Main"> <UsingTask TaskName="BuildMetadata" AssemblyFile="F:\temp\SampleLogger\bin\debug\SampleTasks.dll" /> <Target Name="Main"> <Warning Text="Sample warning #1" /> <Warning Text="Sample warning #2" /> <BuildMetadata> <Output TaskParameter="WarningCount" PropertyName="WarningCount" /> </BuildMetadata> <Error Text="A total of $(WarningCount) warning(s) were raised." Condition="$(WarningCount) > 0" /> </Target> </Project>
Если вы выполните следующую команду:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild test.xml /logger:SampleLogger.dll
Это будет выход:
Microsoft (R) Build Engine Version 2.0.50727.3053 [Microsoft .NET Framework, Version 2.0.50727.3053] Copyright (C) Microsoft Corporation 2005. All rights reserved. Build started 30-09-2008 13:04:39. __________________________________________________ Project "F:\temp\SampleLogger\bin\debug\test.xml" (default targets): Target Main: F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #1 F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #2 F:\temp\SampleLogger\bin\debug\test.xml(15,3): error : A total of 2 warning(s) were raised. Done building target "Main" in project "test.xml" -- FAILED. Done building project "test.xml" -- FAILED. Build FAILED. F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #1 F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #2 F:\temp\SampleLogger\bin\debug\test.xml(15,3): error : A total of 2 warning(s) were raised. 2 Warning(s) 1 Error(s) Time Elapsed 00:00:00.01
Компилятор C# (csc.exe) имеет переключатель / warnaserror, который будет рассматривать предупреждения как ошибки и завершит сборку. Это также доступно в качестве настройки в .файл csproj. Полагаю, у Дельфи есть такая же способность.
msbuild.exe %~nx1 /t:Rebuild /p:Configuration=Release >> %MrB-BUILDLOG% findstr /r /c:"[1-9][0-9]* Error(s)" >> %MrB-BUILDLOG% if not errorlevel 1 ( echo ERROR: sending notification email for build errors in '%~nx1'. >> %MrB-BUILDLOG% ) else ( findstr /r /c:"[1-9][0-9]* Warning(s)" >> %MrB-BUILDLOG% if not errorlevel 1 ( echo ERROR: sending notification email for build warnings in '%~nx1'. >>
%MrB-BUILDLOG% ) еще ( Эхо успешной сборки '%~NX1 по'. > > %MrB-BUILDLOG% ) )