Difference between Source Link and a NuGet symbol package - nuget

While debugging I can step into external dependencies and our own nuget packages, if they were compiled to symbol packages (MyProject.snupkg) and uploaded to the nuget server. This is how we do it for our own nuget packages on our private nuget server.
I discovered the Source Link tool, whose readme states
Source Link enables a great source debugging experience for your users, by adding source control metadata to your built assets
What is the difference between that and the setup I've described above? And is there a benefit to using both at the same time?
(I've found existing SO questions for configuring Source Link, but none about the difference to symbol packages.)

I consider Source Link as some kind of evolution from symbol packages.
With the symbol packages, you always had two files:
MyPackage.nupkg (contains the assembly itself)
MyPackage.snupkg (contains the debug symbols)
So basically the debug symbols are shipped as a separate NuGet package (the snupkg file) and the relationship to the underlying source code is broken.
Microsoft lists some more constraints (see here).
Now since a lot of source code is open anyway (e. g. on GitHub), why not link the NuGet package directly to the sources? That's what Source Link does: it bridges the gap between the referenced assembly and its source code, without relying on an intermediate file (like snupkg).
This enables true deterministic builds, i. e. one can verify which Git commit was used for an assembly of a NuGet package.

Related

How to wrap a NUnit Engine Extension as a NuGet package?

I am working on a nunit engine extension which will be shipped as a nuget package.
Following the advises in How to implement NUnit's NUnit.Engine.ITestEventListener i was able to write the extension.
This solution is working as long as the project which contains the extension (the .cs file as well as the .addins file) is being imported to the target project which will perform the nunit tests.
As soon as I create a nuget package (following Quickstart: Create and publish a NuGet package using Visual Studio (.NET Standard, Windows only)) from the extension project and install this package to a test project, the extension doesn't work anymore.
I assume there is a problem with providing the .addins file within the nuget package so that the nunit engine in the target project can find the extension.
I already tried to ship the .addins file within the nuget package by adding the following lines to the .csproj file of the extension project.
<ItemGroup>
<Content Include="file.addins">
<Pack>true</Pack>
</Content>
</ItemGroup>
If I add the .addins file to the target project by hand, the engine extension starts working.
How can a nunit engine extension be shipped as a nuget package without any adjustments by hand?
Im using NUnit(3.13.2).
Im quite new to nunit, nuget and writing questions on stack overflow. So if I'm missing something obvious here, I'm sorry.
This is one of those areas where I wish things were less complicated, unfortunately. Since extensions are found through a relative path from the NUnit engine to the package content, it depends on where both the engine and runner are located and where the package is located on your machine.
Here are some initial guidelines...
How to structure the package itself... your extension assembly itself should be in the tools directory. If there are other assemblies with it, which it references, it's best to also include a .addins file in the same directory, which lists that assembly on a single line. That way, the NUnit engine will save time by only examining the extension assembly.
A NuGet extension package will automatically be found by the engine if the runner has been installed as a nuget package as well. This works no matter how the packages are installed on your machine, i.e. using packages.config or in a nuget cache, provided both packages were installed the same way. (That proviso is a real gotcha and it may be that a future version of the engine needs to actually understand nuget.) See the addins file provided with the the NUnit 3 console runner as an example of why this works.
The same thing is true if both the runner and the extension are installed as chocolatey packages, because they are both in the chocolatey cache. If you do provide one (which I recomend) it has to be a "native" package - one that includes the actual binaries. A chocolatey package that merely invokes the nuget package will not work. See the source for any of the NUnit-provided extensions for an example of how this this is done.
If the executing copy of the engine (usually in the same directory as the runner) is anywhere else, there is no automatic way for the extension to be found. This includes the case where you are building a runner yourself and want the extension to be available while you are developing. In that case, you need to fully understand how the engine finds extensions (see the docs) and manually create an addins file (next to any that was distributed with the engine) containing the proper relative path.
This is especially complicated if you are developing an extension for general release. Then you have to deal with various runners installed in different ways by different people. OTOH, if you are doing this for internal use in your company, you may only need to deal with one of them. If you add more specifics about your goal to the question, I'll edit this with some more specific suggestions.

NuGet package dependency source files are not embedded in project

We create and host NuGet packages in-house, with source code and deep dependency trees. I'm having some issues getting dependencies to "behave".
For clarity, this is specifically installing packages via VS or Rider into a .Net Core / PackageReference project. I don't expect it to be a VS/Rider/etc bug, so much as we're doing something slightly wrong.
Scenario:
Create “Package A” using the PackageReference style compilation of
“contentFiles/any/any”.
Create a sub-folder under “contentFiles/any/any” called “Source”.
Place source code files in the “Source” folder.
Have a dependency on “Package B”.
Create “Package B”, again using the PackageReference style, with a “Source” subfolder.
Place source code files in its “Source” folder.
Pack and publish both.
Expectation:
Install “Package A” (using the built-in NuGet package manager UI).
Your project gains a “Source” folder.
A’s source files are referenced into the new “Source” folder and compile with the project.
“Package B” is also installed, since it’s a dependency.
B’s source files are also referenced into the “Source” folder and compile with the project.
Package A is immediately consumable by the project because all of its code, and all of its dependency’s code, is present.
Actual:
Install “Package A”.
Your project gains a “Source” folder.
A’s source files are referenced into the new “Source” folder and compile with the project.
“Package B” is also installed, since it’s a dependency.
B’s source files are not referenced into the “Source” folder.
Package A code cannot be compiled because the source for B is not in the project.
Manually install “Package B”, same as you did for “A”.
B’s source files are referenced into the new “Source” folder in the project.
Now “Package A” can be compiled and consumed.
If sample nuspec files are needed, etc. please let me know.
Thanks
(This is a cross-post from https://github.com/NuGet/Home/issues/8858. No replies for a week)
The post to NuGet's github (listed above) ended up with the solution. When declaring the dependency in the nuspec, set the include to "Runtime,Compile,Native,ContentFiles,BuildTransitive" (or some combination thereof) and your dependency's files will correctly embed. I'm still working through the differences between the options, but there you have it.

How do I get a binary NuGet package with one csproj's assembly but a corresponding source package with two csproj's sources?

Using the really easy to follow instructions for building a NuGet package for an assembly with an associated package of sources for the symbol server, found here on David Ebbo's blog "The easy way to publish NuGet packages with sources" I have indeed created a pair of packages: binary and sources.
However, the sources package is incomplete and the reason is that the sources come from two class library .csproj and I used ILMerge to combine the results of the second into the first. (*) So, using the minimal .nuspec described in this post and pointing nuget.exe at the .csproj for the "main" library, the binary package is fine, but of course the sources package only has sources for the "main" library, not also for the library that was ILMerged into the "main" library.
How do I fix this (and get the sources for both projects included in the symbol package but only the binary for the "main" project in the binary package)?
FYI, the actual nuget.exe command line was: nuget pack CommandLineLexing.csproj -Build -Symbols -Properties Configuration=Release.
(*) The reason I'm doing this, in case you're interested, is that the second library is a cut down version of my accumulated "C# utilities" library - you know, a bunch of extension methods and other helpers - cut down so it only has the bare minimum needed for this particular project. And so, since it is cut down, I don't want there to be separate assembly for it which might eventually get confused with the full assembly (having the same name, and not a strong name). So I used ILMerge to put the utilities methods into the main assembly (and also mark them internal).
Not going to be easy I'm afraid.
NuGet symbol packages are simply your regular package, with pdbs, augmented with source files.
Assuming you already know you can get a merged PDB with ILMerge/ILRepack (/debug), that part is probably working file, I'm assuming your issue is that only the source files from the current project gets included.
You could simply post-process your symbol.nupkg (which is a zip), and include the source files from your other (merged) project in the src folder (you can even try that manually).
Though if you run srctool.exe -r MyMergedAssembly.pdb, you'll see different root paths, where usually (for a non-merged project) they all have a common prefix.
It may work, if SymbolSource copes with having multiple path prefixes in your PDB, that I haven't tried.
I also failed to find any documentation irt to their processing of symbol packages. We can assume they use pdbstr.exe tool to update the PDB srcsrv section of the PDB file to redirect the symbol loading to their website, but one can only tell if they support multiple roots by testing it.
If you upload your augmented symbol package to symbolsource, you can download the updated PDB using a URL similar to http://srv.symbolsource.org/pdb/Public/Castle.Core.pdb/4C81FC30DF584853B9869EAB2FA7D9891/Castle.Core.pd_ (then unzip it to a pdb file)
Then you can use both srctool.exe file.pdb and pdbstr.exe -r -s:srcsrv -p:file.pdb to verify their work.

Get current version of package outside of Visual Studio

We are migrating over to using packages and NuGet for managing our dependencies on 3rd party components. This works well when referencing packages from within Visual Studio or building on the build server via msbuild.
However there are a number of files that we would like to access in our build scripts and installers. Previously these would be in source control with a well known path, now as the version of the package that we are consuming changes so the path to the package and hence the files is changing.
Is there a simple way I can get the path to a given package? The best solution I currently have is to search for all packages.config files and extract the package version from them.
Examples of the files that we need to access are
The NUnit console executable from the NUnit.Runners package for running unit tests.
License files from various packages that we redistribute with our installer.
Using the packages.config file is a pretty good solution. NuGet itself uses two approaches:
Reading the package information from the packages.config and using that to resolve to the packages path.
Enumerating all the directories in the packages directory.
You could use NuGet.Core to do either of the above if you do not want to write the code yourself. The classes that can be used are the DefaultPackagePathResolver, the PackageReferenceFile and LocalPackageRepository or SharedPackageRepository.
One problem with the second approach is that sometimes NuGet may occasionally leave behind NuGet packages that are not necessarily referenced by a project. In that case looking at the package directories may give you the incorrect information.
The only other approach I can think of might be to read the project files looking for the assembly references. Although that would not work for a solution level package such as NUnit.Runners.

NuGet pack is not packaging all files in the output directory. What am I missing?

I'm trying to create a NuGet package from a .csproj. I have successfully compiled the project and the output folder contains all of the necessary files (my assembly and all of its dependencies). However, NuGet only seems to be placing the assembly created by the .csproj into the package and not any of its dependencies. My command line looks like this:
nuget pack MyProject.csproj -Property Configuration=Release
and my resulting .nupkg file only has my assembly in the lib folder. I have successfully gotten NuGet to work for other projects, but it just so happens that this project is referencing the Enterprise Library logging block, but it was NOT retrieved via NuGet. I'm not sure if that could be related to my problem or not.
Any thoughts on why it's not picking up the dependenices?
If you need to keep your nuspec file up-to-date automatically, its really just an XML file (as I'm sure you know) so there are some very nice tools you can use from MSBuild to automate nuspec creation/updates. Out of the box, MSBuild provides a few tasks that can update or transform XML, and I've used MSBuild Community Tasks to customize the initial nuspec. For example, the default nuspec contains a few lines with broilerplate that I don't need, so I use XmlUpdate tasks to delete them.
Although I have not looked into scanning the csproj file for non-nuget references, I think its likely possible with a little research. Here are some links to blog entries describing my experiences with NuGet automation, they may help you get a head start:
Creating Packages with NuGet the MSBuild Way - This article includes some basic NuSpec updates because the package described is not that different from the type of package NuGet already knows how to automate.
Manage Your MEF Parts With Nuget - This article includes some more complex updates to support distributing MEF parts as runtime-only references.
If you plan on doing this alot, don't want to mess with MSBuild, or just want to get back the behavior you liked from the pre-1360 version of ProjectFactory.cs, NuGet supports third-party extension through MEF. You could go into the source control and grab the earlier code that you liked and create a custom command (for example custompack) that provides that behavior. Then you could use it from the command line like so:
nuget custompack MyProject.csproj -Property Configuration=Release
I think this is a really cool aspect of NuGet but I haven't played with it myself yet. Here is an article that explains how to do it:
Extend NuGet Command Line
So even though David mentioned that NuGet is not designed to support this scenario, if the scenario is correct for you then you can go this route to extend NuGet to meet your needs.