Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can NuGet use per-project package download paths within the same solution?

Consider this repo/file structure for our solution...

Shared Repo (Checked out to D:/Shared/trunk)
    ├───Shared1.dll Project
    └───Shared2.dll Project

App1 Repo (Checked out to C:/Code/App1/Trunk)
    ├───App1 Project (Refs Shared1.dll project)
    ├───App1.dll Project (Refs Shared1.dll and Shared2.dll projects)
    └───App1.sln

App2 Repo (Checked out to C:/Code/App2/Trunk)
    ├───App2 Project (Refs Shared1.dll project)
    ├───App2a.dll Project (Refs Shared1.dll and Shared2.dll projects)
    ├───App2b.dll Project (Refs Shared1.dll and App2a.dll projects)
    └───App2.sln

To make working with the code easier, we bring in the Shared projects directly into the application's solutions, meaning for instance if you open App1.sln, this would be your project tree...

App1.sln
    ├───Shared1.dll Project
    ├───Shared2.dll Project
    ├───App1 Project (Refs Shared1.dll project)
    └───App1.dll Project (Refs Shared1.dll and Shared2.dll projects)

As you can see, the two Shared DLLs are from a separate repository but are included in this solution. Visual Studio handles this without any issue, prompting you that you are updating multiple repos when you perform a commit against the solution. That's fine and is exactly what we want.

The issue we're having however is with NuGet. From what we understand, the NuGet.config (and the hierarchy/precedence of reading/applying them) is relative to the solution file, and therefore the projects' NuGet references are updated accordingly. This causes issues in that the references to the NuGet packages in Shared1.dll an Shared2.dll are relative to App1.sln when you're working in App1.sln, meaning if someone else is working in App2.sln and hasn't checked out their two trunks relative to each other exactly the same way you have, the references break.

Our work-around for this is to always check out all three trunks into the same folder as siblings, then put the packaging folder as another sibling, adding '../packages' in the NuGet.config next to each solution. This ensures the references never break, but forces the location of the checkouts which can be a problem.

C:/Code/
    ├───Shared Trunk
    ├───App1 Trunk
    ├───App2 Trunk
    └───packages

However, if we could specify per-project package download locations, we could put the packaging folders relative to the projects themselves meaning it wouldn't matter where you check them out to. They would always find the packages they need. Yes, this means that in our example, there would be duplicate package downloads, but space on disk isn't the issue. Maintenance of the code is.

C:/Code/
    ├───Shared Trunk
    │    └─sharedpackages
    ├───App1 Trunk
    │    └─app1packages
    └───App2 Trunk
         └─app2packages

Again, what we want is when opening App1.sln, we want packages for Shared1.dll and Shared2.dll to go in 'sharedpackages' folder but packages used by App1 and App1.dll to go in app1packages.

So... is this possible? Can you specify different NuGet package download paths per project regardless of which solution they are in?

like image 943
Mark A. Donohoe Avatar asked Nov 09 '22 13:11

Mark A. Donohoe


1 Answers

I'm in the same situation as /u/MarquelV.

From my investigation insofar into the options provided by nuget (at least up to ver. 3.5) for tackling this sort of scenario, I concluded that one has to completely ignore the graphical tools for nuget inside Visual Studio (at least as far as installing/restoring packages is concerned) and to also disable automatic package restore (Tools -> Options -> Nuget etc). Then resort to invoking nuget.exe from the command line whenever the need arises to install/restore packages specifying the folder in which the packages should be placed - this point is important because the graphical interfaces for nuget in visual studio are bend on storing packages in a "global" repository (typically right next to the .sln file of the solution).

In my projects I create an .nuget folder coupled with nuget.exe inside each and every project and reference dlls thusly.

Last but not least each and every project needs to restore packages by using nuget via the .csproj like so:

 <Target Name="BeforeBuild">
      <Exec Command=".\.nuget\nuget.exe restore  .\packages.config -PackagesDirectory .\packages"/>
 </Target>

The thing to take away from all this is that the graphical tools for nuget and the automatic package restoration (Tools -> Options -> Nuget) cannot be relied upon in order to achieve the goals described here.

like image 173
XDS Avatar answered Nov 15 '22 07:11

XDS