-
Notifications
You must be signed in to change notification settings - Fork 265
Design for allowing restore of multiple equivalent frameworks (Target Frameworks as Aliases) #12124
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
base: dev
Are you sure you want to change the base?
Conversation
Nirmal4G
left a comment
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.
Some ideas and suggestions. Feel free to ignore it. 😅🙃
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
|
Thanks for taking a look @Nirmal4G For context, this is design I'm still working on, I'd say it's at about 50%. Hoping to add more details about the scenarios and just in general provide more concrete proposals soon. |
|
@nkolev92 These are some of my observations and preliminary suggestions, ideas and takeaways from this draft. I'm not taking this as a concrete proposal. I'm just viewing this from a 10-foot view (or design perspective) of the proposal to see how it could impact normal as well as advanced users. In that mindset, read through my comments again. You would then see what I was talking about. |
Sure, Will look though once you mark this ready for review. Sorry for the uninvited comments. I'll stop now. |
Oh no worries. I appreciate the feedback as this is a large doc so getting feedback early on is always great. My comment was more about that fact that I'll be adding even more info to the doc, setting expectations about when something like this would even be close to happening :) |
proposed/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
55c6bba to
1c19625
Compare
accepted/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
accepted/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
accepted/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
|
This PR has been automatically marked as stale because it has no activity for 30 days. It will be closed if no further activity occurs within another 15 days of this comment, unless it has a "Status:Do not auto close" label. If it is closed, you may reopen it anytime when you're ready again, as long as you don't delete the branch. |
|
oops, vacation and other priorities has kept this feature on the backburner, but it's still planned. |
accepted/2022/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
1c19625 to
ddc7fae
Compare
ddc7fae to
413d370
Compare
… Frameworks as Aliases)
650ca9a to
b6c47f6
Compare
|
@ericstj @ViktorHofer @dsplaisted @baronfel @zivkan @jeffkl This is ready for review. It's a complicated, but I'd love to get through it async as much as possible because of the length itself :D |
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
|
|
||
| PackageReference is also supported by non-SDK style projects, which use [dotnet/NuGet.BuildTools](https://github.com/NuGet.BuildTools) which, despite the name, is owned by the non-SDK project system team, not NuGet. | ||
| The changes to the assets file that affect legacy projects will be done in a non-breaking way and as such, changes should not be required there. | ||
| NuGet will utilize the SDKAnalysisLevel property when it writes out an assets file with breaking changes, ensuring that the .NET SDK will be able to read the assets file for the build. |
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.
Customers are expected to change SDKAnalysisLevel if they have build errors when upgrading to a newer SDK. I can't remember the name of the property, but there's an SDK version that feels more appropriate for what this is aiming to achieve.
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.
Yeah, there's an SDK version property for sure, we raise telemetry on that, but I see SDKAnalysisLevel to mean, behave like the previous SDK version, and to me that'd imply the older restore behavior in general.
I don't feel too strongly though, and can easily be convinced otherwise.
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 my mind, SdkAnalysisLevel is about warnings and errors (diagnostics), not features, and looking at the original spec, I feel my opinion is reinforced: https://github.com/dotnet/designs/blob/main/proposed/sdk-analysis-level.md
The spec doesn't say it, but I always thought SdkAnalysisLevel was inspired by Roslyn's AnalysisLevel, and Roslyn also has LangVersion which I consider to be the feature toggle. The SDK/NuGet doesn't have a "global feature toggle" like Roslyn does with LangVersion. Using SdkAnalysisLevel is a choice that can be made, but then customers lose the ability to enable new features while disabling new diagnostics. I guess we need to decide whether that's an important distinction to allow customers to have.
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 Chet has a good compass when it comes to SDKAnalysisLevel.
Curious what you think @baronfel
tldr;
NuGet will introduce a V4 of the assets file.
It requires a new .NET SDK reader, ie a specific .NET SDK version.
Should that "switch" be based off of the SDKAnalysisLevel or NETCoreSdkVersion property.
More context on the pros and cons in the above comments.
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.
@baronfel attempted to post the below, but was facing GH problems:
The intent of SdkAnalysisLevel is to easily apply behaviors to all kinds of SDK-level analysis - not just Roslyn Analyzers, but built-in diagnostics, MSBuild BuildChecks, and similar. Any kind of validation that we do during a build was in scope.
This has evolved slightly to controlling behaviors as well - I am entirely supportive of this. The main reason for this evolution/broadening of meaning is that the user-facing view of this property is often "make the current SDK behave like the SDK band I tell you to". With this lens, applying SdkAnalysisLevel to behaviors in addition to validations is entirely appropriate.
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
|
|
||
| As previously shown in [the assets file pivots changes](#target-framework-pivots), NuGet uses `tfm/rid` as the property name in the `$/targets` object. | ||
| Therefore, a `TargetFramework` that includes a `/` will cause parsing challenges. | ||
| NuGet's libraries could attempt to do the split on the last `/` character. |
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.
Considering the assets file has an entry for the ridless target, in addition to the per-rid targets, I think it would be challening to tell the difference between the two.
If the parser keeps raw strings in memory and then parses the alias/rid only once all targets are parsed from json, then you can find what the max number of / are, and assume the ridless has n-1.
But I think it's easier if we fail restore if the alias has a /. It's easier to block first and later allow, than the other way around.
Since we're already incrementing the version number, I think it'd be ideal if we could make another breaking change to the format, so instead of
"targets": {
"alias" : { },
"alias/rid": { }
}we could instead have
"targets": {
"alias": {
"": { },
"rid": { }
}
}But I suspect this might be a lot harder to implement.
However, as is pointed out just below, the target alias is used as the directory name for the obj and bin directories, and / is a directory separator, so I think that's another reason we could just block / from the alias
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.
Yeah, I'd be fine with blocking that yeah.
Honestly, I can't image this to be a super critical scenario that would need to be addressed.
The more changes we make, the higher the risk of the change anyways.
accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md
Outdated
Show resolved
Hide resolved
Fixes # ### Context Design: NuGet/Home#12124 To allow duplicate frameworks in aliasing, the project reference protocol nearest framework selection needs to be updated to support matching by alias as well. Relevant part: https://github.com/NuGet/Home/blob/dev-nkolev92-tfmaliases/accepted/2025/Multiple-Equivalent-Framework-Support-TFM-As-Aliases.md#project-to-project-references NuGet/NuGet.Client#7011 NuGet.Client side adding the parameter. NuGet/NuGet.Client#6972 will add the full implementation at a later point. ### Changes Made - Pass CurrentProjectTargetFrameworkProperty if GetReferenceNearestTargetFrameworkTaskSupportsTargetFrameworKPropertyParameter is set. - If GetReferenceNearestTargetFrameworkTaskSupportsTargetFrameworKPropertyParameter is not set, but GetReferenceNearestTargetFrameworkTaskSupportsTargetPlatformParameter is set, call the old variation. - Otherwise calls the last variation. ### Testing - Manual testing. - I'd be happy to add tests if someone can point me in the right direction. ### Notes The idea here is to get ahead of things. Currently aliasing work can't be end to end tested because it requires an msbuild change. It makes it really hard to validate the NuGet changes are enough and good, but this is the only change needed on the msbuild side. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
donnie-msft
left a comment
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 had a couple questions, and left a few nits.
Suggest having Copilot review spelling/etc and also telling it to put each sentence on a new line in the markdown, as I know Andy prefers that.
| - Disabling pack requires setting three properties. Should we aim to reduce this number? | ||
| - Are there any concerns regarding the changes to the [ProjectReference](#project-to-project-references) protocol? | ||
| - Should the alias matching require the frameworks to be fully equivalent? My instinct is no, since we'd potentially like to allow the test projects to have a newer framework than the libraries. | ||
| - Should target alias based matching be consider when applying AssetTargetFallback 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.
| - Should target alias based matching be consider when applying AssetTargetFallback as well? | |
| - Should target alias based matching be considered when applying AssetTargetFallback as well? |
| - Are there any concerns regarding the changes to the [ProjectReference](#project-to-project-references) protocol? | ||
| - Should the alias matching require the frameworks to be fully equivalent? My instinct is no, since we'd potentially like to allow the test projects to have a newer framework than the libraries. | ||
| - Should target alias based matching be consider when applying AssetTargetFallback as well? | ||
| Example: P1 targets net10.0 with alias apple, P2 targets net472 (apple) and net472 (banana). Should the matching allow net10.0 to match net472 (apple) or should it fail due to ambiguity? |
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.
nit
| Example: P1 targets net10.0 with alias apple, P2 targets net472 (apple) and net472 (banana). Should the matching allow net10.0 to match net472 (apple) or should it fail due to ambiguity? | |
| Example: P1 targets net10.0 with alias apple, P2 targets net472 (apple) and net472 (banana). | |
| Should the matching allow net10.0 to match net472 (apple) or should it fail due to ambiguity? |
| Since the `TargetFramework` value is used by the .NET SDK as the directory name for build output, should we block invalid characters on Windows file systems? (Linux doesn't prevent any characters, with the possible exception of `/`, since that's used as the directory separator). | ||
|
|
||
| Note that in the current iteration, something like `banana/3` is allowed as an alias and it seems to work. | ||
| Adding an error here would be a potential breaking change. It is very unlikely to affect people, but something that would probably need to be documented. |
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.
nit
| Adding an error here would be a potential breaking change. It is very unlikely to affect people, but something that would probably need to be documented. | |
| Adding an error here would be a potential breaking change. | |
| It is very unlikely to affect people, but something that would probably need to be documented. |
| ### Lock file changes | ||
|
|
||
| NuGet's "repeatable build" feature adds a package lock file to the project directory. | ||
| The restore has a lock file has a similar schema to the assets file, so that schema would also need to be amended. |
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.
| The restore has a lock file has a similar schema to the assets file, so that schema would also need to be amended. | |
| The restore lock file has a similar schema to the assets file, so that schema would also need to be amended. |
|
|
||
| NuGet's "repeatable build" feature adds a package lock file to the project directory. | ||
| The restore has a lock file has a similar schema to the assets file, so that schema would also need to be amended. | ||
| Fortunately when Central Package Management and its transitive pinning was introduced we introduced the concept of a PackagesLockFile version successfully. |
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.
nit
| Fortunately when Central Package Management and its transitive pinning was introduced we introduced the concept of a PackagesLockFile version successfully. | |
| Fortunately, when Central Package Management and its transitive pinning was introduced, we introduced the concept of a PackagesLockFile version successfully. |
| Non-SDK style project only have a single target, so those project types won't see a change. | ||
|
|
||
| For simplicity of implementation, whenever SDKAnalysisLevel is set to 10.0.300 or more, NuGet will use the V4 assets file. | ||
| Whenever the SDKAnalysisLevel is set to a lower version, then NuGet will use the V3 assets file. |
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.
And this ages out after 3 major releases, based on how SDKAnalysisLevel works, right?
In other words, there's ample time (years?) for a customer to move a solution to version 4.
|
|
||
| Take a project using `<TargetFramework>production</TargetFramework>`, `<TargetFrameworkMoniker>.NETCoreApp,Version=v8.0</TargetFrameworkMoniker>`, and `<RuntimeIdentifiers>linux-x64</RuntimeIdentifiers>`. | ||
|
|
||
| Note that the effective framework itself will not be part of the serialized part, but it'll cleaned up by the reader by looking up the target framework based off of the "project" section of the assets file. |
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.
| Note that the effective framework itself will not be part of the serialized part, but it'll cleaned up by the reader by looking up the target framework based off of the "project" section of the assets file. | |
| Note that the effective framework itself will not be part of the serialized part, but it'll be cleaned up by the reader by looking up the target framework based off of the "project" section of the assets file. |
|
|
||
| The following 2 changes will be made on the writer side: | ||
|
|
||
| - Add "framework" to the packageSpec, while keeping targetAlias for simplicity sake. |
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 a reader not as familiar with targetAlias, I'm not understanding how this is simple. Why would I use targetAlias and framework?
| ```diff | ||
| "frameworks": { | ||
| - "net8.0": { | ||
| - "targetAlias": "production", |
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.
Is there a scenario where targetAlias can be selecting 1 of multiple aliases? Let's say I have "production" and "staging" and "development", can I then set targetAlias to any of those three?
|
|
||
| Given that there is no version for the package spec at this point, we can do a simple trick to infer the type of PackageSpec to read. | ||
|
|
||
| - When reading a framework, if both targetAlias and framework, then this is equivalent to V4 and a .NET SDK scenario |
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.
Could this be simplified from the textual scenarios into a small matrix of scenarios?
Design for #5154
Rendered
cc @dsplaisted