Home: License file with no extension fails to pack with dotnet pack and msbuild /t:pack

Created on 7 Dec 2018  路  26Comments  路  Source: NuGet/Home

Details about Problem

NuGet product used (NuGet.exe | VS UI | Package Manager Console | dotnet.exe): dotnet.exe and msbuild.exe

dotnet.exe --version (if appropriate): 2.1.600-preview-009426
msbuild version: 16.0.218-preview+g5c625fa747

Detailed repro steps so we can see the same problem

  • dotnet new classlib
  • edit generated csproj, add the following lines:
  <PropertyGroup>
    <PackageLicenseFile>license</PackageLicenseFile>
  </PropertyGroup>

  <ItemGroup>
    <None Include="license" Pack="true" PackagePath="$(PackageLicenseFile)" />
  </ItemGroup>
  • Create the license file with any text
  • dotnet pack

Verbose Logs

> dotnet pack
Microsoft (R) Build Engine version 16.0.225-preview+g5ebeba52a1 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 39.19 ms for E:\dev\misc\libtest3\libtest3.csproj.
C:\Program Files\dotnet\sdk\2.1.600-preview-009426\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(143,5): message NETSDK1057: You are working with a preview version of the .NET Core SDK. You can define the SDK version via a global.json file in the current project. More at https://go.microsoft.com/fwlink/?linkid=869452 [E:\dev\misc\libtest3\libtest3.csproj]
  libtest3 -> E:\dev\misc\libtest3\bin\Debug\netstandard2.0\libtest3.dll
C:\Program Files\dotnet\sdk\2.1.600-preview-009426\Sdks\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets(199,5): error NU5030: The license file 'license' does not exist in the package. [E:\dev\misc\libtest3\libtest3.csproj]

Other

If I remove the <PackageLicenseFile>license</PackageLicenseFile> line, it packs fine and license file is added to nupkg. It also works if I drop the PackagePath="$(PackageLicenseFile)" portion. And it works if I use license.txt as a file name everywhere.

Pack NotABug

Most helpful comment

IMO this is a bad behavior. It is very common to include an extension-less LICENSE file along with the repo.

All 26 comments

This is function of how paths are handled in general.

Putting simply "license" in PackagePath (what it resolves to), gets treated as a folder, rather than a file. Which also explains why dropping PackagePath works.
Another option would be to specify ".".

Closing per my above comment.

IMO this is a bad behavior. It is very common to include an extension-less LICENSE file along with the repo.

@replaysMike
It doesn't prevent you from packing a extensionless license, as I said in my above comment.
Furthermore this behavior is about way more than licenses, and requiring a trailing slash for directories would be a breaking change at this point.

This is a really bad practice and it is also broken also in nuget.exe 4.9.2.5706 and that trick with the trailing dot doesn't work.

    <license type="file">LICENSE</license>
...
  <files>
   <file src="licenses/LICENSE." target="" />
  </files>

I tried the above with all combinations of LICENSE without a dot and with a dot and having a dot only in one of them or another - nothing works and I always get this error:

Error NU5019: File not found: 'licenses/LICENSE.'.

Only when I add something like .txt, it works, but then I have to modify a 3rd-party file.

Ok, I found a combination that works. This is not very obvious.

    <license type="file">licenses\LICENSE.</license>
...
  <files>
   <file src="licenses\LICENSE" target="licenses\LICENSE." />
  </files>

Notice how src doesn't have a dot, but target and file do. It only works in this combination and all other dot placements fail. Seeing how you are adding a trailing underscore to the extension-less files to track them as such, I can see the lengths you went to deal with this. It would be simpler if you assumed a directory only if it ends in a slash.

@gh-andre

It would be simpler if you assumed a directory only if it ends in a slash.

That's not/wasn't my decision.
Pack (both nuget.exe and dotnet.exe) have worked a certain way for a very long time. Changing that now would be a big breaking change.
You can also do

    <license type="file">LICENSE</license>
...
  <files>
   <file src="licenses\LICENS*" target="" />
  </files>

Similar to
https://github.com/NuGet/Samples/blob/master/PackageLicenseFileNuspecExample/PackageLicenseFileNuspecExample.nuspec

@nkolev92 Thanks for responding. As long as there is a work around, I can live with it.

@nkolev92 Also, having this documented on MSDN would certainly help. Nuget seems to be tailored for .Net deployments and there is little-to-none on how to work with native packages, especially when contents is not Windows-specific.

I concur, this is still blocking an extensionless LICENSE file.

<PropertyGroup>
  <PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
  <None Include="..\..\LICENSE" Pack="true" PackagePath="$(PackageLicenseFile)">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Which yields:

