Addressing Package Versioning "Hell"

Current behavior (NuGet 1.2)

Sometimes, an image tells the full story. Here’s an example of the state a solution with many projects can get into. In this particular case, there’s a lot of source control churn and the intention is that every project be on the same version of any given library.

NuGetProblemVisualization

Scenarios

We need to list the various scenarios a user might run into and figure out how to address them.

  1. User has package log4net 1.0 in 10 projects and wants to update to the latest version, which is 1.2.
  2. User has package log4net 1.0 in 10 projects, but one of the projects depends on [1.0, 1.1] and the other depends on [1.0].
  3. User has package Elmah 1.0 –> log4net 1.0 which is installed in 10 projects. User wants to upgrade Elmah to 1.1 which requires log4net 1.1 and higher.
  4. User installs Elmah 1.0 -> Log4Net 1.0. Then installs RouteDebugger -> log4net 1.1 in a different project!
  5. Unit test projects are examples of projects that don't care.

Solution

Fix it!

We need to look at a few proposals. Here’s one by Rob Reynolds (ferventcoder) (RAW NOTES, Phil will clean up later)

So here's what I propose. When someone updates a package, it's solution wide. It should be updated everywhere.

  • Package folders are short named by default (no more version on folder name). Let someone have a switch to change this behavior to long name (if they want). With short name, this means during update we remove folder contents and readd.
  • We give someone a switch for long name. If someone needs two versions, have them create another solution and put it in a different folder, so it gets its own packages folder (we do this as well). Or they specify with a switch that they have a long name (versions included).
  • When someone updates a package, we look in all packages.config folders across the solution and update it there as well.

I'm thinking we walk the solution and look in the package.config files, then we apply the normal behavior to updates if we find that another project uses the same package (by name). Then we could apply all of our transitions just as before.

Short name folders will slow down the code churn on source control.

This is how I see it working.

  1. Someone calls for an update of a package (update-package foo)
  2. We walk the solution and return all of the package.config files.
  3. Look for foo by name in the configs.
  4. Note the projects that are using foo.
  5. Call the normal remove foo as before, except to all of the noted projects.
  6. Delete the short named folder.
  7. Run the normal add package that we do during update to each of the noted projects.

Then we can apply transitions and stuff as before. People will still see where dlls got added and removed to a package folder when they go to commit to source. Because we are using short names, source control in effect doesn't see that we deleted and readded a folder (because it was done in one operation between check ins). It just sees that we've made changes inside of the folder.

Note that this doesn't change the normal install-package behavior, you would still need to add it to each project. The only change here is that by default, it is also going to a short named folder.

Questions:

  • Should NuGet assume by default that an update to a package is always an update to that package in every project? Leaning towards yes.
  • If yes, how does one opt out of that behavior if they really need different versions?
  • What happens when dependency versioning won’t allow every project to upgrade to latest?

Design

Elegant

Last edited Apr 5, 2011 at 8:17 PM by Haacked, version 5