使用MSBuild覆盖属性

18

我想在我的MSBuild文件中声明三个属性,并根据调用的目标覆盖一个属性的值,但是无法弄清楚如何实现。我的构建文件大致如下:

<PropertyGroup>
   <DeployPath_TEST>\\test-server-path\websites\mysite</DeployPath_TEST>
   <DeployPath_LIVE>\\live-server-path\websites\mysite</DeployPath_LIVE>
   <DeployPath></DeployPath>
</PropertyGroup>

<Target Name="Deploy-TEST">
   <PropertyGroup>
      <DeployPath>$(DeployPath_TEST)</DeployPath>
   </PropertyGroup>
   <CallTarget Targets="Deploy-Sub"/>
</Target>

<Target Name="Deploy-LIVE">
   <PropertyGroup>
      <DeployPath>$(DeployPath_TEST)</DeployPath>
   </PropertyGroup>
   <CallTarget Targets="Deploy-Sub"/>
</Target>

<Target Name="Deploy-Sub">
   <Message Text="Deploying to $(DeployPath)"/>
   <MSBuild Projects="MySolution.csproj" Targets="Rebuild" />

   <ItemGroup>
     <MyFiles Include="**\*"/>
   </ItemGroup>

   <Copy SourceFiles="@(MyFiles)" 
         DestinationFiles="@(MyFiles->'$(DeploymentPath)\%(RecursiveDir)%(FileName)%(Extension)')"/>

</Target>

目前我正在尝试重新声明该属性,并相应地设置其值,但这并没有起作用。

4个回答

17

Mehmet关于如何从另一个属性设置属性值是正确的,但在MSBuild中存在一个bug/特性,这意味着如果您在同一个目标中调用CreateProperty和CallTarget,则新属性将无法全局可用于其他目标详见此处)。

因此,以下是问题的最终解决方案:

<PropertyGroup>
   <DeployPath_TEST>\\test-server-path\websites\mysite</DeployPath_TEST>
   <DeployPath_LIVE>\\live-server-path\websites\mysite</DeployPath_LIVE>
   <DeployPath></DeployPath>
</PropertyGroup>

<Target Name="SetDeployPath-TEST">
  <CreateProperty Value="$(DeployPath_TEST)">
    <Output TaskParameter="Value" PropertyName="DeployPath"/>
  </CreateProperty>
</Target>

<Target Name="Deploy-TEST">
   <CallTarget Targets="SetDeployPath-TEST"/>
   <CallTarget Targets="Deploy-Sub"/>
</Target>

<Target Name="Deploy-Sub">
  <Message Text="Deploying to $(DeployPath)"/>
  <MSBuild Projects="MySolution.csproj" Targets="Rebuild" />

  <ItemGroup>
    <MyFiles Include="**\*"/>
  </ItemGroup>

  <Copy SourceFiles="@(MyFiles)" 
     DestinationFiles="@(MyFiles->'$(DeploymentPath)\%(RecursiveDir)%(FileName)%(Extension)')"/>

</Target>

谢谢,这很有用。我对批处理还是有些新手,我认为微软在解释相关概念方面做得不好。还有一点需要注意的是,我实际上没有创建全局属性;这缩小了上下文范围,使代码更易于阅读:目标A调用目标B和C。B设置一个列表属性,C对该属性的值进行批处理。正如mdresser所指出的,在同一目标中设置属性是行不通的。希望能帮助到某些人;在找到这篇文章之前,我花了3-4个小时来理解这个问题。 - AlexeiOst
还有一点,您说您收到了只有 Cat 发生了更改的通知,您尝试保存更改了吗?它可以工作吗?(我怀疑) - Paul Zahra

10
您可以使用CreateProperty任务来覆盖现有属性的值。
<Target Name="Deploy-LIVE">   
  <CreateProperty Value="$(DeployPath_LIVE)">
    <Output PropertyName="DeployPath" TaskParameter="Value"/>
  </CreateProperty>
  <CallTarget Targets="Deploy-Sub"/>
</Target>

1
这对我似乎不起作用。我可以在CreateProperty块之后立即使用DeployPath属性的值,但它会在Deploy-Sub目标中失去其值。 - Matthew Dresser
2
哈,刚发现这篇文章 http://weblogs.asp.net/bhouse/archive/2006/03/20/440648.aspx 描述了 CreateProperty 任务的一个 bug/feature。 - Matthew Dresser
有趣,我不知道这个错误。我之前使用过CreateProperty,但显然除了覆盖它的目标之外,没有什么需要访问被覆盖的属性。谢谢。 - Mehmet Aras

4

我通常避免使用CallTarget任务。更好的方法是使用目标依赖项。


你能详细说明一下吗?为什么这对你更好? - Haymo Kutschbach
3
由于这个 bug http://sedodream.com/PermaLink,guid,dd6cb1db-c0e4-47f7-ad84-6e59ff6b03d0.aspx,我认为 CallTarget 违背了使用 msbuild 的心理模型。MSBuild 是声明式的,而 CallTarget 则是非常命令式的。尽管有一些情况下需要使用 CallTarget,但在此之前应该优先考虑使用 DependsOn。 - Sayed Ibrahim Hashimi
谢谢!我同意,而且似乎msbuild团队也鼓励使用DependsOn来启用在导入的项目中全局设置属性。 - Haymo Kutschbach

0
此外,您还可以使用以下方式:
<PropertyGroup>
   <DeployPath_TEST>\\test-server-path\websites\mysite</DeployPath_TEST>
   <DeployPath_LIVE>\\live-server-path\websites\mysite</DeployPath_LIVE>
   <DeployPath></DeployPath>
</PropertyGroup>

<Target Name="SetDeployPath-TEST">
  <CreateProperty Value="$(DeployPath_TEST)">
    <Output TaskParameter="Value" PropertyName="DeployPath"/>
  </CreateProperty>
</Target>

<Target Name="Deploy-Sub" DependsOnTargets="SetDeployPath-TEST">
  <Message Text="Deploying to $(DeployPath)"/>
  <MSBuild Projects="MySolution.csproj" Targets="Rebuild" />

  <ItemGroup>
    <MyFiles Include="**\*"/>
  </ItemGroup>

  <Copy SourceFiles="@(MyFiles)" 
     DestinationFiles="@(MyFiles->'$(DeploymentPath)\%(RecursiveDir)%(FileName)%(Extension)')"/>

</Target>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接