MSBuild: Как мне создать и использовать задачу для преобразования элементов контента во время сборки? - PullRequest
7 голосов
/ 08 августа 2010

У меня есть проект Silverlight 3 с чем-то вроде этого:

<ItemGroup>
  <Content Include="Content\image1.png">
  </Content>
</ItemGroup>

По сути, я добавил PNG-файл в свой проект и установил для него действие сборки «Содержимое». Это хорошо работает.

Теперь я хотел бы добавить в свой проект изображения в другом формате и преобразовать их в формат PNG во время сборки , чтобы конечный результат такой, как если бы я сначала добавил изображение PNG в проект (как контент).

Другими словами - я хочу, чтобы изображение появилось в формате PNG в моем пакете XAP.

В идеале я хотел бы сделать это таким образом, чтобы он работал с Visual Web Developer 2008 Express (чтобы я мог добавлять файлы изображений в свой проект, перетаскивая их в IDE и, возможно, изменяя их действие сборки), и без внесение любых общесистемных изменений.

Конкретный формат, который я хочу преобразовать, это XCF - у меня уже есть код .NET для преобразования в PNG. Я предполагаю, что должен создать задачу MSBuild .

У меня нет особого опыта работы с MSBuild, и я хотел бы знать, как собрать такую ​​вещь.


Исходя из моего грубого понимания того, как работает MSBuild, я думаю, что мне нужно знать:

  • Как создать коллекцию элементов путем (пере) перемещения их из коллекции @(Content) (или какой-либо другой) на основе их расширения файла?
    • ИЛИ: создание пользовательского действия по сборке, которое я могу использовать в Visual Web Developer 2008 Express
  • Как получить путь ввода элементов в Task?
  • Где (.NET или MSBuild?) И Как указать расположение выходных файлов, сгенерированных Task?
  • Как гарантировать, что файл будет перестроен, если его входной файл изменится?
  • Где (вероятно, BeforeBuild?) И как повторно преобразовать преобразованные элементы в @(Content)? (Или я должен использовать какую-то другую коллекцию?)
    • ИЛИ: Есть ли другой способ получить их в XAP?

А если это кажется разумным способом сделать что-то или я что-то пропустил?

Ответы [ 3 ]

13 голосов
/ 10 августа 2010

Вы задали конкретные подвопросы с целью достижения своей общей цели. Я полагаю, что вы хотите узнать о MSBuild, а не получить подробный ответ на вашу общую задачу (что вы получите от многих других людей) из-за вашей щедрости), поэтому я отвечу на ваши индивидуальные вопросы, а затем попытаюсь свернуть их все в решение.

Допустим, вы хотите конвертировать все файлы .jpg в .png.

Создать подсписок из списка элементов контента на основе расширения:

<ItemGroup>
    <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " />
</ItemGroup>

Получить путь к предмету в задании.

Два способа - зависит от ввода, который может принять ваша задача. Этот способ похож на foreach для каждого элемента в Sublist, и я бы предпочел использовать его с задачей Exec:

<Exec Command="convert.exe /Input:%(Sublist.FullPath)" />

Указание выходного пути также зависит от .exe или задачи, которую вы выполняете, и что означает выходной путь для конкретной задачи:

это каталог или просто имя файла с другим расширением. Но я предполагаю, что вы хотите вывести файлы с тем же именем, но с другим расширением:

<Exec Command="convert.exe &quot;%(Sublist.FullPath)&quot;  &quot;%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png&quot;" />    

Как перестроить png, если jpg изменяется (или очищается).

Ну, это использует атрибут Inputs и Outputs содержащего целевой элемент, где выполняется наша команда convert. Inputs указывает, что представляют собой исходные файлы, а output указывает, что будет производить цель. Затем MSBuild сравнивает дату и время входов с датой и временем выходных данных, и если они устарели, то выходные данные перестраиваются

<Target Name="ConvertJpg"  
        Inputs="@(Content)"
        Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png' )"
        Condition=" '%(Extension)' == '.jpg' "
  • Входные данные говорят, что мы хотим использовать группу элементов "Контент"
  • Атрибут Condition гарантирует, что мы работаем только с элементами контента, заканчивающимися расширением .jpg
  • Атрибут Outputs говорит, что из входов, с которыми мы работаем, мы будем генерировать файлы с одинаковым путем и именем файла, но заканчивающиеся расширением .png

Наконец, вы правильно заметили, что вам нужно повторно внедрить сгенерированные файлы .png обратно в группу элементов @Content - ну, это просто, вы просто включаете их в элемент контента. Напомним, что Sublist содержит файлы .jpg - нам нужны эти файлы, но с окончанием .png. Мы также НЕ хотим, чтобы файлы .jpg в группе элементов содержимого были созданы после создания png

<Content Remove="@(Sublist)" />
<Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png' )" />

Итак, подытожив, ваша цель будет выглядеть примерно так:

<Target Name="ConvertJpg"  
        Inputs="@(Content)"
        Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png' )"
        Condition=" '%(Extension)' == '.jpg' "
    <ItemGroup>
        <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " />
    </ItemGroup>

    <Exec Command="convert.exe /Input:%(Sublist.FullPath) Output=%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png" />

    <Content Remove="@(Sublist)" />
    <Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png' )" />
</Target>

Кстати, в ImageMagik есть инструмент командной строки, который преобразует jpg в png ...

2 голосов
/ 10 августа 2010

Я полагаю, вы хотите что-то вроде этого:

<ItemGroup>
  <JPGContent Include="foo.jpg" />
</ItemGroup>
<Target Name="BeforeBuild" 
        Inputs="@(JPGContent)" Outputs="%(JPGContent.Filename).png">
  <!-- replace this with call to jpg->png converter -->
  <Exec Command="copy %22%(JPGContent.FullPath)%22 %(JPGContent.Filename).png" />
  <ItemGroup>
    <Content Include="%(JPGContent.Filename).png" />
  </ItemGroup>
</Target>
<Target Name="AfterBuild">
  <!-- just demoing that 'Content' now has right value -->
  <Warning Text ="Content=@(Content)" />
</Target>

, где вы указываете новый JPGContent BuildAction, который он преобразует.

(Возможно, см. Также http://msdn.microsoft.com/en-us/library/ms164313.aspx иобратите внимание, что %22 - это просто способ вставить кавычку в атрибут.)

0 голосов
/ 10 августа 2010

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

"пользовательский инструмент преобразует файл во время разработки и помещает вывод преобразования в другой файл"

например. DataSet. у него есть собственный инструмент преобразования, с помощью которого мы получаем класс для использования в нашем приложении.

преимущество этого подхода заключается в вас можете использовать сгенерированный файл при проектировании время.

в качестве примера реализации можно найти на http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/

...