среда, 8 февраля 2012 г.

Разработка пакетов NuGet + инфраструктура

В статье "Model scaffolding для MVC 3 – идеи и принципы" я рассказал об идеях и принципах, заложенных в основу пакета Model Scaffolding. Сейчас я расскажу о следующем:

  • Как написать простой пакет NuGet.
  • Как подготовить инфраструктуру для разработки и отладки пакетов NuGet.
  • Как начать реализовывать свой Scaffolder (генератор чего-либо в любом вашем проекте, необязательно ASP.NET MVC).

Важное замечание: после выхода NuGet 1.6 вы можете столкнуться с неожиданными ошибками при установке любых пакетов NuGet для Scaffolding (мои пакеты зависят от T4Scaffolding). В этом случае рекомендую такую последовательность:

  • Uninstall NuGet.
  • Install NuGet.
  • Затем то же самое для всех Scaffolding-пакетов (с учетом зависимостей некоторые установятся сами).

NuGet

Scaffolder имеет смысл делать именно NuGet-пакетом, поэтому коротко расскажу о том что это и как создать и опубликовать пакет в простом случае (подробнее можно почитать в документации). Про возможности NuGet я уже рассказывал раньше, в статье MVC 3 + scaffolding.

NuGet-пакет формируется из набора файлов с помощью файла спецификации и приложения NuGet.exe. Затем его можно опубликовать на NuGet.org или на другом (например, своем) сервере. Также можно просто скопировать в некоторую папку, а папку добавить в настройки Visual Studio (Tools / Library Package Manager / Package Manager Settings). Так что, если хотите использовать возможности NuGet в своей закрытой разработке – это тоже возможно.

Публикация

При установке содержимое пакета может копироваться в папки Content и Scripts, а также могут выполняться PowerShell-скрипты на определенные события. Для того, чтобы опубликовать пакет на NuGet.org, необходимо:

  1. Зарегистрироваться на NuGet.org.
  2. Загрузить NuGet.exe, добавить его в PATH.
  3. Запустить cmd/powershell и установить свой API key (его можно скопировать на сайте в своем аккаунте) – это разовая операция:
    nuget setApiKey <Ваш API Key>
  4. Реализовать, собственно, логику своего пакета :)
  5. Создать файл спецификации:
    nuget spec
  6. Заполнить спецификацию правильными данными.
  7. Запаковать файлы в пакет:
    NuGet Pack <Название пакета>.nuspec
  8. Опубликовать пакет на сервере (эту операцию в случае закрытой разработки или предварительной отладки естественно делать не надо):
    NuGet Push <Название пакета>.nupkg

После этого можно проверить страницу пакета на сайте (у меня, например, это http://nuget.org/List/Packages/ModelScaffolding).

Спецификация

На данный момент содержимое моего файла ModelScaffolding.nuspec следующее:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>ModelScaffolding</id>
<version>0.9.2</version>
<authors>Oleg Aksenov</authors>
<owners>Oleg Aksenov</owners>
<licenseUrl>http://www.opensource.org/licenses/ms-pl.html</licenseUrl>
<projectUrl>http://modelscaffolding.codeplex.com</projectUrl>
<!--<iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>-->
<description>A fast and customizable way to add Model (with optional Controller and Views) to your ASP.NET MVC project. You can specify property types or can use conventions. Visit the Project site to learn about output and conventions' customization. Inspired by MVCScaffolding.</description>
<summary>A fast and customizable way to add Model (with optional Controller and Views) to your ASP.NET MVC project.</summary>
<tags>Model MVC Scaffolding Scaffold Scaffolder</tags>
<dependencies>
<dependency id="T4Scaffolding" version="1.0.0" />
<dependency id="MVCScaffolding" version="1.0.0" />
</dependencies>
</metadata>
</package>

Единственный элемент, который, на мой взгляд, имеет смысл объяснить – это dependencies. Там я указал зависимость от пакета T4Scaffolding (это инфраструктура для scaffolder’ов) и MVCScaffolding (это пакет, который использует T4Scaffolding для генерации MVC-обвязки). В принципе, можно было бы указать только последний – он зависит от первого, и такие зависимости должны устанавливаться автоматически.

Причина такой “неоптимальности” в том, что я думаю над тем, чтобы убрать последнюю зависимость, но меня останавливает желание поддерживать генерацию контроллеров и представлений (а запускать ее без установленного MVCScaffolding вроде бы неправильно). Так что если у вас есть свои соображения на этот счет – добро пожаловать в комментарии.

Установочные файлы

Что касается установочных файлов, напоминаю – пока я использую только PowerShell, поэтому набор файлов у меня небольшой и не включает .NET-сборки.

В корневой папке находится только файл спецификации и bat-файл для упаковки.

В папке “content”, как немой укор разработчикам NuGet находится NuGetDymmy.txt. Ну нет в моем пакете ни скриптов, ни контента – а они этого не предусмотрели (баг у них зарегистрирован, лично я проголосовал).

В папке “tools” у меня есть PowerShell-скрипт “install.ps1”, который автоматически вызывается при установке пакета, то есть, когда вы в Package Manager Console выполняете следующую команду:

PM> Install-Package ModelScaffolding

Значимые строки в “install.ps1” следующие:

   1: param($rootPath, $toolsPath, $package, $project)
   2: if (-not (Get-Command Invoke-Scaffolder)) { return }
   3: if ($project) { Get-ProjectItem "NuGetDymmy.txt" -Project $project.Name | %{ $_.Delete() } }
   4: Set-DefaultScaffolder -Name Model -Scaffolder ModelScaffolding.Model -SolutionWide -DoNotOverwriteExistingSetting
   5: $project.Object.References.Add("System.ComponentModel.DataAnnotations")

Расскажу обо всем по порядку:

  1. Стандартные входные параметры. Повторюсь, я мало знаком с PowerShell и NuGet, поэтому меня наверное будет легко понимать тем, кто видит его в первый раз :)
  2. Проверка на то, что работает T4Scaffolding (а мало ли…).
  3. Удаляем файл, который временно обходит упомянутую выше проблему с NuGet.
  4. Регистрируем свой scaffolder с коротким названием “Model”.
  5. На всякий случай добавляем к проекту ссылку на “System.ComponentModel.DataAnnotations”, потому что при генерации модели могут использоваться атрибуты. Это тоже один из моментов, в правильности которых я не уверен на сто процентов.

