MSBuild:基于文件路径的一部分筛选项

MSBuild:基于文件路径的一部分筛选项,msbuild,Msbuild,我有一组需要复制的文件,它们位于包含存放这些文件的软件包版本的文件夹下: <ItemGroup> <MyFiles Include="$(MyPackages)\foo.x64*\binaries\*.*"/> </ItemGroup> foo.x64*可以解析为多个文件夹,如foo.x64.17.5.50和foo.x64.17.6.2,其中后缀表示软件包的版本。我想根据该版本筛选项目,但似乎找不到方法将项目文件路径的任何部分提取为项目上的元数据

我有一组需要复制的文件,它们位于包含存放这些文件的软件包版本的文件夹下:

<ItemGroup>
    <MyFiles Include="$(MyPackages)\foo.x64*\binaries\*.*"/>
</ItemGroup>


foo.x64*
可以解析为多个文件夹,如
foo.x64.17.5.50
foo.x64.17.6.2
,其中后缀表示软件包的版本。我想根据该版本筛选项目,但似乎找不到方法将项目文件路径的任何部分提取为项目上的元数据,然后在批处理或条件中使用它。

这里可以使用msbuild的一些功能。这些是:

  • 定义自定义项元数据。让我们称它们为
    FooArch
    FooVersion
  • MSBuild允许调用某些.net API,包括正则表达式。因此,我们可以在这里使用
    RegEx.Match()
    提取您需要知道的信息
  • 在对字符串进行数字比较时,MSBuild将它们解析为版本。这将允许您执行范围条件,如
    '%(FooItems.FooVersion)'17.6.2'
  • 开箱即用是不可能确定项目列表的最高版本的。要实现这一点,您需要编写一个自定义msbuild任务

    一个更具体的示例:要在项目上添加所需的元数据并复制正确的版本和体系结构,可以执行以下操作:

    <PropertyGroup>
      <FooRegEx>[\\/]foo\.(?&lt;arch&gt;x(\d*))\.(?&lt;version&gt;((\d+)(\.\d+)+))</FooRegEx>
      <FooVersionToUse>17.5.50</FooVersionToUse>
    </PropertyGroup>
    
    <ItemGroup>
      <FooFiles Include="mypkgs\foo*\binaries\**\*">
        <FooArch>$([System.Text.RegularExpressions.Regex]::Match(%(Identity), $(FooRegEx)).get_Groups().get_Item("arch"))</FooArch>
        <FooVersion>$([System.Text.RegularExpressions.Regex]::Match(%(Identity), $(FooRegEx)).get_Groups().get_Item("version"))</FooVersion>
      </FooFiles>
    </ItemGroup>
    
    <Target Name="IncludeFoo" BeforeTargets="PrepareForBuild">
      <PropertyGroup>
        <FooArchToUse Condition="'$(FooArchToUse)' == '' and '$(Platform)' != 'AnyCPU'">$(Platform)</FooArchToUse>
        <FooArchToUse Condition="'$(FooArchToUse)' == ''">x64</FooArchToUse>
      </PropertyGroup>
      <ItemGroup>
        <Content Include="@(FooFiles)" 
                 Link="foo\%(Filename)%(Extension)"
                 CopyToOutputDirectory="PreserveNewest"
                 Condition="'%(FooFiles.FooVersion)' == '$(FooVersionToUse)' and '%(FooFiles.FooArch)' == '$(FooArchToUse)'"/>
      </ItemGroup>
    </Target>
    
    
    [\\/]foo\.(?archx(\d*))\.(?version((\d+)(\.\d+))
    17.5.50
    $([System.Text.RegularExpressions.Regex]::匹配(%(标识),$(FooRegEx)).get_Groups().get_项(“arch”))
    $([System.Text.RegularExpressions.Regex]::匹配(%(标识),$(FooRegEx)).get_组().get_项(“版本”))
    $(平台)
    x64
    

    这将把所选版本和平台的项目(默认为x64)复制到输出目录的
    foo
    子文件夹中。(在MSBuild 15.1上测试)。我已将示例项目上载到GitHub。

    这里可以使用msbuild的一些功能。这些是:

  • 定义自定义项元数据。让我们称它们为
    FooArch
    FooVersion
  • MSBuild允许调用某些.net API,包括正则表达式。因此,我们可以在这里使用
    RegEx.Match()
    提取您需要知道的信息
  • 在对字符串进行数字比较时,MSBuild将它们解析为版本。这将允许您执行范围条件,如
    '%(FooItems.FooVersion)'17.6.2'
  • 开箱即用是不可能确定项目列表的最高版本的。要实现这一点,您需要编写一个自定义msbuild任务

    一个更具体的示例:要在项目上添加所需的元数据并复制正确的版本和体系结构,可以执行以下操作:

    <PropertyGroup>
      <FooRegEx>[\\/]foo\.(?&lt;arch&gt;x(\d*))\.(?&lt;version&gt;((\d+)(\.\d+)+))</FooRegEx>
      <FooVersionToUse>17.5.50</FooVersionToUse>
    </PropertyGroup>
    
    <ItemGroup>
      <FooFiles Include="mypkgs\foo*\binaries\**\*">
        <FooArch>$([System.Text.RegularExpressions.Regex]::Match(%(Identity), $(FooRegEx)).get_Groups().get_Item("arch"))</FooArch>
        <FooVersion>$([System.Text.RegularExpressions.Regex]::Match(%(Identity), $(FooRegEx)).get_Groups().get_Item("version"))</FooVersion>
      </FooFiles>
    </ItemGroup>
    
    <Target Name="IncludeFoo" BeforeTargets="PrepareForBuild">
      <PropertyGroup>
        <FooArchToUse Condition="'$(FooArchToUse)' == '' and '$(Platform)' != 'AnyCPU'">$(Platform)</FooArchToUse>
        <FooArchToUse Condition="'$(FooArchToUse)' == ''">x64</FooArchToUse>
      </PropertyGroup>
      <ItemGroup>
        <Content Include="@(FooFiles)" 
                 Link="foo\%(Filename)%(Extension)"
                 CopyToOutputDirectory="PreserveNewest"
                 Condition="'%(FooFiles.FooVersion)' == '$(FooVersionToUse)' and '%(FooFiles.FooArch)' == '$(FooArchToUse)'"/>
      </ItemGroup>
    </Target>
    
    
    [\\/]foo\.(?archx(\d*))\.(?version((\d+)(\.\d+))
    17.5.50
    $([System.Text.RegularExpressions.Regex]::匹配(%(标识),$(FooRegEx)).get_Groups().get_项(“arch”))
    $([System.Text.RegularExpressions.Regex]::匹配(%(标识),$(FooRegEx)).get_组().get_项(“版本”))
    $(平台)
    x64
    

    这将把所选版本和平台的项目(默认为x64)复制到输出目录的
    foo
    子文件夹中。(在MSBuild 15.1上测试)。我已将示例项目上载到GitHub。

    您可以使用ItemGroup的条件属性根据一些布尔表达式筛选出元素。例如,您可以根据使用regex。

    您可以使用ItemGroup的条件属性根据一些布尔表达式筛选出元素。例如,您可以根据使用正则表达式。

    您实际上不需要提取零件,您可以使用完整路径上的条件?例如,
    无论如何,我敢肯定以前有人问过这个问题。搜索“msbuild item filter”左右。可能与要筛选的内容重复?版本范围/从项目筛选/进入新项目?或者从
    MyFiles
    中排除某个版本?@MartinUllrich排除非最新版本将是一个很好的开始,虽然将来我们可能希望扩展它,以排除.csproj中某些属性集指定的特定版本以外的所有版本。@stijn我的问题不同,因为我不知道这些版本后缀将是什么,所以硬编码
    17.5.50
    是不可接受的。这就是为什么提取很重要。如果只有
    包含的
    可以引用属性,但我不知道如何设置属性,那么您的条件是完全正确的!您实际上不需要提取零件,您可以使用完整路径上的条件?例如,
    无论如何,我敢肯定以前有人问过这个问题。搜索“msbuild item filter”左右。可能与要筛选的内容重复?版本范围/从项目筛选/进入新项目?或者从
    MyFiles
    中排除某个版本?@MartinUllrich排除非最新版本将是一个很好的开始,虽然将来我们可能希望扩展它,以排除.csproj中某些属性集指定的特定版本以外的所有版本。@stijn我的问题不同,因为我不知道这些版本后缀将是什么,所以硬编码
    17.5.50
    是不可接受的。这就是为什么提取很重要。如果只有
    包含的
    可以引用属性,但我不知道如何设置属性,那么您的条件是完全正确的!谢谢你,马丁,这个正则表达式技巧正是我错过的。最后,我写了一个自定义任务来查找最新版本,这很不幸,但是内联任务并没有那么痛苦。谢谢Martin,正则表达式技巧正是我所缺少的。最后,我确实编写了一个自定义任务来查找最新版本,这很不幸,但内联任务并不那么痛苦。