Monday, February 21, 2011

How I NuGet - Creating a NuGet Package


Update: How I NuGet - Creating a NuGet Package – Without a batch file

I started toying around with the MvcContrib project a couple of months ago.  Since then, I created a few UI extensions that use the MvcContrib project. I wanted to contribute to the project; however, Jeremy Skinner recommended that I create a NuGet package and distribute my contributions that way.  So, that's what I did and this post describes/outlines the steps I used to create the NuGet package.

The source for the MvcContrib UI extensions suggested above is available on CodePlex here: MvcContrib UI Extensions - Themed Grid & Menu

My assumption is that you are familiar with NuGet.  If not, you can read all about it at its CodePlex project site.

Here is a high level outline of the steps that I used to create my NuGet package:
  1. Download the NuGet Command Line tool
  2. Create a generic nuget nuspec file - the nuget manifest file
  3. Update the nuget manifest with project specific settings
  4. Create a batch file (.bat) file that will serve as the main entry point into the nuget package creation process
  5. Create the nuget package
  6. Submit and contribute the package to the NuGet Gallery
For reference, the following is a snippet of my directory structure used in the MvcContrib UI Extensions.  I will reference this structure in the steps below.  This image will also help with understanding the batch file used in the steps below.

 

1. Dowload the NuGet Command Line tool

Easy - download the NuGet command line tool here.  Using our structure above, put the .exe into the MvcContrib.Shp/nuspec/ directory.

2. Create a generic nuget nuspec file - the nuget manifest file

Create the .nuspec file by running the following command from the dos prompt:

nuget spec
This will create a file by with the name of Package.nuspec. All this is is an xml file that describes the details of the package - formally called a package manifest or specification.  While renaming this file is not required, I think it makes sense to give it the same name as that of the resulting NuGet package  - in our scenario, MvcContrib.Shp.nuspec.

3. Update the nuget manifest with project specific settings

The NuGet .nuspec file format specification contains many configuration details; however, for our scenario I’ve updated the .nuspec file to contain the following content:

<?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <id>MvcContrib.Shp</id>
        <version>1.0.0.0</version>
        <authors>Dan Ryan</authors>
        <owners>Dan Ryan</owners>
        <licenseUrl>http://mvcxgridmenu.codeplex.com/license</licenseUrl>
        <projectUrl>http://mvcxgridmenu.codeplex.com/</projectUrl>        
        <requireLicenseAcceptance>false</requireLicenseAcceptance>        
        <description>UI Extensions to the MvcContrib Project - Themed Grid & Menu</description>
        <tags>MVC MVC3 ASP.NET MvcContrib</tags>
        <dependencies>
            <dependency id="MicrosoftWebMvc" version="2.0" />
            <dependency id="MvcContrib.Mvc3-ci" version="3.0.57.0" />
        </dependencies>
    </metadata>
</package>
The XML elements are pretty self-explanatory; however, I recommend reading the NuGet .nuspec file format specification for details on each element.

4. Create a batch file (.bat) that will serve as the main entry point into the nuget package creation process

This step is not necessary; however, I like batch files.  Batch files give us the ability to place simple, repeatable logic into a batch file and execute that logic by double-clicking the batch file.  The following batch file creates a temp directory with subdirectories for the NuGet package content, copies the files (.dll, and .js files) from the source directories and places these files in the temp content directories, executes the NuGet.exe pack command, and then cleans up by removing the temp directories.  Again, this could have all been done via the .nuspec file, but I just prefer to use the batch.  Here’s the batch file contents:

