Msbuild directory.build.props:将存储在多级文件夹中的外部内容文件正确链接到.csproj

Msbuild directory.build.props:将存储在多级文件夹中的外部内容文件正确链接到.csproj,msbuild,projects-and-solutions,csproj,Msbuild,Projects And Solutions,Csproj,在度过了几天之后,我来到这里寻求帮助 情况是这样的——由于git存储库的大小增加,我们的构建占用了太多的时间。在进行构建之前,大部分时间都花在拉取一大组文件上。在进行构建之前,我们的Jenkins工作流将清除工作区,以确保不存在上一个构建的残余。事实证明,这些大型内容文件不会经常更改。因此,我将它们分离到一个不同的目录中,该目录与我现有的源代码文件具有类似的文件夹结构。这些内容文件保存在不同的存储库中,仅在需要时才提取。下面是我的文件夹结构: **ContentFiles**

在度过了几天之后,我来到这里寻求帮助

情况是这样的——由于git存储库的大小增加,我们的构建占用了太多的时间。在进行构建之前,大部分时间都花在拉取一大组文件上。在进行构建之前,我们的Jenkins工作流将清除工作区,以确保不存在上一个构建的残余。事实证明,这些大型内容文件不会经常更改。因此,我将它们分离到一个不同的目录中,该目录与我现有的源代码文件具有类似的文件夹结构。这些内容文件保存在不同的存储库中,仅在需要时才提取。下面是我的文件夹结构:

    **ContentFiles**
       \ConsoleApp1\Content\TestData
                               New Bitmap Image.bmp
                               abc.xyz
                               cosoleDep1.txt
       \Model\ConsoleApp2\Files
                          readme.txt
                          readme2.txt
       \Model\Tools\ConsoleApp3\Packages
                                New Bitmap Image.bmp
                                New Text Document.txt
    **Sources**
       \ConsoleApp1
                    ConsoleApp1.csproj
       \Model\ConsoleApp2
                    ConsoleApp2.csproj
       \Model\Tools\ConsoleApp3
                    ConsoleApp3.csproj
       ConsoleApp1.sln
       Directory.Build.props
现在,我们来制作构建程序,将其中一些文件包含在源项目文件.csproj中,另一些文件包含在各自的输出文件夹中,以便进行打包和单元测试。我选择的选项是使用Directory.Build.props文件根据需要构建链接。因此,使用以下脚本在源代码的根级别添加了Directory.Build.props

<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <ContentFilesDir>$(MSBuildThisFileDirectory)\ContentFiles\</DependencyDir>
    </PropertyGroup>

    <ItemGroup>
        <ContentFiles Include="$(ContentFilesDir)\**\$(MSBuildProjectName)\**\*.*"/>
    </ItemGroup>

    <ItemGroup>
       <Content Include="@(ContentFiles)"  >
            <Link>%(RecursiveDir)\%(Filename)%(Extension)</Link>
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>True</Visible>
        </Content>

    </ItemGroup>
</Project>
这里感兴趣的行是过滤器和 %RecursiveDir\%Filename%扩展名。我相信%RecursiveDir正在从列表中检索该项,并且名称从包含项目名称的最后一个反斜杠开始。因此,它正在处理的列表必须采用正确的格式。当项目处于多级文件夹结构中时,如何修改过滤器以删除该级别

必须有要求:内容文件必须在项目中显示为各个项目中的链接文件。如果我使用任何任务,那么它只会在构建任务期间生效,这可能会起作用,但不会显示在项目文件中


非常感谢您的帮助。

在进一步了解了这项技术的工作原理后,我提出了以下建议。希望这对其他人有帮助。欢迎提出建议

