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

Handle when same name and same version both project and package are referenced in solution #3789

Merged
merged 14 commits into from
Jul 7, 2021

Conversation

erdembayar
Copy link
Contributor

@erdembayar erdembayar commented Dec 8, 2020

Bug

Fixes: Issue#6795
Regression: No

  • Last working version:
  • How are we preventing it in future:

Fix

Details: The problem occurs project and package with same name and same version referenced directly and transitively to project. Let's call them "DoublyReferenced" for both project and package and with version is "1.0.0"

   Source  - - - - - ProjectInterMed -> Package(DoublyReferenced) V1.00 (transitive ref)
             \
               \    
                 \ - Project(DoublyReferenced) V1.00 (direct ref)

Then it fails with vague error "" in VS:

image

Even on cli with dotnet.exe it fails with another vague error, actually it's telling duplicate same name keys are created and we have conflict.
image

Currently below scenario works, after examination it actual doesn't create key duplicate key as our case, only one key for project created due to project over package preference. It looks very similar to our case in question but actually it's not.

   Source  - - - - - -> Package(DoublyReferenced) V1.00 (direct ref)
             \
               \    
                 \ - Project(DoublyReferenced) V1.00 (direct ref, winner)

Even it works it cause squiggly yellow warning with Roslyn.
image

There're only 2 solutions to this problem.

  1. Try to solve issue by choosing one over other (package vs project). Since we already have project over package preference I currently implemented this approach in my code.
    Still this one have issues:
    a. Above Roslyn warning keep continue to show up with or without this fix until we remove one of them.

image

b. Project reference always winner, it's implicit to user and maybe it's not user actually wanted, maybe yes. All different combinations of direct and transient references works except below 1 case.
c. If package direct reference and project is transitive reference then VS doesn't even compile
image

image

  1. Show explicit warning/error and let user know there are both project and package with same name/version referenced so user can take action. Since main complain of customers was message was too implicit/vague this will definitely solve the pain point.
    Maybe this one is most clean and confusion free solution. I can change to implementation, please just give me your feedback.
    Also in this case do we need to introduce new warning NUxxxx code?

Testing/Validation

Tests Added: Yes
Reason for not adding tests:
Validation:

@ericsampson
Copy link

This would be great to have a better error message/handling of this, I just hit it and it took me a while to figure out what was going on. Cheers!

@erdembayar erdembayar added this to the Sprint 181 - 2020.12.21 milestone Jan 4, 2021
@erdembayar erdembayar force-pushed the dev-eryondon-samekey-already-added branch from f00e077 to 4ded836 Compare February 3, 2021 00:49
@erdembayar
Copy link
Contributor Author

@NuGet/nuget-client
Do we need to show warning message to user that we picked up project over package in this case instead of doing it silently?

Also I investigated issue#10368 related this but it requires design change, and ROI is very small since it's just uncommon edge case. So want to keep fix as it's. I'm working on adding unit test.

@nkolev92
Copy link
Member

nkolev92 commented Feb 4, 2021

Do we need to show warning message to user that we picked up project over package in this case instead of doing it silently?

Imo, not as part of this change. That's not something we want to introduce at this point as no one is really asking for it.

@erdembayar erdembayar marked this pull request as ready for review February 5, 2021 01:16
@erdembayar
Copy link
Contributor Author

@NuGet/nuget-client
Ready for review, please review.

@erdembayar erdembayar force-pushed the dev-eryondon-samekey-already-added branch from 2d25ac1 to 6376f86 Compare February 5, 2021 01:26
@nkolev92
Copy link
Member

nkolev92 commented Feb 5, 2021

@erdembayar

Can you please:

  • Fix the title to indicate what the change is, not Fix {issue title}.
  • Add a more detailed description about your changes. What will the experience be like now and why you made that decision.

@erdembayar erdembayar changed the title Fix same key added exception when project graph has projectName == packageRef name (of same version) Not fail when same name and same version both project and package are referenced in solution Feb 5, 2021
@erdembayar erdembayar changed the title Not fail when same name and same version both project and package are referenced in solution Handle when same name and same version both project and package are referenced in solution Feb 5, 2021
@erdembayar erdembayar marked this pull request as draft February 5, 2021 17:42
@erdembayar erdembayar marked this pull request as ready for review February 5, 2021 18:29
@erdembayar
Copy link
Contributor Author

erdembayar commented Feb 5, 2021

@erdembayar

Can you please:

  • Fix the title to indicate what the change is, not Fix {issue title}.
  • Add a more detailed description about your changes. What will the experience be like now and why you made that decision.

Can you check now? Now I more toward to show warning/error direction instead of solve problem by choose one over other (project vs package). By showing clear warning/error we make user take a action to solve problem for good.
Initial assumption of this is just bug was below direct referencing scenario works. But it's not really working (Roslyn warning) and bit different problem:

   Source  - - - - - -> Package(DoublyReferenced) V1.00 (direct ref)
             \
               \    
                 \ - Project(DoublyReferenced) V1.00 (direct ref, winner)

@nkolev92
Copy link
Member

nkolev92 commented Feb 5, 2021

By showing clear warning/error we make user take a action to solve problem for good.

Project was preferred over Package, but not in all scenarios.

Fixing this bug just establishes the already known expectation.
Adding more visibility to projects being preferred over packages is something that's lateral to the current problem.

@erdembayar
Copy link
Contributor Author

erdembayar commented Feb 5, 2021

By showing clear warning/error we make user take a action to solve problem for good.

