project-system icon indicating copy to clipboard operation
project-system copied to clipboard

There is no way to query PackageReferences in a project

Open gardnerjr opened this issue 8 years ago • 20 comments

There are API's to Add or Remove a PackageReference, but there is currently no way to ask if a package reference exists in a project, and if so, what version is it. There's also no way to just enumerate all existing package references.

So you can't positively know if a package is referenced in a project until you have successfully restored packages in a project, at which time existing NuGet related package services will have installed version information and let you enumerate installed packages.

gardnerjr avatar Dec 14 '16 19:12 gardnerjr

Are you looking for a general API that works with any form of nuget packaging style? As in the same API will work for packages.config, project.json, and .csproj PackageReference? Or are you okay with a special case check for the new PackageReference? And also does this have to work outside of VS?

If you are okay with a special case for this and only running inside VS then there is multiple ways to see what PackageReferences exist. Since it is just an MSBuild item you can get a hold of the msbuild project and ask it for all PackageReference items. Or you can get the Dependency tree and find all nuget packages in it.

jviau avatar Dec 16 '16 00:12 jviau

I don't think falling back to MSBuild is the right solution here - design-time builds could supplement (or even remove) these things, so just using evaluation will give misleading results.

@jviau What do we do for references here? I think asking consumers of the project system to fall back to MSBuild or listen to the project subscription is too hard and easy to get wrong.

We should have friendly facades over these concepts, a la DTE's Project.References.

davkean avatar Dec 16 '16 04:12 davkean

it would be nice to have one common thing that tells what the references are whether they are installed or not, without knowing about msbuild or walking build trees/etc, what kind of project it is, etc. It's strange that some kinds of csproj projects give you one answer when calling nuget packages whether installed/restored or not, and another kind of csproj gives you different answers depending on if the user has ever built/restored or not.

because our tooling is specifically built to install some nuget packages and configure a project if they aren't there, we're in this limbo state where until a user builds, we don't know for sure without doing all these kinds of workarounds.

Given that we're a VS Extension, the code only needs to work inside VS. If it has to be a new thing and we have to ask the existing nuget apis AND new ones for package references, fine. but it's really strange right now that there's not even api to ask what package references are supposed to be in this project.

gardnerjr avatar Jan 03 '17 18:01 gardnerjr

aside: @jviau can you give me details about your "get a hold of the msbuild project and ask it for package reference items" workaround? we need do to something until there's a better way.

gardnerjr avatar Jan 03 '17 18:01 gardnerjr

@davkean CPS does have support for VSLangProj.References and other types through our OAVS* classes. I did some investigation and found that the new Dependencies tree is not working with our implementation. I will keep looking into it and see where the fix should go.

@gardnerjr the MSBuild way will only tell you what packages should be there, but not what is restored or not, so it may not be sufficient. Considering that I just found some issues with our references DTE layer we may be able to fix that instead of needing a workaround.

jviau avatar Jan 03 '17 20:01 jviau

@jviau knowing what packages should be there is all we actually need to know. if it should be there, then our tool would show "configure" options, if it isn't found as "should | installed" then we'd show our "add" menu items/etc. given the time left in RC3 is very short, even that kind of workaround is good enough for us for now.

gardnerjr avatar Jan 03 '17 20:01 gardnerjr

@gardnerjr this document subscribe_to_project_data is probably the best option for you. You will want to subscribe to "PackageReference". And here is how you obtain the UnconfiguredProject the example uses: finding_CPS_in_a_VS_Project

jviau avatar Jan 04 '17 21:01 jviau

@jviau I pinged Andrew/Lifeng on this offline but I think asking consumers to listen to the project subscription data is the wrong approach, it requires him to understand:

  • The msbuild representation of what makes up a package reference both at evaluation and design-time and make sure I agree with all the other services (language service, dependency node, VSLangProj.Referenes, etc). For example, we currently only use evaluation to figure out package references - but we're going to be moving to a design-time build based calculation.
  • How metadata values from the evalation/design-time results are interpreted, and make sure that he interprets them the same way that everyone else does
  • Snapshots and snapshot versions, and figuring out how to coordinate between evaluation and design-time versions
  • Making sure the tree is up-to-date (so that any answers I give match the answers it gives) and dealing the fallout when the active config changes under the covers while I’m waiting on this

