Home: IsTool=true should nest dependencies instead of express them

Created on 23 Jan 2017  Â·  29Comments  Â·  Source: NuGet/Home

VS2017: d15prerel 26121.5
dotnet version: 1.0.0-rc4-004597

When I set IsTool=true (as I do in here) I expect my project to be packed without any NuGet dependencies in the nuspec file. This is because at runtime my tools package would have no way to find its runtime dependencies unless the CLR could find them embedded within my package.

But instead, the only thing setting $(IsTool)=true seems to do is put my project's assembly in the tools folder instead of a lib folder. That isn't enough. It isn't removing the package dependencies and embedding them.

Is this simply because the feature isn't done, or because I'm misusing it?

Pack Icebox 2 DCR

Most helpful comment

@DHowett-MSFT Your phrasing suggests we should lower the priority. Were you suggesting that over the alternative which is actually treating this like a pri-1 bug?

I create a lot of nuget packages that are tools-style in nature. I'd love it if this were fixed so I didn't have to hack up custom .targets all the time to do what IMO ought to be a built-in feature.

All 29 comments

Also, since I compile this project twice (once for net45 and once for netstandard1.3) it would be better if both DLLs were copied to the tools folder (under a TFM presumably) so my .targets file that loads the MSBuild Tasks assembly could pick the assembly to load based on whether it's the desktop MSBuild or the CoreCLR variety.

@AArnott you can achieve the second scenario by setting $(BuildOutputTargetFolder) = tools

Will get back to you regarding the right behavior for the first scenario

Consider in future.

If tool is reserved for cli tools then my recent understanding is that expressing dependencies is correct.
The only package type that should embed its dependencies is an msbuild extension. Doing that is currently tedious and error prone. Can we simply add a new property to enable that mode?

Per this doc it seems IsTool is supposed to move the project output to the tools folder, in which case, it only makes sense to embed all dependencies into that folder as well.

@rohit21agrawal When <IsTool>true</IsTool> the output dll is getting copied to the tools folder directly instead of tools\targetframework\ folder when the project is built for multiple frameworks.

When IsTool is not set, then dlls are getting copied correctly to lib\targetFramework\ folder correctly.

Is this a known bug?

You mentioned setting $(BuildOutputTargetFolder) = tools as work-around but in this case, this does not help because output is getting copied to the tools folder but missing the targetFramework folder.

@vijayrkn use the workaround of $(BuildOutputTargetFolder) only when you are not using $(IsTool) = true. The combination of both wouldn't work.

When I am using <IsTool>true</IsTool> and want the output to go to tools{targetframework}\ instead of tools\, is there a work-around?

IsTool doesn't do anything special apart from adding the output to tools folder. so you can achieve the same result by just setting BuildOutputTargetFolder to tools.

Ah. got it. that will work for now. Thanks!

But it would be really good if <IsTool>true</IsTool> behavior is fixed.

@AArnott Could you solve the problem with the dependencies? I'm also working on a MSBuild task that I want to distribute as a nuget, but I face the same problem.

@BalassaMarton yes, I wrote https://github.com/AArnott/Nerdbank.MSBuildExtension to resolve this.

Also for .NET Core targets shouldn't _publish_ target be invoked before _pack_ and _pack_ copy the result of publishing to the tools directory?

Priority 1 seems a little high for something last touched an entire quarter ago.

@DHowett-MSFT Your phrasing suggests we should lower the priority. Were you suggesting that over the alternative which is actually treating this like a pri-1 bug?

I create a lot of nuget packages that are tools-style in nature. I'd love it if this were fixed so I didn't have to hack up custom .targets all the time to do what IMO ought to be a built-in feature.

@AArnott sorry: I think this should be treated as a p1 bug if it's tagged as a p1 bug!

I'm facing the same issue using a SDK-Based csproj-file (). I've tried removing the IsTools property and adding BuildOutputTargetFolder=Tools property.

This indeed puts the EXE file in the tools\<targetframework> folder. But the dependencies are still missing, thus my tools nuget package won't work.

Is there any progress on this one?

Just wanted to chime in with another voice, saying that I'm experiencing this same issue. I have a tool that I need to distribute as a nuget package, but as everyone else has mentioned IsTool doesn't include the packagereferences/dependencies in the tools folder in the nuget package, so it doesn't work.