На этом все по исходным файлам. Также в этой папке (а точнее в “tools\Scaffolders\Model\”) находится сам scaffolder и его настройки, но о них я расскажу позже.

Инфраструктура для отладки

Естественно, перед публикацией пакета хорошо бы отладить его самому – не так ли? :) Для этих целей я создал у себя папку “e:\Projects\MyNuGet\” и небольшой файл “Pack.bat” с таким содержимым:

NuGet Pack
copy *.nupkg e:\Projects\MyNuGet\ /Y

И, как я уже говорил выше, нужно добавить путь к папке в настройки Visual Studio. Если пакет уже опубликован, лучше на время отладки поставить её на первое место, чтобы в процессе тестирования не установить старую опубликованную версию:

PackageSources

После этого можно смело набирать в консоли “Install-Package ModelScaffolding” – установится локальный пакет.

Когда пакет уже установлен в тестовый проект, очень удобно при отладке и тестировании просто копировать файлы в соответствующую папку проекта. В моем (очень простом) случае достаточно скопировать три файла в папку “<Путь к проекту>\packages\ModelScaffolding.0.9.2\tools\Scaffolders\Model\”).

Резюме

Как вы могли увидеть, публикация в NuGet довольно проста. Поэтому, особенно если у вас есть какие-либо свободные библиотеки для .NET или Visual Studio – рекомендую опубликовать их на NuGet – этим вы сильно облегчите жизнь многим вашим пользователям.

Если тема реализации Scaffolder’а интересна, позже расскажу детали реализации своего (ModelScaffolding).

Если у вас есть замечания, пожелания или новые темы – пишите в комментариях, твиттер или на olegaxenow.reformal.ru. Постараюсь учесть.

9 комментариев:

  1. Статья интересная. Спасибо!

    ОтветитьУдалить
  2. test comment. в пятницу был длинный коммент от меня, ау.

    ОтветитьУдалить
  3. вот блин. он не сохранился. сам виноват, не заметил (при отключенных картинках) что он еще капчу спрашивал.

    короче коммент был про то будет/нет предновогодняя YaNa, в прошлом (иль позапрошлом) уж не помню мне понравилась.

    про доклад - полноценный подготовить врядли.
    наметки есть. по тестированию. можно опять же "круглый стол".

    ОтветитьУдалить
  4. To @dwarwood: скорее всего в этом году не получится

    ОтветитьУдалить
  5. ok.
    че, все всё сдают к концу года ? :-)

    ОтветитьУдалить
  6. я кстати нашел (пятничный) первоначальный коммент, вот он:
    __
    здорова.
    че, предновогодней Yan'ы не будет?

    а то я б сходил, развеялся.

    провалялся тут месяц дома, болея - появилось желание активизироваться и куда ниб сходить.

    да, если у тебя сразу возникнет встречный вопрос про не пора ль и мне доклад подготовить - м.б. и можно, но он будет очень хреновый, ибо тестирование я опять забросил (прошлым летом была попытка сделать доклад по CodedUITest в VS, я его даже принес, но там случилаь история с девушкой тестером с ЖД - "Пусть-говорят", и прочитать я его тогда не успел. тебя на той встрече не было, рассказывал тебе xorets энту историю?) и занимаюсь в последнее время не пойми чем и всем понемногу, включая код на java и чтение чужой документации :-(
    __

    ОтветитьУдалить
  7. кстати, если присмотреться :-), пятничный коммент содержит вопрос.

    ОтветитьУдалить
  8. >содержит вопрос.
    ok, проехали с вопросом.

    >скорее всего в этом году не получится

    назначай[те] тогда ориентировочную дату, я к ней причешу свой заброшенный доклад.

    у вас что в качестве движка для тестов используют?

    смысел вопроса таков - я его, доклад, готовил на основе MS CodedUI Tests, Microsoft Test Manager и с ориентацией на автоматизированное тестирование в попытке ответить на вопрос: получится ли нам его внедрить в текущих проектах, или мы попадем в то большинство, которое начинает-вязнет-и-бросает, и тд, но т.к. тему забросил - мне бы оппонента который в теме. инструмент не столь важен, но поскольку у нас дотнет то лучше бы его и.

    ОтветитьУдалить
  9. To @dwarwood:
    Используем Web Aii.
    В каком смысле оппонент?

    P.S. Пиши лучше на mail :)

    ОтветитьУдалить