Incremental Build of Nuget Packages

2019-09-07 20:13发布

问题:

I want to execute an msbuild project which uses batching to determine that one or more csproj projects have been freshly-built, and therefore require fresh nuget packaging. The script I've made so far seems like a reasonable start, but it the incremental-build mechanism isn't working. The MainBuild target executes every time, no matter what.

Here is what I have:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="MainBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)'=='' ">Debug</Configuration>
    <Content>content\plugins\</Content>
  </PropertyGroup>
  <ItemGroup>
    <Nuspec Include="$(MSBuildProjectDirectory)\plugins\*\*.nuspec" />
  </ItemGroup>

<Target Name="MainBuild"
        Inputs="%(Nuspec.RootDir)%(Nuspec.Directory)bin\$(Configuration)\*.dll"
        Outputs="%(Nuspec.RootDir)%(Nuspec.Directory)%(FileName).pkg" >
  <ItemGroup>
    <Inputs Include="%(Nuspec.RootDir)%(Nuspec.Directory)bin\$(Configuration)\*.dll" />
    <Outputs Include="%(Nuspec.RootDir)%(Nuspec.Directory)%(FileName).pkg" />
  </ItemGroup>
  <Message Text="INPUTS: %(Inputs.FullPath)" />
  <Message Text="OUTPUTS: @(Outputs->'%(FullPath)')" />

  <Copy SourceFiles="@(Inputs)" DestinationFiles="@(Outputs->'%(FullPath)')" />

</Target>
</Project>

The Copy task is just a debugging placeholder for calling-out to nuget and creating a new package.

The idea is that if any files in the bin\Debug directory are newer than the corresponding .nuspec file (found two folders above bin\Debug), then the MainBuild target should execute.

Any ideas?

p.s. The Inputs and Outputs attributes of the Target presumably each create an item. I think it strange that the items created can't be referenced inside the target. In the above example, I had to make a target-interna dynamic ItemGroup to re-create the items, just so that I could access them. Is there a way around that?

回答1:

I read this in the MSBuild Batching documentation

If a task inside of a target uses batching, MSBuild needs to determine if the inputs and outputs for each batch of items is up-to-date. Otherwise, the target is executed every time it is hit.

Which may be the cuprit. Try changing your copy target to use batching instead of an ite transform (I don't think using item metadata in an item group satisfies the above requirement).

<Target Name="MainBuild"
        Inputs="%(Nuspec.RootDir)%(Nuspec.Directory)bin\$(Configuration)\*.dll"
        Outputs="%(Nuspec.RootDir)%(Nuspec.Directory)%(FileName).pkg" >
    <ItemGroup>
        <Inputs Include="%(Nuspec.RootDir)%(Nuspec.Directory)bin\$(Configuration)\*.dll" />
        <Outputs Include="%(Nuspec.RootDir)%(Nuspec.Directory)%(FileName).pkg" />
    </ItemGroup>
    <Message Text="INPUTS: %(Inputs.FullPath)" />
    <Message Text="OUTPUTS: @(Outputs->'%(FullPath)')" />

    <Copy SourceFiles="@(Inputs)" DestinationFiles="%(Outputs.FullPath)" />

</Target>

It looks like the number of inputs may be different than the number of outputs (I suspect there is more than one .dll files in the output directory for each project), which will also cause the target to execute.