Найти файл в родительских папках с помощью msbuild - PullRequest
4 голосов
/ 23 ноября 2011

В MsBuild можно создать файл build.proj.user, который анализируется файлом сборки Microsoft.Common.Targets.

Я хочу иметь подобную систему там, где можно иметь файл .user в корне папки и заставить msbuild выбрать параметры конфигурации из этого файла.

Возьмем для примера следующие пути:

c:\working\build.proj.user
c:\working\solution1\build.proj.user
c:\working\solution1\project1\
c:\working\solution1\project2\
c:\working\solution1\project3\build.proj.user

c:\working\solution2\
c:\working\solution2\project1\
c:\working\solution2\project2\

Я хочу добиться, чтобы для solution1 / project1 файл c:\working\solution1\build.proj.user читался, а для solution2 / project1 файл c:\working\build.proj.user

Цель состоит в том, чтобы можно было настраивать свойства строки тестового соединения интеграции для решения и / или проекта.

Текущие решения, которые я вижу:

  • Создайте пользовательскую задачу msbuild, которая будет искать этот файл
  • Создайте команду оболочки для поиска файла.
  • Жестко запрограммируйте его в родительском и родительском путях

Я не фанат ни одного решения, и мне интересно, нет ли более элегантного способа достижения моей цели (с помощью msbuild).

Ответы [ 2 ]

16 голосов
/ 30 апреля 2012

Эта функциональность существует в MSBuild 4.0: $ ([MSBuild] :: GetDirectoryNameOfFileAbove (каталог, имя файла)

Пример: включить файл с именем «Common.targets» в каталог предков

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Common.targets))\Common.targets" 
    Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Common.targets))' != '' " />

См. Этот блог для более подробной информации: Функции свойств MSBuild

7 голосов
/ 23 ноября 2011

Добавьте это к своим файлам проекта:

<Import Project="build.proj.user" Condition="Exists('build.proj.user')"/>
<Import Project="..\build.proj.user" Condition="!Exists('build.proj.user') and Exists('..\build.proj.user')"/>
<Import Project="..\..\build.proj.user" Condition="!Exists('build.proj.user') and !Exists('..\build.proj.user') and Exists('..\..\build.proj.user')"/>

EDIT: Вы также можете сделать это, используя MsBuild inline task . Это немного медленнее, но более обобщенно :) Встроенные задачи поддерживаются из MsBuild 4.0

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="4.0">
  <UsingTask TaskName="FindUserFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <CurrentDirName ParameterType="System.String" Required="true" />
      <FileToFind ParameterType="System.String" Required="true" />
      <UserFileName ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
          Log.LogMessage("FindUserFile parameters:");
          Log.LogMessage("CurrentDirName = " + CurrentDirName);
          Log.LogMessage("FileToFind = " + FileToFind);

          while(CurrentDirName != Directory.GetDirectoryRoot(CurrentDirName) && !File.Exists(CurrentDirName + Path.DirectorySeparatorChar + FileToFind))
             CurrentDirName = Directory.GetParent(CurrentDirName).FullName;
          if(File.Exists(CurrentDirName + Path.DirectorySeparatorChar + FileToFind)) 
             UserFileName = CurrentDirName + Path.DirectorySeparatorChar + FileToFind;

          Log.LogMessage("FindUserFile output properties:");
          Log.LogMessage("UserFileName = " + UserFileName);
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="FindUserFileTest" >
    <FindUserFile CurrentDirName="$(MSBuildThisFileDirectory)" FileToFind="build.proj.user">
     <Output PropertyName="UserFileName" TaskParameter="UserFileName" />
    </FindUserFile>

    <Message Text="UserFileName = $(UserFileName)"/>
    <Error Condition="!Exists('$(UserFileName)')" Text="File not found!"/>

  </Target>
</Project>

Как это работает: FindUserFile - встроенная задача, написанная на языке C #. Он пытается найти файл, указанный в параметре FileToFind. Затем выполните итерации по всем родительским папкам, и он возвращает первое вхождение файла FileToFind в выходное свойство UserFileName. Свойство вывода UserFileName - пустая строка, если файл не был найден.

...