MSBuild как и его свободный брат XBuild предназначены для автоматизации процессов сборки решений. В этой статье я попробовал собрать самые интересные и полезные моменты их использования. Это не быстрый обзор для начинающего, а закрепление знания для практикующего. Возможно, некоторые советы вам пригодятся для написания своих скриптов.
Отладка
Мало кто знает, но XML MSBuild можно запустить в режиме отладки. С ее помощью можно просмотреть текущие значения параметров и групп. Включается отладка не тривиально, и требует изменений в реестре. Для включения недокументированного параметра — /debug, используйте следующую команду:
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\4.0" /v debuggerenabled=true /d true
После этого, комманда MSBuild /? должна показать дополнительную опцию — debug. Если запустить скрипт с этим параметром, система предложит подключить Visual Studio к процессу. В ней можно выставлять точки прерывания (breakpoints) и анализировать скрипт.
Трансформации XML файлов с помощью Document Transform синтаксиса.
Я уже рассказывал о возможности трансформаций конфигурационных файлов с помощью упрощенного синтаксиса. Во время выполнения скрипта можно преобразовать XML файлы соответственно параметрам. Подробно трансформации можно узнать из моего предыдущего поста. Тут правда есть несколько подводных камней, с которыми придется бороться:
- TransformXml не может изменять файл который читает. Destination — это всегда новый файл.
- MSBuild не отпускает файлы до завершения скрипта, по этому сделать несколько преобразований с одним файлом просто так не получится. Как вариант, каждый раз копировать файл во временный каталог.
Логирование результатов в файл.
Самый простой способ, воспользоватся цепочками консоли и перевести весь вывод в отдельный файл: msbuild script.xml > out.txt. Но в некоторых случаях (continious integration, запись промежуточных результатов с целью их чтения или преобразования и т.д.) это может не подойти. Не надо писать велосипед. Присмотритесь к стандартной библиотеке скриптов! Все делается легко и просто:
<WriteLinestoFile File="log.txt" Lines="[$(NowDate)] Some log information." />
Вызов CLR методов, совсем как в PowerShell.
В предыдущем примере используется параметр NowDate. Получить текущую дату можно с помощью CLR:
<NowDate>$([System.DateTime]::Now.ToString("dd.MM.yyyy hh:mm"))</NowDate>
Переопределение переменных
Еще один полезный прием, это инициализация пустых переменных, значениями по умолчанию. Предположим, что есть основная конфигурация, которая может меняется в зависимости от локальных настроек или целевой системы, для который происходит сборка. Получается 3 файла:
- Файл пользовательской конфигурации. Тут переопределяются значения, отличающиеся от стандартных.
- Файл стандартной конфигурации (значения по умолчанию). Тут нужно задавать значения только пустым параметрам.
- Собственно сама логика скрипта (включает 2 первых по порядку).
Вот таким образом декларируются значения по умолчанию:
<Param1 Condition=" '$(Param1)' == '' ">default value for Param1</Param1>
Дело в том, что выражения получения значения переменной выполняется сразу. Если у вас составная переменная, например в этом случае
<BookFile>${ContentRoot}/Books.xml</BookFile>
нужно будет переопределять обе переменные и ContentRoot и BookFile.
Циклы
Это больная тема MSBuild скриптов. Предположим у нас есть набор конфигураций с которыми нужно выполнить таск:
<ItemGroup> <Configs Include="Name1"> <Environment>Env1</Environment> <Url>env1.test.com</CmsUrl> </Configs> <Configs Include="Name2"> <Environment>Env2</Environment> <Url>env2.test.com</CmsUrl> </Configs> </ItemGroup>
Выполнить таск к каждому элементу из Configs можно так:
<Target Name="ConfigsTarget"> <Message Text="Target called for $(Name) Env: $(Environment) Url: $(Url)" /> </Target> <MSBuild Projects="$(MSBuildProjectFile)" Properties="Name=%(Configs.Identity);Environment=%(Configs.Environment);Url=%(Configs.Url)" Targets="ConfigsTarget" />
Пользовательские таски.
Написать таск для MSBuild проще чем может показаться. Это класс-наследник от Microsoft.Build.Utilities.Task.
Чтобы таск можно было использовать в скрипте, его надо за декларировать с помощью UsingTask:
<UsingTask AssemblyFile="BinaryAnalysis.Tasks" TaskName="BinaryAnalysis.Tasks.MyTask"/>
После этого его можно использовать по названию.
Готовые таски
Прежде чем писать свой таск для билда, убедитесь что вы не изобретаете велосипед (в 80% случаев это именно так). Вот несколько сборок, которые могут пригодится:
- Таски от Tigris. Еще известен как Community Tasks.
- MSBuild extension pack
- И еще куча в интернете для отдельных нужд.
Метки:C#, разработка, OpenSource, обзор
Похожие статьи
- 21 сентября 2010 -- Программирование искусственного интеллекта от Google (11)
- 24 июня 2011 -- Установка Mono 2.10.2 и MonoDevelop 2.6 на Debian (1)
- 25 сентября 2011 -- Трансформации. Web.config и App.config для «C# продолжающих». (2)
- 19 сентября 2010 -- StringTemplate на C#. (Часть 1) (0)
- 20 мая 2008 -- Open source проекты на C# .NET. (0)
3 января, 2012 at 16:34
Вот еще забыл добавить интересный трюк: Вытаскиваем версию сборки и на основе нее делаем архив:
<getassemblyidentity AssemblyFiles="$(SourceCmsDirectory)\bin\MyLibrary.dll">
<output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities"/>
</getassemblyidentity>
<propertygroup>
<version>%(MyAssemblyIdentities.Version)</version>
</propertygroup>
После этого $Verions будет содержать версию сборки MyLibrary.dll
9 июля, 2013 at 22:51
Доброго времени суток.
Ваш код в разделе с циклами неверен. Во первых — открывающемуся тэгу Url у Вас противопоставлен закрывающийся CmsUrl. Во вторых, MSBuild — это задача. Соответственно она, как минимум, должна находится в теле Target.
С уважением, Андрей.
16 августа, 2013 at 17:56
Огромное спасибо!
Именно то что я искал, столкнулся с тем что необходимо распарсить вводимые пользователем TeamCity параметры и по ним проехаться циклом.
Так же очень полезно было узнать про возможность дебажить.
16 августа, 2013 at 18:42
в команде включения дебага — debuggerenabled=true не верно, нужно просто debuggerenabled.