Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OutputPath logic in Pack targets in a customized build doesn't work properly #9234

Closed
Nirmal4G opened this issue Feb 29, 2020 · 19 comments · Fixed by NuGet/NuGet.Client#3270
Closed

Comments

@Nirmal4G
Copy link

Nirmal4G commented Feb 29, 2020

NuGet.Build.Tasks.Pack project in NuGet.Client repo

    <PropertyGroup>
      <PackageOutputPath Condition=" '$(PackageOutputPath)' == '' ">$(OutputPath)</PackageOutputPath>
      <RestoreOutputPath Condition=" '$(RestoreOutputPath)' == '' " >$(MSBuildProjectExtensionsPath)</RestoreOutputPath>
    </PropertyGroup>

File: NuGet.Build.Tasks.Pack.targets(149-152)

I don't know why but when I try to customise a build relying on Pack targets, the output path logic hits me with so many issues that it doesn't work out of the box.

There are two main issues here,

  1. OutputPath should be BaseOutputPath since, you are generating single package for many targets at once, which is similar to NuSpecOutputPath (has BaseIntermediateOutputPath).
  2. The output paths logic is placed inside a target, which means in a customised build, overriding the target or excluding that particular logic cause path issues.

Related issue: dotnet/sdk#10730

Fix/Solution: Move the logic out of the target and place it where NuSpecOutputPath property is.

Breaks anything?: N/A

@Nirmal4G
Copy link
Author

Nirmal4G commented Mar 4, 2020

Supersedes #9231

@nkolev92
Copy link
Member

OutputPath should be BaseOutputPath since, you are generating single package for many targets at once, which is similar to NuSpecOutputPath (has BaseIntermediateOutputPath).

In which project types is this an issue?

The output paths logic is placed inside a target, which means in a customised build, overriding the target or excluding that particular logic cause path issues.

Can you give an actual example?

In #9231, I simply wanted a default so that when you install the SDK, you don't get errors such as PackageOutputPath not being set!

@nkolev92
Copy link
Member

In SDK based projects the structure is and should remain:

bin\Debug*.nupkg
bin\Debug\targetFrameworkName1*.dll
bin\Debug\targetFrameworkName2*.dll
obj\Debug*.nuspec
obj\Debug\targetFrameworkName1*.dll
obj\Debug\targetFrameworkName2*.dll

The outputs should mimic one another.

So the non-sdk based project defaults should be:

App
bin\Debug*.dll, *.exe, *.nupkg
obj\Debug*.nuspec, *.dll

@Nirmal4G
Copy link
Author

Nirmal4G commented Mar 25, 2020

In the SDK project, the structure becomes

obj\Debug\*.nuspec
bin\Debug\<targetFrameworkName>\<Rid>\*.nupkg

If we just use the OutputPath in the pack targets without the PackageOutputPath being set in the SDK!

With BaseOutputPath the above problem goes away. But BaseOutputPath is not present in the common targets, only in SDK targets. See the issue here...?!

@Nirmal4G
Copy link
Author

That's why I offered two solutions without needing to modify common targets

NuGet/NuGet.Client#3270 (comment)

@nkolev92
Copy link
Member

obj\Debug<targetFrameworkName><Rid>*.nuspec

Please provide a repro.
Pack runs in the outerbuild, no rid and tfms are set in the outer build.

@Nirmal4G
Copy link
Author

Nirmal4G commented Mar 26, 2020

Sorry about the mistake! fixed the comment

Only nupkg path is wrong. nuspec uses BaseIntermediateOutputPath which will always have correct path.

Here's the repro

OutputPath Repro

Pack any project and look at the directory tree. Then change the properties in Directory.Build.props and pack again to see the changes (w.r.t. the various fixes I proposed in the PR).

@nkolev92
Copy link
Member

nkolev92 commented Mar 27, 2020

Ok, I finally understand your concern.

A few points however:

  • No regression/changes in SDK based projects. That means in sdk based projects we default to OutputPath, the same way we always have.
  • In non-SDK based projects, we can add a default that goes to $(BaseOutputPath)$(ConfiguratioN) to avoid putting the nupkg in platform specific folders.
  • Avoid using both Platform and RuntimeIdentifier in SDK based projects, https://github.com/dotnet/sdk/issues/1553 In particular probably set the platform in full framework projects only.

Given that here are my recommendations.

  • Don't change the default for SDK based projects, just lift them and do the same test.
  • For Full framework projects, a good default would be baseoutput/configuration which is the equivalent of what OutputPath is in in the outer build in SDK based projects.

@Nirmal4G
Copy link
Author

Nirmal4G commented Mar 28, 2020

No regression/changes in SDK based projects. That means in sdk based projects we default to OutputPath, the same way we always have.

In SDK projects, single-targeting will put the output nupkg to bin\<platform>\Debug\<tfm>\<rid>\*.nupkg when we remove the property in the SDK targets. It'll still be in bin\Debug\<tfm>\*.nupkg at the least, which is confusing.

Package path should not change for any custom build except Configuration, since you might need to upload debug packages to private feed while release packages to public.

Don't change the default for SDK based projects, just lift them and do the same test.

Are you sure that's what we want?

