Monday, October 11, 2010

A Quick Play With NuPack

For those of you who have been hiding under a rock for the last few days, NuPack is a Microsoft sponsored package management system along the lines of Ruby Gems. As anyone who’s tried to use open source software on a .NET project will know, package management, or lack of it, has been a huge problem. Having a standard system that OSS developers can target and a central recognised repository of software will have a major impact on the adoption of OSS in the .NET world.

Make no mistake, this is revolutionary. It’s the difference between right-clicking on references in VS to install an OSS library and the huge PITA that getting source, building, resolving dependencies, etc has been up to now. It makes it orders of magnitude easier.

So, eager to have a play with this shiny new toy, I quickly installed the CTP and fired it up. Looking at the list of packages, I was initially disappointed to see that the latest Castle Windsor release, 2.5.1, wasn’t there. Never mind, I thought, this is a perfect excuse to dig around and see how it works.

Let’s build a new NuPack package for Windsor 2.51.

Castle Windsor has a dependency on Castle.Core, so I need to create a package for that too. Castle.Core also has dependencies on log4net and NLog. So I created a directory structure like this:

nupack_directory_structure

In the Castle.Core directory goes the Castle.Core.nuspec file. It’s a simple XML file that describes the package. I just copied the version from the NuPack source and changed the version number, note the dependencies list:

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
    <id>Castle.Core</id>
    <version>2.5.1</version>
    <authors>
      <author>Jonathon Rossi &amp; Krzysztof Kozmic</author>
    </authors>
    <description>Core of the castle project</description>
    <language>en-US</language>
  </metadata>
  <dependencies>
    <dependency id="log4net" />
    <dependency id="NLog" minversion="1.0" />
  </dependencies>
</package>

In the lib directory under Castle.Core we put the Castle.Core.dll downloaded from the Castle project website. We do the same for Castle.Ioc, here’s the Castle.Ioc.nuspec file, including the dependency on our new Castle.Core 2.5.1:

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
    <id>Castle.Ioc</id>
    <version>2.5.1</version>
    <authors>
      <author>Ayende Rahien</author>
    </authors>
    <description>Castle Project ... </description>
    <language>en-US</language>
  </metadata>
  <dependencies>
    <dependency id="Castle.Core" version="2.5.1" />
  </dependencies>
</package>

We pop the Castle.Windsor.dll assembly in the lib folder. For log4net and NLog I just copied the existing nuspec files and assemblies from the NuPack source.

The next job is to run nupack.exe against the nuspec files. This packs up the assemblies and the nuspec file into a single nupkg binary file:

nupack_console

Open the Package Manager Console in Visual Studio and point it at our local nupkg files rather than the default remote repository:

nupack_package_source

Now we can install our new packages:

nupack_install_packages

Note deliberate mistake :)

When you install the packages, NuPack adds a reference to them to your project:

nupack_project_refs

It also creates a packages.config file:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="NLog" version="1.0" />
  <package id="log4net" version="1.2.1" />
  <package id="Castle.Core" version="2.5.1" />
  <package id="Castle.Ioc" version="2.5.1" />
</packages>

One thing that confused me for a while is that NuPack caches the packages list while your solution is open. When I deleted all the references, the assemblies and the packages.config file it still insisted that: ‘Mike.Spikes already has a reference to 'log4net 1.2.1'’. Closing and opening the solution refreshed the cache and fixed the problem.

So there we have it. NuPack is very cool and the fact that it only took me a couple of hours this afternoon to go from zero to building my own packages shows how easy it is. You need to learn how to use it, it’s going to be ubiquitous in .NET development very soon.

10 comments:

David Fowler said...

Nice post, the caching issues are fixed for the next version :).

Anonymous said...

Thanks, makes it all seem nice and clear. Any chance you'll be repeating the exercise with Openwrap to do a comparison?

Mike Hadlow said...

Hi Anonymous,

Don't hold your breath. I'll probably stick with NuPack now, unless it proves to have serious shortcomings. In any case I understand that Seb's working to make OpenWrap compatible with NuPacks package definitions, so you should be able to use them interchangeably.

Ryan Cromwell said...

Looks awesome. So you're aware I pushed the Castle.Core 2.5.1 out last night to the main repository at nupackpackages.codeplex.com which feeds the default nupack source. You can have windsor if you're planning to send a pull request to nupackpackages.

Also, see this post for information on the integration with NLog and log4net: http://nupack.codeplex.com/Thread/View.aspx?ThreadId=230498

Mike Hadlow said...

Hi Ryan,

That's excellent, thanks!

Anonymous said...

Mike this sounds alot like nubular at nu.wikispot.org. Have you seen this oss?

Mike Hadlow said...

Hi Anonymous,

I gather that the nubular guys have been helping with NuPack and the plan is to merge the projects at some point.

Sebastien Lambla said...

Well, I do hope you'll still try openwrap, it's easier to use and has more features.

It'd be a shame to stick with the "good enough" wouldn't it?

Mike Hadlow said...

Thanks Seb,

I'll make a point of having a look at it. Have you blogged about the differences/advantages of OpenWrap?

Sebastien Lambla said...

I'm just going to post about our featureset, people can draw the comparisons themselves. I don't think it's quite what I should be doing in the doco or in blogs, but then again I'm not a marketing guy :)