{"id":17037989,"url":"https://github.com/kzu/nuget.restore","last_synced_at":"2025-03-22T23:23:35.227Z","repository":{"id":31314176,"uuid":"34876560","full_name":"kzu/NuGet.Restore","owner":"kzu","description":"Ultimate Cross Platform NuGet Restore","archived":false,"fork":false,"pushed_at":"2017-04-24T17:49:58.000Z","size":1991,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-17T18:56:15.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kzu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-30T21:00:21.000Z","updated_at":"2022-02-06T17:43:48.000Z","dependencies_parsed_at":"2022-09-10T01:52:02.977Z","dependency_job_id":null,"html_url":"https://github.com/kzu/NuGet.Restore","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2FNuGet.Restore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2FNuGet.Restore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2FNuGet.Restore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kzu%2FNuGet.Restore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kzu","download_url":"https://codeload.github.com/kzu/NuGet.Restore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245032886,"owners_count":20550170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T08:55:39.276Z","updated_at":"2025-03-22T23:23:35.186Z","avatar_url":"https://github.com/kzu.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"![Icon](https://raw.githubusercontent.com/kzu/NuGet.Restore/master/icon.png) Ultimate Cross Platform NuGet Restore\n============\n\nThis project provides the best-practice, NuGet-team blessed, most reliable and performant way \nof performing automatic NuGet package restore across MSBuild and XBuild, without causing unnecessary \nextra restores from Visual Studio and Xamarin Studio, which handle the restore already by themselves.\n\nNow that 'Enable NuGet Package Restore' is the deprecated non-recommended way of doing package \nrestores, everyone is coming up with a different way of doing it in a way that works on build \nservers and command line builds. Here is an approach that follows NuGet's own guidance but also \nworks from command line MSBuild, build servers, Linux/Mac via Mono's xbuild and even Xamarin \nStudio. Oh, and it requires NO tuning of your build process, you just continue to build your \nsolution files as usual.\n \nThis new approach leverages the built-in support in MSBuild and XBuild for solution-level \nMSBuild imports so that restoring packages is done only ONCE for an entire solution, and it's \nNOT used when doing IDE builds.\n\n## Usage\n\n1. Download [the targets file](https://raw.githubusercontent.com/kzu/NuGet.Restore/master/NuGet.Restore.targets \"Targets file for automated restore\") \n   alongside your .sln or on an ancestor folder \n   (you can also `curl -f -k -L -o NuGet.Restore.targets http://bit.ly/nugetore` instead)\n2. Run `msbuild NuGet.Restore.targets /t:Init`: this will traverse all \n   directories from the path where you placed the targets file, looking \n   for all *.sln that don't have a correspondig `Before.[sln].targets`\n   and create one automatically, enabling command-line build automated \n   solution restore for them.\n3. You can stay up to date with changes to the target by running \n   `msbuild NuGet.Restore.targets /t:Update`. It's recommended you run \n   on first use too, since that updates the `ETag` used for subsequent \n   checks.\n\nThat's it. Now either MSBuild or XBuild command line builds of any \nsolution file in your repository will automatically perform a solution \nrestore before opening the projects and performing the build.\n\nIf you want to learn how it works in more detail, keep reading :).\n\n## Overview\n\nBack in the day, when NuGet just came out, you were supposed to just right-click on your \nsolution node in Visual Studio, and click \"Enable NuGet Package Restore\". You may be surprised \nto still find that context menu command even when the \n[latest recommendation](http://docs.nuget.org/docs/reference/package-restore \"Package Restore Documentation\") \nby the NuGet team is to NOT use it. \n\nThe new way is to just run nuget.exe restore before building the solution. And of course \nthere are a gazillion ways of doing it, from batch files, to a \n[separate MSBuild file](http://chris.eldredge.io/blog/2014/01/29/the-newer-new-nuget-package-restore/) \nthat is built instead of the main solution, to powershell scripts, etc. Oh, and you should \nprobably download nuget.exe from nuget.org too before doing the restore ;).\n\nWith the unstoppable rise of Xamarin for development (ok, maybe I'm slightly biased ;)), \nit's highly desirable that whatever solution you adopt also works on a Mac too, Xamarin Studio, \nand why not xbuild in addition to MSBuild command line builds?\n\nIt turns out that such a cross-platform solution is pretty straight-forward to implement \nand fairly simple, by just leveraging a little-known extensibility hook in MSBuild/xbuild. \n\n\n## IDE vs Command Line Builds\n\nBoth Xamarin Studio and Visual Studio build solutions differently than their command line \ncounterparts xbuild and MSBuild. Both IDEs read the solution file and construct their \nin-memory representations of the included projects. From that point on, it's the IDE that \ncontrols the build, not the command-line xbuild/msbuildn tools. \n\nBut since the solution file is not an MSBuild file, on command line builds a \n[temporary MSBuild file is created from the solution](http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx), \nand this file is built instead. And luckily, it also has some extensibility points itself \nthat we can leverage.\n\nIt's important to keep in mind though that these extensibility points are for the command \nline builds only, which is a really nice plus in this case, since both IDEs already do \ntheir own NuGet package restore automatically (and that's why the project-level MSBuild-based \npackage restore from before is no longer recommended, it's just duplicate behavior that \nbasically slows down every build).\n\n\u003e NOTE: this does not change with the new NuGet v3, since solution-level restores before \n\u003e build are still not supported out of the box.\n\nSo, part of the good news is: if you just want IDE-driven NuGet package restore, you \ndon't have to do anything at all :). But who does IDE-only builds these days anyway? \nSo let's see how we tweak the command line builds so that they work from the very same \nsolution file as the IDE, AND, without involving *any* changes to build/CI scripts that \nyou may currently have. The solution is fully unobtrusive, and at most, allows you to\n*removing* the parts of your build/CI scripts that did the solution-level restore \nmanually previously.\n\n##  Command Line Automated Package Restore\n\nThe approach is to basically have a file named Before.[solution file name].targets \n(like Before.MyApp.sln.targets) alongside the solution. As \n[explained by the awesome Sayed in his blog](http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx \"Extending the solution build\"), \nthis targets file is imported alongside the temporary MSBuild project generated for \nthe solution, and can therefore provide targets that run before/after any of the \nbuilt-in ones it contains:\n\n- Build\n- Rebuild\n- Clean\n- Publish\n\nFor package restore, we'll just provide a target that runs before Build.\n\nThe gist of the solution is very very simple:\n\n\n\t\u003cPropertyGroup\u003e\n\t\t\u003cNuGetPath Condition=\" '$(NuGetPath)' == '' \"\u003e$(MSBuildThisFileDirectory).nuget\u003c/NuGetPath\u003e\n\t\t\u003cNuGetUrl Condition=\" '$(NuGetUrl)' == '' \"\u003ehttps://dist.nuget.org/win-x86-commandline/latest/nuget.exe\u003c/NuGetUrl\u003e\n\t\t\u003cNuGet Condition=\" '$(NuGet)' == '' \"\u003e$(NuGetPath)\\nuget.exe\u003c/NuGet\u003e\n\t\t\u003cMono Condition=\" '$(OS)' != 'Windows_NT' \"\u003emono\u003c/Mono\u003e\n\t\u003c/PropertyGroup\u003e\n\n\t\u003cTarget Name=\"RestorePackages\" \n\t\t\tBeforeTargets=\"Build\" \n\t\t\tDependsOnTargets=\"DownloadNuGet;EnsureBeforeSolutionImport;RestoreSolutions\"\n\t\t\tCondition=\" '$(RestorePackages)' != 'false' \" /\u003e\n\nThe `DownloadNuGet` target takes care of automatically downloading the `nuget.exe` command line\nfrom the official URL. \nThe `EnsureBeforeSolutionImport` will just error if you try to import this targets file from \nanything but the `Before.[sln].targets` file, just to avoid misuse.\nFinally, the `RestoreSolutions` target basically does the following:\n\n\t\u003cExec Command='$(Mono) \"$(NuGet)\" Restore \"$(SolutionPath)\"'\n\t\t\tWorkingDirectory=\"$(RestoreDir)\" /\u003e\n\n\n\u003e NOTE: `$(Mono)` will be empty on Windows\n\nIn order to download files, we use `curl` both on the Mac and Windows. If it's not available, \nwe download it from [this same repository](https://github.com/kzu/NuGet.Restore/master/curl.exe) \nusing PowerShell on Windows. \n\n\t\u003cTarget Name=\"DownloadCurl\" Condition=\" '$(OS)' == 'Windows_NT' And !Exists('$(TEMP)\\curl.exe') \"\u003e\n\t\t\u003cPropertyGroup\u003e\n\t\t\t\u003cPowerShell Condition=\" '$(PowerShell)' == '' \"\u003e%WINDIR%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\u003c/PowerShell\u003e\n\t\t\u003c/PropertyGroup\u003e\n\n\t\t\u003cExec Command=\"\u0026quot;$(PowerShell)\u0026quot; -NoProfile -Command \u0026quot;\u0026amp; { (New-Object System.Net.WebClient).DownloadFile('$(CurlUrl)', '$(TEMP)\\curl.exe') }\u0026quot;\" /\u003e\n\t\u003c/Target\u003e\n\nWith `curl` at hand, it's trivial to download `nuget.exe` before the other targets:\n\n\t\u003cTarget Name=\"DownloadNuGet\" DependsOnTargets=\"DownloadCurl\" Condition=\" !Exists('$(NuGet)') \"\u003e\n\t\t\u003cMakeDir Directories=\"$(NuGetPath)\" Condition=\" !Exists('$(NuGetPath)') \" /\u003e\n\t\t\u003cExec Command='$(Curl) -o \"$(NuGet)\" \"$(NuGetUrl)\"' /\u003e\n\t\u003c/Target\u003e\n\nFor restoring the solution, the targets simply add the current solution to the `@(RestoreSolution)`\nitem group:\n\n\t\u003cItemGroup\u003e\n\t\t\u003cRestoreSolution Include=\"$(SolutionPath)\" Condition=\" '$(SolutionPath)' != '' \" /\u003e\n\t\u003c/ItemGroup\u003e\n\nNote that being an item group, it allows adding more solutions to restore. It might be that a \ngiven solution brings in projects from other solutions, that may have their nuget packages \ninstalled to a different folder than your solution root. In those cases, you should be restoring \nthose external solutions too before building yours. This can easily be achieved by customizing the \n`Before.[sln].targets` you got. For example:\n\n\t\u003cItemGroup\u003e\n\t\t\u003c!-- Restore/Install some packages that are used without any version # in the path --\u003e\n\t\t\u003cRestoreSolution Include=\"$(BuildDir)packages.config\"\u003e\n\t\t\t\u003cCommand\u003eInstall\u003c/Command\u003e\n\t\t\t\u003c!-- We can pass arbitrary arguments to nuget.exe this way --\u003e\n\t\t\t\u003cArgs\u003e-ExcludeVersion\u003c/Args\u003e\n\t\t\t\u003cOutputDirectory\u003e$(RootDir).nuget\\packages\u003c/OutputDirectory\u003e\n\t\t\u003c/RestoreSolution\u003e\n\n\t\t\u003c!-- Restore a submodule solution --\u003e\n\t\t\u003cRestoreSolution Include=\"$(ExternalDir)SomeSubmodule\\SomeSubmodule.sln\"\u003e\n\t\t\t\u003c!-- Rather than installing the packages to the default path relative \n\t\t\t\t to the current solution, make them relative to the submodule path\n\t\t\t--\u003e\n\t\t\t\u003cOutputDirectory\u003e$(ExternalDir)SomeSubmodule\\packages\u003c/OutputDirectory\u003e\n\t\t\u003c/RestoreSolution\u003e\n\t\u003c/ItemGroup\u003e\n\nThese advanced capabilities are generally not necessary, but for more complex solutions \nwith external dependencies consumed as source code (project references), it's pretty \nuseful. We use this mechanism in *Xamarin for Visual Studio*, for example.\n\n\n\nSo there it goes: a single .targets file, and you can do IDE and command line builds \nconsistently that automatically restore without slowing down builds for each project \nunnecessarily.\n\nYou can just [inspect the entire targets file](https://github.com/kzu/master/NuGet.Restore.targets \"Targets file for automated restore\") \nto learn more, since there are no compiled tasks or external dependencies whatsoever.\n\n\n\nHappy nugetting! ;)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkzu%2Fnuget.restore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkzu%2Fnuget.restore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkzu%2Fnuget.restore/lists"}