The BaseOutputPath will unify package output into single directory on both sdk (both outer/inner builds) and non-sdk projects.

We can do the BaseOutputPath changes along with MSBuild's Common targets' changes (if they'll accept). Besides what the user has set will always takes precedence, we're merely adjusting the defaults to be deterministic.

There are proposals to unify build outputs. I think this change might play well with those.

@nkolev92
Copy link
Member

I screwed up something in my test for SDK based projects.
Let's just do BaseOutputPath and configuration for both.

@Nirmal4G
Copy link
Author

Let's just do BaseOutputPath and configuration for both.

It's practically done. Let me know if there are any issues with the tests. I have yet to add framework pack tests too but that depends on changes from MSBuild common targets.

I have asked MSBuild team on BaseOutputPath in common targets.

@nkolev92
Copy link
Member

I posted a comment on the PR to clean up a thing or two.

Because the pack targets are installed and used with both newer and older VS versions, we can consider a different default for non-SDK based projects.
We are really only trying to improve things there.

Sorry it took us a while to fully understand to what you were proposing.
The inconsistency throughout the targets got me so many times while testing :)

@Nirmal4G
Copy link
Author

The inconsistency throughout the targets got me so many times while testing :)

I have updated the repro projects link: #9234 (comment)

we can consider a different default for non-SDK based projects.

VS team can update pack targets in the next revision, right?

If we're back porting changes just to have the default, we can set OutputPath for older versions. but this also depends on the answer from MSBuild team. If they too are back-porting BaseOutputPath to older versions then we can just use that.

@nkolev92
Copy link
Member

VS team can update pack targets in the next revision, right?

Not sure what you by vs team, but NuGet owns these experiences.

If we're back porting changes just to have the default, we can set OutputPath for older versions. but this also depends on the answer from MSBuild team. If they too are back-porting BaseOutputPath to older versions then we can just use that.

I don't think there'll be any servicing...the need is not there.
So for old style csproj we should do something that works today.

@Nirmal4G
Copy link
Author

Nirmal4G commented Mar 31, 2020

NuGet owns these experiences

I suppose, we could wait for dotnet/msbuild#1664. PR to Add BaseOutputPath is at dotnet/msbuild#5238

So for old style csproj we should do something that works today.

If it's urgent, I'll open a separate PR for using OutputPath as a default. Is that ok?

@nkolev92
Copy link
Member

If it's urgent, I'll open a separate PR for using OutputPath as a default. Is that ok?

If you want to keep the changes isolated, let's reopen #9231 and handle that in a different PR.
I am ok with doing both in the current PR though. I think both changes need to go in the same release.

Nirmal4G added a commit to Nirmal4G/dotnet-sdk that referenced this issue Apr 6, 2020
This should free the SDK from having to manage NuGet Pack's `PackageOutputPath` property.
This was possible because of the `BaseOutputPath` that'll be used instead of `OutputPath` in the Pack targets.
It does depend on NuGet's Fix. Issue: NuGet/Home#9234 PR: NuGet/NuGet.Client#3270
Hopefully, this change won't break anything...
@Nirmal4G
Copy link
Author

Me too. One PR is enough for this change.

Still waiting on the MSBuild PR.

Nirmal4G added a commit to Nirmal4G/dotnet-sdk that referenced this issue Apr 14, 2020
This should free the SDK from having to manage NuGet Pack's `PackageOutputPath` property.
This was possible because of the `BaseOutputPath` that'll be used instead of `OutputPath` in the Pack targets.
It does depend on NuGet's Fix. Issue: NuGet/Home#9234 PR: NuGet/NuGet.Client#3270
Hopefully, this change won't break anything...
@malovicg
Copy link

malovicg commented Dec 16, 2023

I am not quite sure what was agreed here. $(OutputPath) returns different paths when used with build, pack and nuget commands.

An example for build output of Microsoft.NET.Sdk.Razor project type in Release mode and .NET 8:

Build -> /bin/Release/net8.0
Pack -> /bin/Release (default value is $(OutputPath))

Now, I wanted to execute nuget add command after Pack command, so I used MSBuild Task for this purpose inisde .csproj:

<Target Name="NugetAdd" AfterTargets="Pack" Condition=" '$(Configuration)' == 'Release'"> <Exec Command="nuget add $(OutputPath)$(PackageId).$(PackageVersion).nupkg -Source 'c:\nuget\packages\'" /> </Target>

$(OutputPath) in nuget command is resolved as /bin/Release/net8.0, same with build command. So this means that the only different behavior for output path we see in Pack command, which removes $(TargetFramework) from output. This is the reason why above nuget add fails with

Provided Nupkg file 'bin\Release\net8.0\fileName.nupkg' is not found.

Is this different behavior intentional? If yes, how can I achieve my task, without using hardcoded paths in nuget add command for nupkg file? I tried setting PackageOutputPath to $(OutputPath)$(TargetFramework), but this resolves in net8.0 only, not bin/Release/net8.0.

@Nirmal4G
Copy link
Author

The PackageOutputPath is being overriden in SDK targets. I had a patch there to remove that but ultimately it was dropped. So technically, the issue still remains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants