使用msbuild在父文件夹中查找文件

Fil*_*Vos 4 msbuild .net-3.5

在MsBuild中,可以创建build.proj.userMicrosoft.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\
Run Code Online (Sandbox Code Playgroud)

我希望实现对于solution1/project1,文件c:\working\solution1\build.proj.user被读取以及对于solution2/project1文件c:\working\build.proj.user

目的是允许根据解决方案和/或项目自定义集成测试连接字符串属性.

我看到的当前解决方案是:

  • 创建一个自定义的msbuild任务,它将查找此文件
  • 构造一个shell命令来查找该文件.
  • 让它在父路径的父级和父级中进行硬编码查看

我不是任何一个解决方案的粉丝,并且想知道是否有更优雅的方式来实现我的目标(使用msbuild).

Kev*_*ler 16

MSBuild 4.0中存在此功能:$([MSBuild] :: GetDirectoryNameOfFileAbove(目录,文件名)

示例:在祖先目录中包含名为"Common.targets"的文件

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

有关更多详细信息,请参阅此博客文章:MSBuild属性函数


Lud*_*dwo 7

将其添加到项目文件中:

<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')"/>
Run Code Online (Sandbox Code Playgroud)

编辑:您也可以使用MsBuild内联任务来完成.它有点慢,但更通用:) 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>
Run Code Online (Sandbox Code Playgroud)

工作原理:FindUserFile是用C#语言编写的内联任务.它尝试查找FileToFind参数中指定的文件.然后迭代所有父文件夹,它返回UserFileName输出属性中第一次出现的FileToFind文件.如果找不到文件,则UserFileName输出属性为空字符串.