在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
目的是允许根据解决方案和/或项目自定义集成测试connectionstring属性。
我看到的当前解决方案是:
我不是任何一个解决方案的粉丝,并且想知道是否有更优雅的方式来实现我的目标(使用msbuild)。
答案 0 :(得分:16)
MSBuild 4.0中存在此功能: $([MSBuild] :: GetDirectoryNameOfFileAbove(目录,文件名)
示例:在祖先目录中包含名为“Common.targets”的文件
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Common.targets))\Common.targets"
Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Common.targets))' != '' " />
有关详细信息,请参阅此博客文章:MSBuild Property Functions
答案 1 :(得分: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')"/>
编辑: 您也可以使用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参数中指定的文件。然后迭代所有父文件夹,它返回UserFileName输出属性中第一次出现的FileToFind文件。如果找不到文件,则UserFileName输出属性为空字符串。