- PVSM.RU - https://www.pvsm.ru -

Автоматизация сборки .NET приложений — часть 2

Автоматизация сборки .NET приложений — часть 2

Три года назад я писал статью [1] про автоматизацию сборки .NET приложений. Планировалось, что она будет из двух частей. Первая часть — основы использования NAnt [2] и примеры выполнения базовых задач (компиляция проекта, сборка сайта ASP.NET). Во второй части хотел рассказать о более продвинутых задачах типа трансформации конфигов, запуска модульных тестов и т.п.

Когда вторая часть была почти готова, перечитал ее и понял, что получился пересказ документации NAnt. Вне контекста реальных задач он бесполезен, а если возникнет необходимость, всю нужную информацию легко найти в гугле. В результате, статья до сих пор лежит в черновиках.

Сейчас я хотел бы предложить вашему вниманию вторую часть, но немного на другую тему, чем планировалось изначально. Я расскажу о написании собственных тасков для NAnt, а также сделаю небольшой обзор библиотеки с тасками, которую я писал для себя последние 4 года. Если интересно, добро пожаловать под кат…

Написание собственных тасков

Таск (task) — это элемент билд-скрипта, который выполняет определенное действие (например, копирует файл в другую папку или запускает модульные тесты). Таск может содержать параметры. Например, таск regasm [3] регистрирует COM-объекты из заданной библиотеки, а его параметром является путь к нужному файлу .dll.

<regasm assembly="myAssembly.dll" />

NAnt уже содержит большое [4] количество [5] тасков для решения разнообразных задач, но, к сожалению, иногда их не хватает. В этом случае, вы можете написать собственные таски, выполняющие нужные действия и использовать их в своих билд-скриптах. Сделать это очень легко!

Каждый таск — это класс .NET, унаследованный от базового класса NAnt.Core.Task (из библиотеки NAnt.Core.dll). Для написания собственного таска открываем Visual Studio, создаем новый проект Class Library, добавляем ссылку на NAnt.Core.dll и создаем примерно такой класс:

[TaskName("my-task")]
public class MyTask : NAnt.Core.Task
{
	protected override void ExecuteTask()
	{
		// TODO: здесь выполняются нужные действия
		System.IO.File.WriteAllText("Hello, world!");
	}
}

NAnt.Core.Task — абстрактный класс, все наследники которого должны содержать собственную реализацию абстрактного метода void ExecuteTask() — именно в нем и выполняются те действия, для которых предназначен таск. Для того, чтобы задать имя XML-тэга, которое будет потом использоваться в билд-скриптах, нужно пометить созданный класс атрибутом TaskName.

Для передачи параметров добавьте в класс свойства и отметьте их атрибутом TaskAttribute. Во время выполнения в этих свойствах будут находиться значения, указанные в параметрах таска в билд-скрипте.
Обратите внимание, для передачи в параметрах пути к файлам удобнее использовать свойства типа System.IO.FileInfo, а не string.

[TaskAttribute("path", Required = true)]
public string Path { get; set; }

Для записи сообщений в лог используйте метод Log из базового класса.

Log(Level.Warning, "Файл не найден");

Использование и отладка собственных тасков

Для использования в билд-скрипте собственных тасков нужно подключить свою скомпилированную библиотеку при помощи команды loadtasks, а потом вызвать нужные таски, используя имя, заданное в атрибуте TaskName.

<loadtasks assembly="MyLibrary.dll" />
<my-task path="D:temp" />

Для отладки своего таска добавьте в нужное меcто вызов статического метода System.Diagnostics.Debugger.Launch() и соберите библиотеку в режиме Debug. При запуске таска через NAnt в указанном месте выполнение скрипта остановится и вам будет предложено запустить для отладки Visual Studio.

Библиотека ECM7.NantContrib

За последние несколько лет мне периодически приходилось писать собственные таски для решения разных специфических задач. Я добавлял все их в один общий проект [6] (исходный код лежит на code.google.com) и сейчас там накопилось уже довольно много интересного. Ниже приведены примеры его использования. Надеюсь, это пригодится кому-нибудь.