echo OFF :: root nuspec directory set rootDirectory=%cd% ::::::::::::::::::::::::::::::::: :: 1) build the destination directory structure ::::::::::::::::::::::::::::::::: :: destination structure set baseDirectory=basenuspec set contentDirectory=content set libDirectory=lib set scriptsDirectory=Scripts :: make directory command set makeDirectoryCommand=MKDIR :: delete directory command ::set deleteDirectoryCommand=DEL /f set deleteDirectoryCommand=RMDIR /s /q :: delete the previous package build files and directories - if they were not deleted before %deleteDirectoryCommand% %baseDirectory% :: build the directory structure %makeDirectoryCommand% %baseDirectory% cd %baseDirectory% %makeDirectoryCommand% %libDirectory% %makeDirectoryCommand% %contentDirectory% cd %contentDirectory% %makeDirectoryCommand% %scriptsDirectory% :: navigate to the root directory cd %rootDirectory% ::::::::::::::::::::::::::::::::: :: 2) copy files from source to destination ::::::::::::::::::::::::::::::::: :: relative path to the MvcContrib.Shp.dll set srcLibDirectory=..\src\MvcContrib.Shp\MvcContrib.Shp\bin\Release\ :: relative path to source script files set srcScriptsDirectory=..\src\MvcContrib.Shp\Shp.Web\Scripts\ :: lib files to copy set libFiles=MvcContrib.Shp.dll :: script files to copy set scriptFiles=jquery.mvccontrib*.* superfish.js *jquery.hoverIntent* :: copy commnad set copyCommand=COPY /y :: copy the source dll to the lib destination directory %copyCommand% %srcLibDirectory%\%libFiles% %rootDirectory%\%baseDirectory%\%libDirectory%\ :: navigate to the root directory cd %rootDirectory% :: navigate to the source scripts directory cd %srcScriptsDirectory% :: copy the source scripts to the scripts destination directory for %%F in (%scriptFiles%) do %copyCommand% %%F %rootDirectory%\%baseDirectory%\%contentDirectory%\%scriptsDirectory%\ :: navigate to the root directory cd %rootDirectory% ::::::::::::::::::::::::::::::::: :: 3) create the nuget package ::::::::::::::::::::::::::::::::: :: nuget pack command set packCommand=NuGet.exe pack :: nuspec manifest file set manifest=MvcContrib.Shp.nuspec :: run the nuget package command %packCommand% %manifest% -b %baseDirectory% :: delete the temp package build files and directories %deleteDirectoryCommand% %baseDirectory% ::PAUSE
The above batch file is pretty much fully documented, so it shouldn’t take too much to understand the logic.

Could I have used PowerShell to do this? Absolutely; however, I really haven't spent much time diving into PowerShell. Until then, the batch solution works just fine.

As a side note - NuGet gives you the ability to add Content to the package (this is essentially what the previous batch file is doing); add pre-processing of files to the client project (the project importing the NuGet package); add XML elements to be merged with the client project's .config files; add PowerShell scripts to do anything else that the NuGet package requires; and a whole laundry list of other functionality. Again, if you're interested, check out the NuGet Project and Documentation on CodePlex.

5. Create the nuget package

In our scenario, creating the NuGet package is simple.  All you have to do is double-click the .bat file and the batch file handles the command to create the NuGet package.  The resulting package is compiled into a single file.  In our scenario and using the .nuspec file from above, the resulting package is compiled into: MvcContrib.Shp.1.0.0.0.nupkg. How is the package name composed? The following image identifies the package name components:

nupkgname

 

6. Submit and contribute the package to the NuGet Gallery

Log into the NuGet Gallery and contribute your package.  What?  If you don’t already have an account, request one from the NuGet Gallery.  The process of submitting/contributing you package for distribution is as simple as uploading and following the NuGet package wizard.

Useful Links:
Anyway, thanks for reading…

2 comments:

joy said...

The mind is a great philosopher. And life is not a philosophy, life is a reality. And philosophy is an escape from reality; philosophy means thinking. Life is, there is no question of thought. You can simply jump into it. You can simply experience it. Visit my site for more information.Thank you.

n8fan.net

www.n8fan.net

Leslie Lim said...

Wow. Awesome article. Please do more articles like this in the future. Very informational and knowledgeable. I will expect more from you in the future. For now i will just bookmark your page and surely I'm gonna come back later to read more. Thank you to the writer!


Rica
www.imarksweb.org