I see there that @fubar-coder had to add his own .nuspec file (https://github.com/fluentmigrator/fluentmigrator/commit/bdfd1294f4af0dcf27041cb7ffc46e77d3440525#diff-fc464b261a7aeaad0b7f5fb0057f10f8) … is that really the best/only option here? I'd really rather avoid having to maintain that separately.

In case it's helpful for anyone else, I worked around this issue in the following way:

First, I run this restore command locally, so that I have all of my nuget dependencies in a common/known location:

dotnet restore <path/to/.csproj> --packages packages

On Azure Devops, I added a dotnet restore task, and in the "Advanced" section, disabled the cache, and set the destination directory to $(system.defaultworkingdirectory)\packages. With that done, I added the following ItemGroup to the CLI's .csproj:

  <ItemGroup>
    <Content Include="..\GitmoSharp\bin\$(Configuration)\netstandard2.0\**\*.*" Link="..\..\..\tools\%(Filename)%(Extension)" />
    <Content Include="..\packages\mono.options\*\lib\netstandard1.3\*.*" Link="..\..\..\tools\%(Filename)%(Extension)" />
  </ItemGroup>

My particular project had a number of other dependencies, but this is a simple example that shows how to add in a library project in the same solution, and a nuget package (Mono.Options, in this case). The key bit here is the Link attribute ... those Content files get put into some content folder, so with a bit of sneakiness (ie. ..\..\..\), I moved those to be dropped into the tools directory.

This is far from ideal, but at least I have it working now ... really looking forward to there being an official method of doing this very thing automatically. It really feels like IsTool should do all this without any further configuration.

FWIW the way I solved this problem prior to finding this issue was to do a dotnet publish and then nuget pack with a custom .nuspec file that takes the contents of the publish output and puts it in the tools folder. Less hardcoding of versions in paths that way.

e.g.

foo.nuspec

<?xml version="1.0"?>
<package >
  <metadata>
    <id>package_id</id>
    <version>1.0.0</version>
    <description>description</description>
    <authors>author1;author2</authors>
  </metadata>
  <files>
    <file src="**" target="tools" />
  </files>
</package>

Then run nuget pack foo.nuspec -BasePath path/to/publish/folder

It's exactly 2 years old. Happy 2nd birthday, Issue! 🎂

Having this in nuspec is the workaround I use (my tools are single-target):

<files>
  <file src="bin\$configuration$\net472\*" target="tools" />
</files>

In csproj I have this:

<IsTool>true</IsTool>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>

And I build the package using nuget.exe pack with the -Tool option.

Hey, I can see this above:

jjanuszkiewicz unassigned rohit21agrawal 5 days ago

I have no idea what's going on!

Having this as well. The interesting part is that it doesn't seem to include the exe for netcoreapp3.0:

// As described in the this issue: https://github.com/NuGet/Home/issues/4360
// we should not use IsTool, but set BuildOutputTargetFolder instead
msBuildSettings.WithProperty("BuildOutputTargetFolder", "tools");
//msBuildSettings.WithProperty("IsTool", "true");

image

It does include it for .net 4.7 though. The exe is in the output directory for .net core app. Will remove .net core app for now as a "workaround".

Here's a work around for those who don't want a nuspec file.

<PropertyGroup>
    <GenerateNuspecDependsOn>IncludeOutputInContent;$(GetPackageVersionDependsOn)</GenerateNuspecDependsOn>
  </PropertyGroup>
  <Target Name="IncludeOutputInContent" AfterTargets="Build" Condition="'$(GeneratePackageOnBuild)'=='true'">
    <ItemGroup>
      <None Include="bin\$(Configuration)\$(TargetFramework)\**\*">
        <Pack>true</Pack>
        <PackagePath>tools</PackagePath>
      </None>
    </ItemGroup>
  </Target>

Here's a work around for those who don't want a nuspec file.

<PropertyGroup>
    <GenerateNuspecDependsOn>IncludeOutputInContent;$(GetPackageVersionDependsOn)</GenerateNuspecDependsOn>
  </PropertyGroup>
  <Target Name="IncludeOutputInContent" AfterTargets="Build" Condition="'$(GeneratePackageOnBuild)'=='true'">
    <ItemGroup>
      <None Include="bin\$(Configuration)\$(TargetFramework)\**\*">
        <Pack>true</Pack>
        <PackagePath>tools</PackagePath>
      </None>
    </ItemGroup>
  </Target>

Best birthday present ever. Thank you

you can also just set the property BuildOutputTargetFolder to tools and SuppressDependenciesWhenPacking to true to suppress the dependencies in the nuspec file. You don't need to set IsTool to true.

This also worked and seems more official:

https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets#targetsfortfmspecificbuildoutput

    <PropertyGroup>
        <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);ToolDependenciesTarget</TargetsForTfmSpecificBuildOutput>
    </PropertyGroup>
    <Target Name="ToolDependenciesTarget">
        <Message Text="Including dependencies from $(OutputPath)" Importance="high" />
        <ItemGroup>
            <BuildOutputInPackage
                    Include="$(OutputPath)\**"
                    Exclude="$(OutputPath)\$(TargetName)$(TargetExt);$(OutputPath)\$(TargetName).pdb"
                >
                <PackagePath>tools\$(TargetFramework)</PackagePath>
            </BuildOutputInPackage>
        </ItemGroup>
    </Target>
Was this page helpful?
0 / 5 - 0 ratings