Когда solution-файл содержит достаточно большое число проектов, сборка бинарных файлов превращается в процесс, требующий ощутимого количества времени, а отчет о сборке в простыню размером в несколько мегабайт. Лично у меня подобная строка в самом конце при таких масштабах вызывает недоумение:
А помимо недоумения закономерный вопрос: а что, собственно, сломалось? Есть, конечно, вкладка «Error list», но она к сожалению не показывает названий проектов — только файлы, а при таком объеме исходного кода, да с учетом того факта, что над этим solution'ом работает большая команда, довольно проблематично определять на память принадлежность того или иного файла к определенному проекту (читай определять виновных в сломанной сборке). Пролистывать же отчет в поисках имени проекта, содержащего ошибки, на мой взгляд, не совсем целесообразно.
Принимая во внимание всё вышесказанное, я решил совместить приятное с полезным, получив небольшое представление о том, что же такое VS Exstensibility, снабдив при этом студию маленьким «удобством». «Удобство» должно позволять одним кликом мыши отсеять все ненужное из отчета о сборке, оставив только сообщения об ошибках и имена проектов, их содержащие.
Всё оказалось довольно просто. Начиная с готового шаблона проекта:
и заканчивая довольно очевидным набором классов, который позволяет практически не заглядывать в документацию, пользуясь лишь подсказками редактора.
После создания проекта генерируется довольно много кода (выбор языка предоставляется; в моем случае — C#). По сути интересны там только два места: методы OnConnect и Exec, где первый, как несложно догадаться инициализация, а второй непосредственная реализация нашей логики.
OnConnect нам необходим только для того, чтобы сделать новый пункт в меню «Tools». По факту, в сгенерированном для нас коде всё это уже есть, нам остаётсяь только подкорректировать само создание команды:
========== Build: 258 succeeded, 1 failed, 40 up-to-date, 1 skipped ==========
А помимо недоумения закономерный вопрос: а что, собственно, сломалось? Есть, конечно, вкладка «Error list», но она к сожалению не показывает названий проектов — только файлы, а при таком объеме исходного кода, да с учетом того факта, что над этим solution'ом работает большая команда, довольно проблематично определять на память принадлежность того или иного файла к определенному проекту (читай определять виновных в сломанной сборке). Пролистывать же отчет в поисках имени проекта, содержащего ошибки, на мой взгляд, не совсем целесообразно.
Принимая во внимание всё вышесказанное, я решил совместить приятное с полезным, получив небольшое представление о том, что же такое VS Exstensibility, снабдив при этом студию маленьким «удобством». «Удобство» должно позволять одним кликом мыши отсеять все ненужное из отчета о сборке, оставив только сообщения об ошибках и имена проектов, их содержащие.
Всё оказалось довольно просто. Начиная с готового шаблона проекта:
и заканчивая довольно очевидным набором классов, который позволяет практически не заглядывать в документацию, пользуясь лишь подсказками редактора.
После создания проекта генерируется довольно много кода (выбор языка предоставляется; в моем случае — C#). По сути интересны там только два места: методы OnConnect и Exec, где первый, как несложно догадаться инициализация, а второй непосредственная реализация нашей логики.
OnConnect нам необходим только для того, чтобы сделать новый пункт в меню «Tools». По факту, в сгенерированном для нас коде всё это уже есть, нам остаётсяь только подкорректировать само создание команды:
try
{
//Add a command to the Commands collection:
Command command = commands.AddNamedCommand2(_addInInstance,
"BuildStat",
"Show failed build parts",
"Provides information about failed parts of performed solution build",
true,
56,
ref contextGUIDS,
(int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled,
(int)vsCommandStyle.vsCommandStylePictAndText,
vsCommandControlType.vsCommandControlTypeButton);
//Add a control for the command to the tools menu:
if((command != null) && (toolsPopup != null))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch(System.ArgumentException)
{
//If we are here, then the exception is probably because a command with that name
// already exists. If so there is no need to recreate the command and we can
// safely ignore the exception.
}
* This source code was highlighted with Source Code Highlighter.
В итоге получим:
Остается реализовать фильтрацию отчета о сборке. Для этого, нам необходимо получить сам отчет из окна «Output/Build», оставить только необходимое, создать в окне «Output» новую панель и заполнить ее результатами работы. Соответственно, метод Exec примет следующий вид:
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "BuildStat.Connect.BuildStat")
{
handled = true;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if(pane.Name == "Build")
{
// нашлась нужная нам вкладка
TextDocument textDocument = pane.TextDocument;
textDocument.Selection.StartOfDocument(false);
textDocument.Selection.EndOfDocument(true);
String buildLog = textDocument.Selection.Text;
if(buildLog.Length > 0)
{
string parsedLog = Parse(buildLog);
if (parsedLog.Length > 0)
Output(parsedLog);
}
break;
}
}
return;
}
}
}
* This source code was highlighted with Source Code Highlighter.
Немного работы со строками:
private string Parse(string buildLog)
{
String parseResult = "";
StringReader logReader = new StringReader(buildLog);
Regex failedProjects = new Regex("[1-9][0-9]* error\\(s\\), [0-9]+ warning\\(s\\)");
for (string line = logReader.ReadLine(); line != null; line = logReader.ReadLine())
{
if(failedProjects.IsMatch(line))
{
parseResult += line;
parseResult += "\r\n";
}
if ((line.IndexOf(": error") != -1) || (line.IndexOf(": fatal error") != -1))
{
parseResult += line;
parseResult += "\r\n";
}
}
return parseResult;
}
* This source code was highlighted with Source Code Highlighter.
И сам вывод на экран:
private void Output(string outputString)
{
OutputWindowPane myPane = null;
foreach (OutputWindowPane pane in _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes)
{
if (pane.Name == "Build [failed]")
{
myPane = pane;
break;
}
}
if (myPane == null)
myPane = _applicationObject.ToolWindows.OutputWindow.OutputWindowPanes.Add("Build [failed]");
myPane.Clear();
myPane.OutputString(outputString);
myPane.Activate();
}
* This source code was highlighted with Source Code Highlighter.
И вот он результат:
Для установки модуля необходимо присутствующий в проекте .AddIn файл скопировать в «Мои документы\Visual Studio <версия>\Addins», не забыв при этом поправить в нем необходимые поля, например, пути.
P.S. Ощущение того, что изобрел велосипед, присутствует, но совокупность таких факторов, как всего 30 минут потраченного времени и небольшая порция полученного удовольствия все компенсирует.