Project was preferred over Package, but not in all scenarios.

Fixing this bug just establishes the already known expectation.
Adding more visibility to projects being preferred over packages is something that's lateral to the current problem.

Can you recommend next course of action? Is my current fix I submitted ok for bug fix? Do I need to change anything?

@nkolev92
Copy link
Member

nkolev92 commented Feb 5, 2021

I think the first idea of continuing to choosing project over package is more appropriate. Especially because that matches current behavior.

I'll review the code later.

@erdembayar
Copy link
Contributor Author

I think the first idea of continuing to choosing project over package is more appropriate. Especially because that matches current behavior.

I'll review the code later.

@nkolev92
Please review when you have time.

@nkolev92
Copy link
Member

@erdembayar Sorry, this slipped through my fingers last week. I've added it to my queue.

@nkolev92
Copy link
Member

@erdembayar

Reviewing your description, I think proposal 1 makes sense.

a. We should file an issue for that. Start it in our repo. The fix might actually end up being on project-system side, but it's NUGet scenario.
b. I think this is similar to a. Personally given that projects have always been preferred, I'd keep it as is for now, just focus on fixing the bug. Adding a warning, if any, can be a different task.
c. That's a very nice catch. However, if you add PackageVersion in the DoubleReferencedTarget project, the bug you are fixing doesn't exist and the behavior is the same. We should file an issue on the dotnet/sdk side for this scenario.

It sounds to me like this is what you implemented, so I'll review the code.

var first = item.First();
var second = item.Last();

if (first.Type == second.Type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this happen?

Copy link
Contributor Author

@erdembayar erdembayar Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I tried to be more cautious, now removing.

Copy link
Contributor Author

@erdembayar erdembayar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkolev92
Thank you for your review.
I addressed your PR comments, please check.

var first = item.First();
var second = item.Last();

if (first.Type == second.Type)
Copy link
Contributor Author

@erdembayar erdembayar Feb 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I tried to be more cautious, now removing.

@erdembayar
Copy link
Contributor Author

@nkolev92
Can you review again please?

@erdembayar erdembayar force-pushed the dev-eryondon-samekey-already-added branch 2 times, most recently from 7aca23e to c6b33b9 Compare March 23, 2021 16:53
@erdembayar erdembayar force-pushed the dev-eryondon-samekey-already-added branch from c6b33b9 to ff603ef Compare March 26, 2021 01:23
@erdembayar erdembayar force-pushed the dev-eryondon-samekey-already-added branch from a2e1dec to 68b2f07 Compare March 28, 2021 19:43
@erdembayar erdembayar marked this pull request as draft April 21, 2021 22:44
@ghost ghost added the Status:No recent activity PRs that have not had any recent activity and will be closed if the label is not removed label Jun 13, 2021
@ghost
Copy link

ghost commented Jun 13, 2021

This PR has been automatically marked as stale because it has no activity for 7 days. It will be closed if no further activity occurs within another 7 days of this comment. If it is closed, you may reopen it anytime when you're ready again, as long as you don't delete the branch.

@ghost ghost closed this Jun 20, 2021
@ericsampson
Copy link

uhh this probably shouldn't be auto closed, lol

@ghost ghost removed the Status:No recent activity PRs that have not had any recent activity and will be closed if the label is not removed label Jun 20, 2021
@erdembayar erdembayar reopened this Jun 28, 2021
@erdembayar
Copy link
Contributor Author

erdembayar commented Jun 29, 2021

@nkolev92
Here is dotnetbenchmark result. I don't see much difference in both run time duration and memory allocation for before and after my change. Actually it performs bit better on edge case we're interested in.

Code used for benchmarking is here.

  1. Without any change.

[Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
DefaultJob : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT

Method Mean Error StdDev Rank Gen 0 Gen 1 Gen 2 Allocated
Test0:Normal 488.6 us 3.69 us 3.45 us 1 41.9922 10.2539 - 259 KB
  1. With my PR changes. Below DuplicateId is edge case which we're interested in.

.NET SDK=6.0.100-preview.5.21302.13
[Host] : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT
DefaultJob : .NET 5.0.7 (5.0.721.25508), X64 RyuJIT

Method Mean Error StdDev Ratio RatioSD Rank Gen 0 Gen 1 Gen 2 Allocated
Test0:DuplicateId 336.6 us 2.46 us 2.05 us 1.00 0.00 1 28.8086 8.3008 - 179 KB
Test0:Normal 487.1 us 4.45 us 4.16 us 1.45 0.02 2 41.9922 10.2539 - 259 KB

@erdembayar erdembayar marked this pull request as ready for review June 29, 2021 04:01
@@ -283,6 +285,79 @@ public class LockFileBuilder
return lockFile;
}

private void ValidateLockFileLibrary(IList<LockFileLibrary> libraries)
{
var libNameVersion = libraries.Select(l => l.Name + " " + l.Version);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be at all simpler to just create a dictionary, and iterate over the libs one by one and updating the selected ref as we go?

Currently

All of that can be replaced with 1 dictionary and 1 loop.
The moment you find a conflict, rank references and dedup.

Same applies to both methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkolev92
Could you be able to check now? I pushed new changes.

Copy link
Member

@nkolev92 nkolev92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small question.

Copy link
Member

@nkolev92 nkolev92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job!
👏

@erdembayar erdembayar merged commit 65e9d80 into dev Jul 7, 2021
@erdembayar erdembayar deleted the dev-eryondon-samekey-already-added branch July 7, 2021 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants