-
Notifications
You must be signed in to change notification settings - Fork 695
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
Use MSBuildProjectExtensionsPath for RestoreOutputPath #2056
Use MSBuildProjectExtensionsPath for RestoreOutputPath #2056
Conversation
This is not a complete fix actually. This is a breaking change, doesn't matter which way we implement it. I think we need to analyze this, and discussing internally before committing to a fix. Personally, I'd like us to get this in, but the road is thorny. |
//cc @rrelyea for visibility. Related issue here: |
Per discussion with @nkolev92, here are some outstanding items for this:
|
|
||
namespace NuGet.Build.Tasks | ||
{ | ||
public class ErrorForMismatchRestoreOutputPathTask : Task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed in chat, can you please remove this error message, because it will break the advanced scenarios (namely dotnetclitool and global tools).
…ectExtensionsPath
@nkolev92 I've removed the error message and modified |
{ | ||
ThreadHelper.ThrowIfNotOnUIThread(); | ||
|
||
var baseIntermediatePath = _vsProjectAdapter.BaseIntermediateOutputPath; | ||
var restoreOutputPath = _vsProjectAdapter.RestoreOutputPath; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be MSBuildProjectExtensionsPath, or did we misunderstand each other?
RestoreOutputPath is only meant to be used in non-VS/non-build scenarios. Namely the tool restore.
The property here should be the same as the one we read in MsBuild.
@@ -35,7 +35,7 @@ private static string GetBuildIntegratedProjectCacheFilePath(RestoreRequest requ | |||
|| request.ProjectStyle == ProjectStyle.PackageReference | |||
|| request.ProjectStyle == ProjectStyle.Standalone) | |||
{ | |||
var cacheRoot = request.BaseIntermediateOutputPath ?? request.RestoreOutputPath; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since MsbuildExtensionsPath will always be set, it breaks this logic here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks project.json.
Don't remove RestoreOutputPath as from restoreRequest as the assets/lock and msbuild properties go to the project directory, but the cache file still goes into obj.
@nkolev92 We discussed today that we want However, since the .NET CLI uses Because of this, how would you feel about the following?
|
@dsplaisted I'd like us to have a minimal fix, that being replace The error could be something that we add later on. |
@nkolev92 OK, so what else do you think needs to be done with this PR? |
Basically, it the diff should be changing the BaseIntermediateOutputPath calls to MsBuildExtensionsPath. Don't replace GetBaseIntermediate with GetRestoreOutputPath because the cache path calculatio is a bit different. |
After a discussion offline: Tracking bug for follow-up 15.7 work.
|
…h in VS project adapters
ea78d16
to
09f1311
Compare
@@ -577,6 +578,12 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
<Output TaskParameter="AbsolutePaths" PropertyName="RestoreOutputAbsolutePath" /> | |||
</ConvertToAbsolutePath> | |||
|
|||
<WarnForMismatchedBaseIntermediateOutputPathTask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced that this makes sense. I could set just MSBuildProjectExtensionsPath
and leave BaseIntermediateOutputPath
alone if I wanted. With this warning, I would feel like I need to set them both always to the same location. Why even have a different property?
If NuGet only reads MSBuildProjectExtensionsPath
, why would it care what the value of BaseIntermediateOutputPath
is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with Jeff on this, that's why I added it in the follow-up task, becuase I'm not convinced we should add it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jeffkl @nkolev92 My reasoning is that the common case will be that BaseIntermediateOutputPath
is set in the body of the project, and the result is not what was expected (ie the expectation was that nothing would be written to obj
in the project folder. So the warning helps guide people to the right way of doing what they want to do.
I forgot to allow the warning message to be disabled by setting a property, which is what I was thinking you would do if you actually wanted the paths to be different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should rely on the error in MSBuild we're adding: dotnet/msbuild#3059
Is that not enough? I'd be okay with this warning if it was only displayed when BaseIntermediateOutputPath is different and it was modified. But I don't think it should happen anytime they're different after evaluation...
…ct uses PackageReferenc
491c25f
to
b0eae2d
Compare
@nkolev92 I think this is ready for review now. It enables the warning being added in dotnet/msbuild#3059. /cc @jeffkl |
@nkolev92 I think I've fixed the behavior for project.json. Please take a look. |
//cc |
DependencyGraphSpec = projectDgSpec, | ||
BaseIntermediateOutputPath = projectPackageSpec.RestoreMetadata.OutputPath, | ||
RestoreOutputPath = projectPackageSpec.RestoreMetadata.OutputPath, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be:
RestoreOutputPath = project.PackageSpec.RestoreMetadata.ProjectStyle == ProjectStyle.ProjectJson ? rootPath : project.PackageSpec.RestoreMetadata.OutputPath,
Why did it change?
I feel like the assetscachepath and the restoreoutputpath conditions are swapped here, unless I am missing something.
It seems to me that this is going to be null in the project.json case from commandline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you are right about the conditions being swapped. Thanks for catching that!
It seems to me that this is going to be null in the project.json case from commandline.
Looking at MSBuildRestoreUtility, it looks like the RestoreOutputPath will be set for project.json projects:
result.RestoreMetadata.OutputPath = specItem.GetProperty("OutputPath");
<PropertyGroup Condition=" '$(RestoreProjectStyle)' == 'ProjectJson' "> | ||
<!-- For project.json projects, only the assets file cache goes in the RestoreOutputPath. The assets file and the | ||
generated .props and .targets go in the project folder. So in that case use the BaseIntermediateOutputPath, | ||
so that the assets file cache will respect a BaseIntermediateOutputPath set in the project body. --> | ||
<RestoreOutputPath Condition=" '$(RestoreOutputPath)' == '' " >$(BaseIntermediateOutputPath)</RestoreOutputPath> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now different between VS and commandline for Project.Json?
One cache file goes BaseIntermediate, the other one goes to MsBuildExtensionsOutputPath.
Why not use MSBuildProjectExtensionsPath here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't mean to make it inconsistent, so if it is that should be fixed.
But the idea is that for project.json, the generated props and targets go in the project folder and are imported via other means, so the whole reason we needed to switch to MSBuildProjectExtensionsPath doesn't exist. So we might as well continue to use BaseIntermediateOutputPath so that we don't change where the assets cache goes if BaseIntermediateOutputPath has been overridden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Valid.
I think I'll just change what we read in VS for PJ then.
Other than that, this change, looks fine to me.
I'll get someone else to review it and merge it to a feature branch, and fix the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the issue if we change it for project.json as well? at least that way, it will be a consistent behavior across project formats...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jainaashish
We can do either one.
The argument would be, no need to risk changing the experience in PJ, because it's not fixing a bug there.
I personally don't care too much either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the time when we're still supporting pj for legacy projects, I'd recommend we keep the code same across formats instead of making it conditional.
/// </summary> | ||
public string BaseIntermediateOutputPath { get; set; } | ||
public string AssetsCachePath { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also a NuGet restore artifact just like assets file or target file, so I think this should also go in the same location.
@@ -43,17 +43,17 @@ public LegacyPackageReferenceProjectTests(DispatcherThreadFixture fixture) | |||
} | |||
|
|||
[Fact] | |||
public async Task GetAssetsFilePathAsync_WithValidBaseIntermediateOutputPath_Succeeds() | |||
public async Task GetAssetsFilePathAsync_WithValidMSBuildProjectExtensionsPath_Succeeds() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before merging this PR, we have to add func tests to cover this scenario. So either we add as part of this PR itself or open a workitem to add them subsequently
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jainaashish
My plan was to merge this in a feature branch....work on some tests, PR those against the feature branch, and then merge that into dev.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good!
@nkolev92 I've pushed some updates which should fix the test failures (or at least some of them). Can you kick off another test pass? Thanks! |
@nkolev92 I've pushed some updates that should at least fix the compile errors. I think the tests that were failing before should pass now, although I might have broken other stuff. |
<RestoreOutputPath Condition=" '$(RestoreOutputPath)' == '' " >$(BaseIntermediateOutputPath)</RestoreOutputPath> | ||
<!-- For project.json projects, the restore output path is the project directory. The assets file cache | ||
goes in BaseIntermediateOutputPath. --> | ||
<RestoreAssetsCacheFolder Condition=" '$(RestoreOutputPath)' == '' " >$(BaseIntermediateOutputPath)</RestoreAssetsCacheFolder> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change this?
I fear this is becoming a bigger refactoring than it needs to be.
I'd like the change to be more targeted so we can actually merge it, and solve the initial problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nkolev92 I just keep hitting issues where I'm having trouble following how all the data about the paths to use flows through, so I try to refactor it to make it more understandable to have more confidence that the change is correct.
Additionally I decided to use the BaseIntermediateOutputPath for project.json projects. I'm fine with just using MSBuildProjectExtensionsPath in both cases, but I don't think that would significantly affect the other changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the refactoring is necesarry, because in the end, this is a very simple change on our side.
Can you please revert these refactoring and I'll merge it in a feature branch and clean it up there?
Closing in favor of #2121 |
This is part of a solution to dotnet/msbuild#1603. The
MSBuildProjectExtensionsPath
is where MSBuild will automatically import project .props and .targets files from. This PR changes theRestoreOutputPath
to default toMSBuildProjectExtensionsPath
instead ofBaseIntermediateOutputPath
. By default, both of these properties will default to theobj
folder, but this change will make the behavior more correct if one of the properties is overridden.This PR also adds an error message if
RestoreOutputPath
doesn't matchMSBuildProjectExtensionsPath
. This is because if they don't match, Restore will write .props and .targets to one location, while MSBuild will look in another, so the .props and .targets that Restore writes won't be used in the build.I could use some help figuring out how to add a test for this behavior. @rohit21agrawal @nkolev92 To test it I think you really need to restore a project that sets
RestoreOutputPath
to something different thanMSBuildProjectExtensionsPath
, and verify that an NU1004 error is generated. Would the EndToEnd tests that are implemented in PowerShell be the right place for this? How do you run those tests?Included in this PR is also a commit that replaces
new string[0]
withArray.Empty<string>()
, which was something I noticed when browsing the code investigating this change.