Severity    Code    Description Project File    Line    Suppression State
Error   NU5030  The license file 'LICENSE' does not exist in the package.   my.project  C:\Program Files\dotnet\sdk\2.1.507\Sdks\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets    202 

Whereas, when the file is named LICENSE.txt, for instance, the build succeeds, but only partially. The file is completely ignored, see below.

This is a bug, NuGet/Microsoft.

Further, dotnet pack is only using PackageLicenseExpression completely ignoring PackageLicenseFile when that has been specified. This is not a documentation issue, but a failure to execute, especially when so much dust has been kicked up over a migration path (loosely so-called).

This is kind of a kluge workaround IMO:

<PropertyGroup>
  <_DesiredLicenseFileName>LICENSE.</_DesiredLicenseFileName>
  <_InternalLicenseFileName>LICENSE.txt</_InternalLicenseFileName>
</PropertyGroup>

<Target Name="CopyLicenseFileForPackagingPurposes" BeforeTargets="BeforeBuild" Condition="!Exists('..\..\$(_InternalLicenseFileName)')">
  <Copy SourceFiles="..\..\$(_DesiredLicenseFileName)" DestinationFiles="..\..\$(_InternalLicenseFileName)" />
</Target>

And so on...

<PropertyGroup>
  <PackageLicenseFile>$(_InternalLicenseFileName)</PackageLicenseFile>
</PropertyGroup>

<ItemGroup>
  <None Include="..\..\$(_InternalLicenseFileName)" Pack="true" PackagePath="$(_InternalLicenseFileName)">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Which we do end up with the License File in the package nuspec:

<license type="file">LICENSE.txt</license>

However, to include a deprecateLicenseUrl there as well is unprofessional, Microsoft. How do we torpedo that output?

<licenseUrl>https://aka.ms/deprecateLicenseUrl</licenseUrl>

@mwpowellhtx

This is kind of a kluge workaround IMO:

There is a simpler solution. This is how paths have been treated in nuget/msbuild for a while. Changing it would be a huge breaking change.
https://github.com/NuGet/Home/issues/7601#issuecomment-450209731

However, to include a deprecateLicenseUrl there as well is unprofessional, Microsoft. How do we torpedo that output?

Refer to the spec for that behavior: https://github.com/NuGet/Home/wiki/Packaging-License-within-the-nupkg
It is there for backwards compatibility.

Further, dotnet pack is only using PackageLicenseExpression completely ignoring PackageLicenseFile when that has been specified. This is not a documentation issue, but a failure to execute, especially when so much dust has been kicked up over a migration path (loosely so-called).

If you do that the following warning will be raised.
https://docs.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu5033

I have a test for that https://github.com/NuGet/NuGet.Client/blob/74508a570f9611e3ecd1641415a7bf9d9ee6e0ef/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs#L3455.

If you see it otherwise, please create a new issue with that information.

@nkolev92 This is effectively the workaround I've taken.

Or is a path to a license file. E.g. <license type="file">LICENSE.txt</license>

Coupled with other precautions. i.e. copied LICENSE to LICENSE.txt as a before build target, added LICENSE.txt to Git-ignored directories/files, and so on.

You can always do the below if you are using dotnet pack

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
    <PackageLicenseFile>License</PackageLicenseFile>
  </PropertyGroup>

  <ItemGroup>
    <None Include="License" Pack="true" Visible="false" PackagePath=""/>
  </ItemGroup>

</Project>

@nkolev92 That did not work, assuming file system behavior, <PackageLicenseFile>License</PackageLicenseFile> is case insensitive, same as <PackageLicenseFile>LICENSE</PackageLicenseFile>, and is the reason we are having this exchange in the first place.

To be clear, I am specifying <PackageLicenseFile>$(_InternalLicenseFileName)</PackageLicenseFile>, which ends up being <_InternalLicenseFileName>LICENSE.txt</_InternalLicenseFileName>, assuming LICENSE precautions taken in advance, etc.

That did not work, assuming file system behavior, License is case insensitive, same as LICENSE, and is the reason we are having this exchange in the first place.

I'm not following the concern.
Why wouldn't my example work? The casing is consistent. I just tested it myself and I did not hit any problems.

Furthermore, what you are articulating is just how MSBuild works since it is case insensitive.
The property names are case insensitive. The values in them are case preserving for the consumer of the property.

@nkolev92 So, what you're telling me is MSBuild's treatment of property values is inconsistent (i.e. case sensitive) with how the operating system treats file names (i.e. case insensitive). All I'm saying is, file name and property named LICENSE did not work, I got the packaging error.

