In my last post, A world of debuggable open-source software – Part 2: Plugins, I used NuGet Package Explorer as an example of an application that uses NuGet-based plugins, and how that makes it very easy to publish their symbols and sources to SymbolSource, for a great debugging experience in case anything goes wrong at runtime. If you’re interested in creating your own plugin system based on NuGet, have a look at this post by Aaron Powell: Creating a NuGet-based plugin engine.
I also mentioned in that post that you can push any PDB files and sources to SymbolSource, including those of entire applications. Because NuGet is still the easiest way of pushing symbol packages, what we would need is a NuGet-based method of distributing programs. Fortunately such tool exists already and is called Chocolatey. If you haven’t heard of it before, here’s how it’s described by its authors:
Chocolatey NuGet is a Machine Package Manager, somewhat like apt-get, but built with windows in mind.
In this post I will show you how Chocolatey and SymbolSource can be used to publish open-source applications with full debugging support, allowing users with programming skills to analyze problems through code and provide much more useful bug reports. Or even patches and pull requests!
The end-user experience
First let’s try installing a sample application and see how a user can get into its source when something goes wrong.
- Install Chocolatey if you haven’t done so yet:
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('http://bit.ly/psChocInstall'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin
- Install our sample application:
- Chocolatey automatically makes executables included in a package’s lib folder visible in PATH, so can now start our example simply as:
- As printed out, you can now simulate a crash by passing an argument to the program:
- This will give you a stack trace:
Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown.
at SymbolSource.DemoApplication.Program.Main(String args)
And a Windows Error Reporting window:
- Wait it out and click the Debug button. Then choose New instance of Microsoft Visual Studio.
- You might also get this windows instead (does anybody know why?):
- Make sure that the Visual Studio instance that just opened is configured for SymbolSource. Load symbols for
SymbolSource.DemoApplicationfrom the call stack and double click on the call to
Program.Mainto see where and why the program failed.
- Oops, the symbols loaded fine, but the source didn’t! It turns out, that because Chocolatey installs packages in C:\Chocolatety, Visual Studio is having trouble downloading files from the source server. If you enable Print source server diagnostic messages to the Output window in Tools -> Options -> Debugging -> General and try again, you’ll notice this hint in the log: SRCSRV: Source server cannot retrieve the source code (…) Access is denied.
- My solution was to start again from step 4 in an elevated prompt. Visual Studio will warn you that it needs to elevate itself too, to debug an elevated process:
- You should see the source now, loaded by Visual Studio on-demand from SymbolSource.
When looking at the source, notice however that the debugger is stopped at the exit of the scope where the exception occured.
This is because we are actually doing post-mortem debugging here, which was triggered by the absence of any exception handler along the way. Have a look at my previous post for more on this matter: Writing an automatic debugger in 15 minutes – section Choosing the right place and time. It would help, if we set up a breakpoint at the beginning of the scope, and stepped into the exception manually. Unfortunately, for a simple application like this, there’s no way of attaching the debugger fast enough, but you can always take Chocolatey’s package install location and start the program from within the debugger. Except that Visual Studio doesn’t offer this possibility directly, so you’ll need to create a bogus project (e.g. ConsoleApplication or ClassLibrary) and go to Properties -> Debug -> Start action to set Start external program to the actual culprit. Visual Studio will then allow you to start debugging as usual, believing that at some point this external application will call into the current project. It won’t, but we just need Visual Studio to catch the exception that we’ve seen before.
Unfortunately, at this point Visual Studio will still break only at the end of the scope, if you have chosen to load symbols manually at Tools -> Options -> Debugging -> Symbols. Add
SymbolSource.DemoApplication.exe to the module list or choose automatic loading for all modules. After rerunning the bogus project, Visual Studio will now stop at the exception throw site:
Building a debug-enabled Chocolatey package
Now let’s see how easy it is to create a Chocolatey package and how even easier it is to enable symbols and sources publishing for it.
Chocolatey provides a lot of helpers to wrap external setups or ZIP files in packages, but it also allows distributing applications as-is. Like I mentioned before, any executable that you put in the package’s lib folder will be included on your PATH for convenience.
So creating a Chocolatey package for a simple console program like SymbolSource.DemoApplication (you’ve seen all of its source already) is as easy as packaging a
.nuspec file like the following (I prefer building packages with
<files> instead of from projects):
With the application built and ready for packaging, all you need to do is register at chocolatey.org to obtain a NuGet API key and run commands similar to:
nuget.exe pack SymbolSource.DemoApplication.nuspec -symbols
nuget.exe setapikey <key> -source http://chocolatey.org
nuget.exe setapikey <key> -source http://nuget.gw.symbolsource.org/Public/Chocolatey
nuget.exe push SymbolSource.DemoApplication.nupkg -source http://chocolatey.org
nuget.exe.push SymbolSource.DemoApplication.symbols.nupkg -source http://nuget.gw.symbolsource.org/Public/Chocolatey
Let me know if you’re aware of any open-source applications that have chosen Chocolatey as their native distribution method. They’re the first to benefit from all this, the easiest to enable symbol and source publishing for.
And our regular motto to finish off this post:
Let’s create not only an open- but also debuggable-source world