Monday, August 03, 2020

Fixing a really common misunderstanding about nuget.exe

It turns out that a lot of people commit a copy of nuget.exe into their code repositories.
Some of them used to be mine. Not anymore.

screenshot showing the number of copies of nuget.exe found when searchiGitHubng

tldr: don't include a copy of nuget.exe in your repository. Instead, add a reference to Nuget.CommandLine and use the copy of the exe the package provides.

It's rare to think about how NuGet works. You can just add the packages to your project, they get downloaded, referenced and everything just works.

But there are some things you might do with NuGet where you can't rely on MSBuild (or similar) to take care of things for you.

You may have to call `nuget.exe` directly.
I've had to do this many times and when doing so it's raised a tricky question.
"Where is nuget.exe located?"
Across all development machines and build/CI servers, there's no single answer.
You can't rely on it being in a particular place. unless you put it there.

So, how do you put it in a specific place?
I've never found any documentation to explain this and so put it in the repository with the code/scripts/whatever that needed it.

It never felt like the right thing to do but I didn't know any better and it seemed to work ok.
As we saw above, I'm far from the only person to have done this.
The only time this became a problem was when I needed to change something that called nuget.exe and needed a feature that was added in a newer version than the one I had checked in. Not a big deal but another reminder that this isn't the best way to do things.

A couple of weeks ago I stumbled across the NuGet.CommandLine package. Again, documentation of this package wasn't something I could find but the name had me wondering. "Could this be the way to perform the command-line NuGet operations I've always wanted?"

Some investigation was needed.

I started by downloading the package and looking inside.

Nuget Package Explorer showing nuget.exe in the tools directory of the package

Bingo! That looks exactly like what I need.

Now, how to reference it?

Fortunately, this is where some documentation did come in handy.

By adding `GeneratePackagePath="true"` to the PackageReference element I could have a way to get access to the version of the executable from the package.

partial view of the project file showing the PackageReference entry with the GeneratePropectPath property set

Now to use it.

By adding this property a new build parameter is created. It has the same name as the package but with two differences. Firstly it's refixed with "Pkg" and secondly, is has non-alphanumeric characters replaced with underscores. so, in this instance, the parameter is called `PkgNuGet_CommandLine`.

With this all set, I could now reference the version of nuget.exe that was downloaded as part of the package by specifying `$(PkgNuGet_CommandLine)\tools\nuget.exe`. As an example, see this targets file, which I use to automatically pack and sign release builds of packages.

That was it. Simple really, but poorly documented. I was surprised how easy it was to fix and why I've never seen anyone mention this before. Maybe other people do talk about this. Maybe other people know this already. That the package has sooooo many downloads makes me suspect that many people do already know this. But the number of repositories containing this file on GitHub also makes me certain I'm not the last person to learn about this.
If you're in the position I was, I encourage you to make the switch to using the package reference instead. Not only will you save a bit of space in the repository but, more importantly, you'll be able to learn when newer versions of the exe become available when a new version of the package becomes available.


I originally investigated the above while streaming on Twitch.  I like to stream there while investigating or researching topics as it forces me to articulate what I'm thinking, doing, and looking for, without getting distracted. Hopefully, it serves as an interesting way for others to learn what I'm learning. Follow me on Twitch to learn when I next do things like this and we can all learn together.


Post a Comment

I get a lot of comment spam :( - moderation may take a while.