Package auto-restore check-ins nuget.exe a subject to become obsolete

Topics: General
Jul 15, 2013 at 4:52 AM
Edited Jul 15, 2013 at 4:53 AM
Is there a nuget package containing nuget.exe?
Turning on package auto-restore check-in nuget.exe under source control which is a subject to become obsolete later.
So I'd like to see if it were adding a package say Nuget.AutoRestore containing nuget.exe so you could update it from time to time.
Does it make sense?
Jul 15, 2013 at 2:18 PM
I had the same problem, but the NuGet.exe comes from an http download in a code snippet in the .nuget/NuGet.targets msbuild script. At the bottom of the script is the "DownloadNuGet" task which has http://nuget.org/nuget.exe hardcoded in it. This is where the NuGet.exe update comes from.

Right away I didn't want users checking in NuGet.exe's all over my Perforce depots. We have over a hundred active Solution files. So I immediately asked the users to modify the NuGet.targets script and in the PropertyGroup at the top of the script, change the default value of DownloadNuGetExe from 'false' to 'true'. I already had checking ....exe and ....dll blocked except in a common location to prevent a scattering of binaries in my repository, so the NuGet.exe SCM add was already blocked.
        <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' != 'false' ">true</DownloadNuGetExe>
But this left me extremely vulnerable to NuGet.exe versions rolling, as I grab a new NuGet.exe everytime the build is cleaned and re-built! Plus I run my own NuGet feed as we use NuGet to deliver common libraries among the groups.

So how did I fix this? First you need your own NuGet Feed and that private feed needs to be configured as a source BEFORE you set up auto-restore (before you add the .nuget Solution folder). (You can refresh the auto-restore feature in a Solution by first deleting the .nuget Solution folder, and then the .nuget FileSystem folder. The option to setup the Solution for auto-restore will then re-appear.)

A simple private Feed can be created by sharing a UNC path and dropping files in it, but creating your own server is super-simple and outlined in the Docs on the nuget.org website. Newer NuGet will treat even a local folder as a feed, nice for testing your packages and how they are delivered.

When you configure a Solution for auto-restore, two packages are silently installed, NuGet.Build (delivers NuGet.targets) and NuGet.CommandLine (delivers NuGet.Config and NuGet.exe, but does not contain NuGet.exe, it is grabbed from that URI above, I assume.). Using NuGet Package Explorer (download-able from http://nuget.org), I grabbed NuGet.Build from the public feed.

In the Package contents window, open 'tools' and right-click NuGet.targets and choose Edit. Modify and save NuGet.targets with the changes, in this case, the location of the NuGet.exe URI and any other changes you might like this to do differently. (You might even change the entire mechanism for getting the NuGet.exe. You can even change it to a local UNC download as it's just a C# code snippet in msbuild syntax.) Save this change by clicking the disk icon in the tool bar and then click the back arrow right next to it to return to the original view.

Now comes the trick. If two packages of the same name are available on two different available feeds, NuGet will pick the one with the highest version, so I append an absurdly high version number to my NuGet.Build package. As long as my local feed is added to the client-side as an available source, my absurdly high version is always picked, even if the public server rolls a new version.

I chose a 4 digit number as it is one of our popular company acronyms spelled out on a phone keypad. So let's say it's 1234. When NuGet 2.6.1 releases, my modified version becomes 1234.2.6.1, so it is ALWAYS higher but keeps the original version number so I know what I've modified from. As long as my private feed is available, it will be picked, even if something absurd happens like NuGet jumps to version 5.1.2 as their next release. 1234.2.6.1 is still higher. Then, when I am ready for new packages to publish, I can choose when to create 1234.5.1.2 as the next release and let it become the newest version.

Now we have to save this package to your private feed with a new version. First, click EDIT in the menu bar and choose 'Edit Metadata'. Now change Version to our new version. (I suggest keeping the original version part, say '2.6.1' so you know what you sourced your private change from, and just add an absurdly large major revision number.) Click the green check to save the version.

Next, click FILE and then 'Publish...'. This will automatically read our new version from the metadata and ask for a publish URL. Give it your private feed and the apikey if you've set one. Once this is published, just make sure all of your NuGet users set your private Feed as an available source BEFORE they set their solutions for auto-restore. Deleting the .nuget folder from both the Solution Explorer and the File Explorer is the only way I know of reverting Solutions that are already configured for auto-restore. Note you'll have to instruct users (or use automation) to update any futher changes you make or when you roll a new version.

Setting your private feed can be done through Tools->Options->Package Manager->Package Sources in Visual Studio, or by directly editing %APPDATA%\NuGet\NuGet.config.

So that takes care of delivering the NuGet.targets file with the new location to grab the NuGet.exe from. Now all you have to do is manage this new location, dropping new exe's as you're ready for your users to grab them. I wouldn't even bother checking them into source control, but that's up to you.
Coordinator
Jul 15, 2013 at 10:59 PM
Thanks for covering this so thoroughly, @CopperTopp!!