So, what you're telling me is MSBuild's treatment of property values is inconsistent (i.e. case sensitive) with how the operating system treats file names (i.e. case insensitive).

No, what I'm saying it's the following. I'll illustrate with an example:

    <PackageLicenseFile>LICENSE</PackageLicenseFile>
    <packagelicensefile>license</packagelicensefile>

  <Target Name="MyTarget">
      <Message Text="The PackageLicenseFile value is $(PackageLicenseFile)" Importance="high"  />
  </Target>

dotnet msbuild /t:MyTarget myproj.csproj
The PackageLicenseFile value is license

Reasoning: MSBuild evaluates top to bottom, and packagelicensefile is the latest declaration

    <PackageLicenseFile>LICENSE</PackageLicenseFile>
    <packagelicensefile>LICENSE</packagelicensefile>

  <Target Name="MyTarget">
      <Message Text="The PackageLicenseFile value is $(PackageLicenseFile)" Importance="high"  />
  </Target>

dotnet msbuild /t:MyTarget myproj.csproj
The PackageLicenseFile value is LICENSE

    <packagelicensefile>LICENSE</packagelicensefile>

  <Target Name="MyTarget">
      <Message Text="The PackageLicenseFile value is $(PackageLicenseFile)" Importance="high"  />
  </Target>

dotnet msbuild /t:MyTarget myproj.csproj
The PackageLicenseFile value is LICENSE

The MSBuild property names are case insensitive.
The values inside are case sensitive. It's up to consumer to enforce the casing.
In the license pack case it's NuGet and the file system.

In MSBuild it's valid to say

<None Include="files/license.txt"/>
<None Include="files/License.txt"/>

as long as the file system says it's ok.

I have uploaded an extensionless sample in the nuget samples repo that I have verified that it works on my end.

https://github.com/NuGet/Samples/tree/master/PackageLicenseFileExtensionlessExample

@nkolev92 No, you are missing the point. <PackageLicenseFile>LICENSE</PackageLicenseFile> fails to package. It is because the file apparently cannot be called LICENSE, or apparently any extensionless naming convention. Or if there is some internal machinery in MSBuild itself, it is case sensitive and wants License, but this is inconsistent with the operating system naming convention. Anyway, we have an adequate, at best, workaround.

Tried the workarounds, but doesn't work - at least not on the official ASP.NET Core 2.1 Docker image. I ended up renaming the file from LICENCE to LICENCE.txt. Seems the simplest solution to me, instead of banging my head with such trivial things.

@DMW007 I ended up doing the same thing. Then MSBuild sees it and life is good. Not perfect, but it is an acceptable work around.

You can always do the below if you are using dotnet pack

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0</TargetFrameworks>
    <PackageLicenseFile>License</PackageLicenseFile>
  </PropertyGroup>

  <ItemGroup>
    <None Include="License" Pack="true" Visible="false" PackagePath=""/>
  </ItemGroup>

</Project>

The above proposition from @nkolev92 just worked fine for me (with dotnet pack) with a license file named LICENSE, it took me hours to end up here because I couldn't make it work with the official documentation. Hopefully this will be documented explicitly at some point.

In any case, thank you.

@LukeMarlin Like you, I ended up isolating a "licensing" target that I could import into my projects along similar lines. However, you must rename the file as the file name "license", really "license." is not supported.

Any chance of re-opening this issue? Having a LICENSE file at the root of the repository is a common standard on open-source projects.

We should be able to simply reference that file from our .csproj using a relative path:

  <PropertyGroup>
    <PackageLicenseFile>..\..\LICENSE</PackageLicenseFile>
  </PropertyGroup>

dotnet pack fails when using the above:

C:\Program Files\dotnet\sdk\3.1.300\Sdks\NuGet.Build.Tasks.Pack\buildCrossTargeting\NuGet.Build.Tasks.Pack.targets(198,5):
error NU5030: The license file '..\..\LICENSE' does not exist in the package. [C:\Users\augustoproiete\my-project\src\MyProject\MyProject.csproj]

@gh-andre

It would be simpler if you assumed a directory only if it ends in a slash.

That's not/wasn't my decision.
Pack (both nuget.exe and dotnet.exe) have worked a certain way for a very long time. Changing that now would be a big breaking change.
You can also do

    <license type="file">LICENSE</license>
...
  <files>
   <file src="licenses\LICENS*" target="" />
  </files>

Similar to
https://github.com/NuGet/Samples/blob/master/PackageLicenseFileNuspecExample/PackageLicenseFileNuspecExample.nuspec

Not sure why you took the "E" off. You need only put "*" on the end.

Was this page helpful?
0 / 5 - 0 ratings