<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <SourceDirName>Sources</SourceDirName>
        <DependencyDirName>Dependencies</DependencyDirName>
        <RootDir>$(MSBuildThisFileDirectory)</RootDir>
        <DependencyDir>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\Repo1\$(DependencyDirName)))</DependencyDir>
        <SourceDir>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\Repo2\$(SourceDirName)))</SourceDir>
        <MSBuildProjectDirName>$([System.IO.Directory]::GetParent($(MSBuildProjectFullPath)).Name)</MSBuildProjectDirName>
    </PropertyGroup>

    <ItemGroup>
        <DepFiles Include="$(DependencyDir)\**\$(MSBuildProjectDirName)\**\*.*"></DepFiles>
    </ItemGroup>

    <Target Name="Test" BeforeTargets="CopyFilesToOutputDirectory">
        <Message Importance="Low" Text="MSBuildThisFileDirectory $(MSBuildThisFileDirectory)"/>
        <Message Importance="Low" Text="SourceDirName            $(SourceDirName)"/>
        <Message Importance="Low" Text="DependencyDirName        $(DependencyDirName)"/>
        <Message Importance="Low" Text="RootDir                  $(RootDir)"/>
        <Message Importance="Low" Text="DependencyDir            $(DependencyDir)"/>
        <Message Importance="Low" Text="SourceDir                $(SourceDir)"/>
        <Message Importance="Low" Text="MSBuildProjectDirName    $(MSBuildProjectDirName)"/>

        <Message Importance="Low" Text="@(DepFiles->Count())"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)'))"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)))"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)).Replace($(MSBuildProjectDirectory),''))"/>
    </Target>

    <ItemGroup>
            <Content Include="@(DepFiles)" Condition="'@(DepFiles->Count())' > 0">
                <Link>$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)).Replace($(MSBuildProjectDirectory),''))</Link>
                <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>True</Visible>
        </Content>

    </ItemGroup>
</Project>
ConsoleApp1
            \Content
                  New Bitmap Image.bmp
                  \TestData
                      abc.xyz
                      cosoleDep1.txt
Model\ConsoleApp2
              \Files
                 readme.txt
                 readme2.txt
Model\Tools\ConsoleApp3
              \Packages
                    New Bitmap Image.bmp
                    New Text Document.txt
<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <SourceDirName>Sources</SourceDirName>
        <DependencyDirName>Dependencies</DependencyDirName>
        <RootDir>$(MSBuildThisFileDirectory)</RootDir>
        <DependencyDir>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\Repo1\$(DependencyDirName)))</DependencyDir>
        <SourceDir>$([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\Repo2\$(SourceDirName)))</SourceDir>
        <MSBuildProjectDirName>$([System.IO.Directory]::GetParent($(MSBuildProjectFullPath)).Name)</MSBuildProjectDirName>
    </PropertyGroup>

    <ItemGroup>
        <DepFiles Include="$(DependencyDir)\**\$(MSBuildProjectDirName)\**\*.*"></DepFiles>
    </ItemGroup>

    <Target Name="Test" BeforeTargets="CopyFilesToOutputDirectory">
        <Message Importance="Low" Text="MSBuildThisFileDirectory $(MSBuildThisFileDirectory)"/>
        <Message Importance="Low" Text="SourceDirName            $(SourceDirName)"/>
        <Message Importance="Low" Text="DependencyDirName        $(DependencyDirName)"/>
        <Message Importance="Low" Text="RootDir                  $(RootDir)"/>
        <Message Importance="Low" Text="DependencyDir            $(DependencyDir)"/>
        <Message Importance="Low" Text="SourceDir                $(SourceDir)"/>
        <Message Importance="Low" Text="MSBuildProjectDirName    $(MSBuildProjectDirName)"/>

        <Message Importance="Low" Text="@(DepFiles->Count())"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)'))"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)))"/>
        <Message Importance="Low" Text="@(DepFiles)->$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)).Replace($(MSBuildProjectDirectory),''))"/>
    </Target>

    <ItemGroup>
            <Content Include="@(DepFiles)" Condition="'@(DepFiles->Count())' > 0">
                <Link>$([System.String]::Copy('%(FullPath)').Replace($(DependencyDir), $(SourceDir)).Replace($(MSBuildProjectDirectory),''))</Link>
                <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Visible>True</Visible>
        </Content>

    </ItemGroup>
</Project>