davkean avatar Jan 04 '17 23:01 davkean

@davkean yes I agree, but @gardnerjr wanted a workaround for the time being. @abpiskunov and I are working on getting VSLangProj.References working again with the dependency tree. We are also considering including support for PackageReference in this work as well, but it will need some design.

jviau avatar Jan 04 '17 23:01 jviau

Yes, i just need a workaround. Is there any way to do this without all the subscriptions? i need a "what are the packagereferences right now" type check for some BeforeQueryStatus VSCT calls. I don't need (or really want) to watch ongoing changes while the user is doing things.

gardnerjr avatar Jan 04 '17 23:01 gardnerjr

FYI: we were discussing supporting VSLangProj.References with @jviau and are making corresponding changes in Managed project system and CPS. It should work soon hopefully ..

abpiskunov avatar Jan 05 '17 22:01 abpiskunov

What will packages show up as? Or are we adding new API to support this?

davkean avatar Jan 05 '17 23:01 davkean

in the UI nothing changes for users. After my change in managed project system, without CPS changes VSLangProj.References would only show usual references (assemblies, projects etc). If CPS changes would be done , then we could also include packages to references and have a new reference type "package" ...

abpiskunov avatar Jan 05 '17 23:01 abpiskunov

yeah, I'm talking about VSLangProj APIs.

davkean avatar Jan 05 '17 23:01 davkean

The way it implemented in CPS now, to support VSLangProj.References they look in the tree nodes and check nodes with Reference flag. Then the match them to rules from DT build . I did not support Refernce flag for Dependency nodes, and adding this support right now (review will be soon). This will bring support for regular references. However CPS currently has hardcoded list of rules that thay try to map to VSLangProj.Refernces and it does not include PackageDependency rules, thus until it is supported package would not appear in VSLangProj.References... Thats what Jacob is looking at .

abpiskunov avatar Jan 05 '17 23:01 abpiskunov

Do we know if this is going to make RTM at this point?

gardnerjr avatar Jan 13 '17 19:01 gardnerjr

For official support we need to consider how a PackageReference falls into the VSLangProj.Reference interface, or is there a new interface we need to implement for them?

@gardnerjr for now there is a messy way to find all PackageReferences. They are on the DTE tree in the following way: Dependencies -> NuGet -> {PackageReferences}. You can walk the DTE tree to the NuGet node and then all children are package references. The best way to find the Dependencies tree is to find the node where DTE.ProjectItem.Object is VSLangProj.References is true. From there you can walks its children (on the DTE.ProjectItem layer!, not the VSLangProj layer) to find the node with a caption of "NuGet" and then all children are package references.

This is a very implementation specific work around, and I hope we can come up with a better solution in the future.

jviau avatar Jan 14 '17 01:01 jviau

Related: this appears to have been "fixed" in nuget recently, though:

https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/PackageManagement.VisualStudio/ProjectSystems/CpsPackageReferenceProject.cs#L174

that means the IPackageInstallerServices.IsPackageInstalled calls there will return true if there are PackageReferences for a package. this "fixes" this issue for me, personally, as that method was returning false in prior versions (like for .xproj in dev14), so i needed some other check if that returned false to see if it was "supposed" to be installed.

Given those fixes were made, it is possible that nothing needs to be done here?

gardnerjr avatar Jan 18 '17 01:01 gardnerjr

How is everything going on?

stg609 avatar Apr 25 '19 05:04 stg609

@gardnerjr That file you linked to has been moved or deleted, is that fix still in place?

I have recently updated to using PackageReference with the legacy project system and IsPackageInstalled will return true even if that package is a indirect dependency of the project. Then when I attempt to update the project, it will fail because the project doesn't actually have the XML for a PackageReference to the package it claimed to have.

maxinfet avatar May 04 '19 22:05 maxinfet