Создание новой базы данных MSSQL

<createDatabase database="dbname" instance="." integratedSecurity="true" />

Бэкап базы данных MSSQL

<!-- integrated security -->
<backupDatabase database="dbname" instance="." integratedSecurity="true" backupFileName="d:test.bak" />
<!-- user & password -->
<backupDatabase database="dbname" instance="." user="sa" password="123" backupFileName="d:test.bak" />

Добавление пользователям MSSQL прав на базу данных (пользователям добавляется роль db_owner; если пользователи не существуют, они создаются)

<addDatabaseUsers database="dbname" instance="." integratedSecurity="true">
	<user login="IIS APPPOOLtest" isWindowsUser="true" />
	<user login="test1" password="123" />
	<user login="test2" password="qwert" />
</addDatabaseUsers>

Минификация JS и CSS (использует YUI Compressor for .NET [7]):

<minify-js obfuscate-js="true" with-line-breaks="true" disable-optimizations="true">
	<files>
		<include name="test2.js" />
		<include name="test.js" />
	</files>
</minify-js>

<minify-css compression-type="hybrid" with-line-breaks="true">
	<files>
		<include name="*.css" />
	</files>		
</minify-css>

Компиляция .LESS файлов (используется DotLess [8]):

<compile-less file="D:projectsecm7milkmilk.less" result="D:milk.min.css" />

Создание сайта в IIS

<createIISWebSite websiteName="xxx3.ru" fileSystemPath="d:xxx3.ru" appPool="xxx3.ru">
	<bindings>
		<add host="localhost" port="4898" protocol="http" />
		<add host="xxx3.ru" />
	</bindings>
</createIISWebSite>

Создание application и виртуальных каталогов в IIS

<createIISApplication websiteName="xxx3.ru" virtualPath="/admin" fileSystemPath="d:/admin" />
<createIISDirectory websiteName="xxx3.ru" applicationVirtualPath="/admin" virtualPath="/images" fileSystemPath="d:/images" />

XDT-трансформация XML-файлов

<xdt target="test.xml">
	<transformation>
		<moo1 xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
			<moo2 xdt:Transform="Insert">123</moo2>
			<rewrite xdt:Transform="Insert">
				<a1>456!</a1>
			</rewrite>
		</moo1>
	</transformation>
</xdt>

XDT-трансформация XML-файлов (параметры трансформации вынесены отдельно)

<!-- в другое место билд-скрипта  -->
<xdt target="test.xml">
	<transformation refid="mimimi" />
</xdt>
...
<raw-xml id="mimimi">
	<moo1 xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
		<moo2 xdt:Transform="Insert">123!</moo2>
		<rewrite xdt:Transform="Insert" xxx2="${test.property}" aaa="bbbb">
			<a1 xxx1="${test.property}">456!</a1>
		</rewrite>
	</moo1>
</raw-xml>

<!-- в отдельный файл  -->
<xdt target="test.xml">
	<transformation file="transform.xml" />
</xdt>

Обратите внимание, внутри файлов с описанием трансформации можно использовать выражения NAnt.

В принципе, это все, что я хотел вам рассказать. Надеюсь, это кому-нибудь пригодится и буду рад ответить на вопросы.
Спасибо за внимание!

Автор: dima117

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka/41171

Ссылки в тексте:

[1] статью: http://habrahabr.ru/post/101183/

[2] NAnt: http://nant.sourceforge.net/

[3] regasm: http://nant.sourceforge.net/release/0.92/help/tasks/regasm.html

[4] большое: http://nant.sourceforge.net/release/0.92/help/tasks/index.html

[5] количество: http://nantcontrib.sourceforge.net/help/tasks/

[6] один общий проект: http://code.google.com/p/ecm7nantcontrib/

[7] YUI Compressor for .NET: http://yuicompressor.codeplex.com/

[8] DotLess: http://www.dotlesscss.org

[9] Источник: http://habrahabr.ru/post/189190/