Install NuGet packages to Project Dirs instead of Solution Dir? - visual-studio

I have a solution in Visual Studio 2015 with about 40 projects in it. Some of these projects have some NuGet packages referenced.
Due to a combination of our branching strategy (where each project folder is branched individually) and our security requirements (that the NuGet binaries are actually checked into TFS) I would like the NuGet packages for each Project to be installed into each Project's folder, not in the solution's folder. Space usage is not a concern here.
I've looked at:
https://docs.nuget.org/consume/nuget-config-file
https://docs.nuget.org/Release-Notes/NuGet-2.1#Specify-packages-Folder-Location
And they've helped my understanding of how the config files work... but I can't seem to get it to do what I want.
I've tried this in my config file:
<configuration>
<config>
<add key="repositoryPath" value="$(ProjectDir)\Nuget\" />
</config>
</configuration>
But it creates a folder in the solution folder actually called '$(ProjectDir)'.
And I can't hardcode the path to the project folders (i.e. 'C:\myteam\teampackages' in the NuGet docs) as pretty much everyone in the team have different paths to their local workspaces!
How can I do this?

Firstly, you should not check in NuGet packages into TFS Version Control. As one of the advantages of using NuGet is that you can use it to avoid checking in binaries to your version control system.
Instead, you need to restore NuGet packages during TFS build process and the required packages will be downloaded. In VS2015, you need to follow steps in this blog: https://docs.nuget.org/consume/package-restore/team-build).
Some key steps are (assume you're working with XAML build):
Add following items to the solution. (Content of the nuget.config and .tfignore file can be found here)
Add one build.proj file under the root path of the solution folder. (Content of the build.proj file can be found here)
Create one folder named tools under the root path of the solution folder. Create NuGet sub-folder under tools folder, download and save nuget.exe under tools\NuGet path.
Check in nuget.config, .tfignore, build.proj and tools\NuGet\nuget.exe into TFS version control.
Modify the build definition to choose to build the build.proj file.
Then you will have NuGet packages restored successfully during the TFS build process.

The Nuget docs mentions specifying package folder location is to have many different solutions share the same package. This is an opposite scenario as your. Repository path setting only allows you to install the NuGet packages in the specified folder (like C:\teampackages ) or for relative path (like ../Nuget).
To make installing package in different repositoryPath, you can try:
<configuration>
<config>
<add key="repositoryPath" value="../Nuget" />
</config>
</configuration>
Check case: Is it possible to change the location of packages for NuGet?

Related

MSBuild Macro for NuGet package directory

I'm working on a NuGet package that adds a step to the build process by using a .targets file.
I need to reference other files from my NuGet package in order to complete the build successfully.
In the past, I've used $(SolutionDir)packages\MyPackage and all has worked fine.
However, I was just playing around with the VS 2017 RC, and I noticed that my package was installed in the global NuGet package directory, not in the solution folder.
Is there some macro that I can use from MSBuild, that contains the path for the NuGet packages folder? It is a requirement that I maintain compatibility with VS2012.
The $(NuGetPackageRoot) macro points to the package root.
You can use an alternative method that create a NuGet.Config file in the root of the \Solutions\ folder to set the package repositoryPath of VS 2017 RC, add to NuGet.Config the following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="$\..\Packages" />
</config>
</configuration>
For the repositoryPath setting, you can specify an absolute path or relative path (recommended) using the $ token. The $ token is based on where the NuGet.Config is located. In this case, you package will install in $(SolutionDir)packages\ folder, you can used $(SolutionDir)packages\MyPackage for Visual Studio 2017 RC. It`s also maintain compatibility with VS2012.

Making nuget work when its referenced in multiple solutions or by itself?

We have the following project structure in a solution:
.\Project2
.\Project1
Project2 is dependent on Project1. Project1 is shared across multiple projects. I added the nuget packages (Roslyn for example) for Project1 when it was part of this solution. The problem we are having if either we try to compile Project1 by itself or compile it when its in an entirely another app it fails:
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ../../Project2/packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props.
If i open the project file in a text editor it has the following statments in the project file:
<Import Project="..\..\Project2\packages\Microsoft.Net.Compilers.1.2.2\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\Secured Account Access\Member\packages\Microsoft.Net.Compilers.1.2.2\build\Microsoft.Net.Compilers.props')" />
If of course removed all the nuget references and then just opened the individual project and added the nuget references. Which fixed when i was trying to compile the project by itself and broke it when it was part of the solution because VS will no longer restore the packages for Project1 while its in the solution.
I'm not sure why VS/Nuget works this way. Why not always have a package folder for each project? Disk Space savings (which would be absolutely nothing)? You should never have references that look like the following:
../../Project2/Packages/MyNugetDepedency.dll
Is there any way to get around this and have everything just work.
The packages folder is determined by the solution the project is contained in by default. You can override the default packages directory by specifying the repositoryPath in a NuGet.Config file.
<configuration>
<config>
<add key="repositoryPath" value="../MyPackages" />
</config>
</configuration>
To have multiple solutions all share the same packages directory you can create a NuGet.Config file, with a repositoryPath setting, in a directory that is a parent to all the solutions. NuGet will then work its way up each directory until it finds a NuGet.Config file and then use the repositoryPath defined there. This repositoryPath is relative to the NuGet.Config file itself, unless you have specified a full path. A relative path is probably what you want so other developers do not need to check out the source code to the same directory.

nuget creating two package folders?

OK,
So i recently reinstalled windows 10 and upgraded vs2013 -> vs2015. At this point i tried to grab a couple of nuget packages.
The problem i am having is that i have a .nuget/packages folder at the same level as my solution file (set via NuGet.config) but i also have exactly the same folder getting created in the root of my user folder.
the packages folder for my solution contains the packages installed for that solution, while the one i don't want in my user directory contains all the packages for all the projects and solutions i am working on.
Is there a way i can prevent this .nuget folder being created in my user directory? it seems useless when i already have package folders for my solutions
Thanks
You can clear the .nuget\packages directory under your user profile however the packages will be downloaded again if you install them again.
Package retrieval
%USERPROFILE%\.nuget\packages is the local machine cache used by NuGet v3 when installing NuGet packages for new project types, such as Universal Windows projects.
For a C# console project NuGet will use the %LOCALAPPDATA%\NuGet\Cache directory which is also what NuGet v2 uses.
ASP.NET Core projects currently use their own %USERPROFILE%\.dnx\packages directory for NuGet packages.
Specifying a custom NuGet package location
To prevent NuGet from copying the packages to your user profile you can create a new %NUGET_PACKAGES% environment variable pointing to the location where you want NuGet to copy the files e.g. C:\git-repositories\.nuget\packages.
To prevent NuGet from copy the packages to the solution folder too you can create a new NuGet.config file either in the solution folder or at any higher level up to the root. As content you can specify following XML.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="C:\git-repositories\.nuget\packages" />
</config>
</configuration>
As help for configuration inheritance please follow this link: NuGet Configuration Inheritance

Am I doing this right? Nuget Package Restore with centralized packages folder

I placed a nuget.config file in my project root folder that specifies where all NuGet packages should go for all my solutions.
Here is the file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="D:\Projects\Development\NuGet Packages" />
</config>
</configuration>
I have also enabled NuGet Package Restore on all my solutions.
When I first set this up, the nuget.config file was being ignored--all NuGet packages were being placed in a "packages" folder in the solution folder. I tried deleting this folder numerous times, but invariably, NuGet would recreate it and fill it with packages.
After much trial and error, I stumbled upon the <PackagesDir> element in "NuGet.targets" and noticed that commenting it out finally allowed the packages to be placed in the correct folder in my project root.
Here's the relevant line from NuGet.targets
<PackagesDir>$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
My question is simply whether commenting out the PackagesDir element in the NuGet.targets file is the intended method to get my nuget.config file to be followed or if I'm missing a more obvious solution.
There are two things in play in your question:
Where does NuGet store packages?
NuGet package restore for the open project(s) / solution
Regarding the first: setting the repositoryPath key in your nuget.config file is the correct approach to instruct NuGet to extract packages in a different folder from the default. This setting is used whenever a developer adds a package refernce to your project.
For NuGet package restore, thissetting is overridden by the setting you found in NuGet.targets. This setting is used when restoring packages upon build of a solution.
If you want to use package restore and a custom path, you indeed have to specify both. The first one for your devs, the second one for package restore.

How to configure where NuGet.exe Command Tool line looks for packages

We have successfully set up a couple of local package repositories using the NuGet.Server package and hosted them on a local IIS webserver. We are able to connect from the Package Manager and install no problem. So these are working fine.
In order for us not to have to check in our packages folder we have included the following command line in each project file that includes NuGet references. This works, if the NuGet.exe is in the path on the CI build agent.
However, I would like to move the source configuration form the command line in every project file and put it in just one place, preferably where other pesky developers can't change it ;)
<Target Name="BeforeBuild">
<Exec Command="nuget install $(ProjectDir)packages.config -s
http://domain:80/DataServices/Packages.svc/;
http://domain:81/DataServices/Packages.svc/
-o $(SolutionDir)packages" />
</Target>
Is there a better way?
Yes there is ;-)
Take a look at NuGetPowerTools. After running Install-Package NuGetPowerTools, it adds a .nuget folder to your $(SolutionDir) containing nuget.exe, nuget msbuild targets and settings (which you will need to check in).
After that, you simply run Enable-PackageRestore and it sets up msbuild targets into your visual studio project files which will make sure that packages will be fetched in a prebuild step, even on your build server, without checking in any packages. (don't forget to check in the .nuget folder though!).
This way, you simply manage the nuget package sources in a nuget msbuild settings file (in the .nuget folder) central to your solution, instead of in each project.
Cheers,
Xavier
I finally got NuGetPowerTools to install after the advice from digitaltrust on http://blog.davidebbo.com
Although NuGetPowerTools solved my problem, it was overkill for what I wanted. It requires that you check in to version control a .nuget folder that it creates in your solution root. The folder contains NuGet.exe, and a couple of target files. I don't like this as I think version control is for source code, not tools.
I came up with the following solution.
Save NuGet.exe to a folder on your local drive, both on dev and continuous integration machines. I chose C:\tools\nuget\
Add that filepath to the Path Environment Variable in all environments
On continuous integration machines, find %APPDATA%\NuGet\NuGet.Config and enter the following
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="LocalRepositoryName" value="http://Domain/DataServices/Packages.svc/" />
</packageSources>
You can add more than one entry to packageSources and NuGet will search them in the order that they appear
The after build code from my question can now be amended to the following.
<Target Name="BeforeBuild">
<Exec Command="nuget install $(ProjectDir)packages.config
-o $(SolutionDir)packages" />
</Target>
The end result of this is that whenever the approved repository location is changed, the config has to be changed in only one place rather than in every csproj file. Also, it is the continuous integration server administrators who determine that location, not the developers in their command line calls.

Resources