Monday, June 11, 2012

Creating your first package with Chocolatey NuGet

What is it and why would I want to do it?

Chocolatey is a way to download and install software in Windows from the command line. Its documentation describes it as 'a kind of apt-get for Windows'. If you're not familiar with package managers in other systems, think back to the last time you were setting up a new machine, or reinstalling your current machine. Launch Internet Explorer. Download a new browser. Search for the homepages of your favorite tools and utilities, download various zips or MSIs. Open your My Downloads folder and run each of the installers individually, clicking yes and continue and ok incessantly. Redownload some of the installers because you forgot to download the x64 executable. Rinse, repeat.

With Chocolatey, you can install software in one convenient step from the command line. Moreover, if the application you are looking for does not yet have a package in the Chocolatey repository, you can add it to save time for others (and your future self, when you go to reinstall that software again). So, think of an application or tool you love, and let's create a Chocolatey package for it.

Get Chocolatey

The first step is to install Chocolatey. This is bootstrapped by executing a one-line powershell script. Hit Windows + R to bring up the "Run" dialog. Type cmd and hit enter to bring up a Command prompt. Copy and paste the following line into the command prompt and run it:

> @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('http://bit.ly/psChocInstall'))"

This will download and install the latest version of Chocolatey and add it to your PATH environment variable. Now you can run Chocolatey from the command line. Run the following to show the help page:

> chocolatey --help | more

To install a package, use chocolatey install <packageName> or the shortcut:

> cinst <packageName>

You can list available packages by running chocolatey list or browsing the main repository at http://chocolatey.org/packages.

Register to create your own packages

Chocolatey packages typically don't contain the executables themselves, but rather scripts to automate downloading and executing the installers. This means that, in most cases, you are free to create Chocolatey packages for your favorite tools and utilities. For open source software with licenses that explicitly allow redistribution, you should be fine. For proprietary licenses, use your best judgement and ask the software's author when in doubt. Refer to the wiki for more on distribution rights.

First, register at Chocolatey.org. Click through the confirmation link in your email, log in, then go to your account page. Scroll down to where it says API Key and click the area to show your API key. Copy this key to your clipboard.

Note that as of 6/10/2012, the instructions shown on the site are incorrect and apply to NuGet, not Chocolatey. To setup your API key in Chocolatey, run the following:

> nuget setApiKey <apiKey> -Source http://chocolatey.org/api/v2/

Now we're ready to create the package. Chocolatey packages are NuGet packages that contain a PowerShell scipt named chocolateyinstall.ps1 in the /tools directory. Chocolatey also provides some helper PowerShell functions to make writing the install scripts easier.

Git clone the chocolatey template account

You should have git installed on your machine. If you don't install it now:

> cinst git

Now let's clone the Chocolatey and open the template folder:

> git clone https://github.com/ferventcoder/nugetpackages.git
> cd nugetpackages/_template/chocolatey
> tree /F
Folder PATH listing
Volume serial number is ...
C:.
│   __NAME__.nuspec
│
└───tools
        chocolateyInstall.ps1

As you can see, we have the .nuspec file, which is an XML file containing metadata for the package, and the chocolateyInstall.ps1 file which contains the powershell script for downloading and running the installer.

Copy this directory stucture to a new folder for your package. You may want to keep this package in source control, for example Github. This will make it easier to manage updates to your packages as new versions are released.

Rename __NAME__.nuspec to whatever you want your package name to be. Don't include a version number, as the package name will stay the same between versions. This is the name that people will type when they go to cinst your package. Open this file and update the appropriate fields. Be complete, especially with the version number of the underlying software, the license information and links back to the project homepage. For more information about the nuspec file format, see the nuspec reference.

Edit the chocolateyInstall.ps1 file in your favorite text editor. This template file is commented and includes common examples. You can use any PowerShell commands you want in this file, but it's best to keep it simple. For more on the included Chocolatey commands, see the helpers reference on the wiki.

Make sure the chocolateyInstall.ps1 file is in a folder called /tools under the folder which contains the nuspec file. This is where Chocolatey will look to run the install script.

Build and publish your package

To finalize your package, navigate to the directory for your package in a command window and run:

> chocolatey pack <packageName>.nuspec

This will create a file called <packageName>.nupkg, which is a zip file containing the .nuspec and chocolateyInstall.ps1 files. It also validates the metadata in the package. This resulting .nupkg file is the package itself which we'll upload to the Chocolatey repository.

First, let's test the package. cinst has a -source flag which will let you specify a location other than the main Chocolatey repository to check for packages. This can also be a folder on your local machine. We'll also use the -force flag so we can repeat the installer while we're testing the package. By default, Chocolatey will only install a package once.

> cinst <packageName> -source <pathToYourPackage> -force

Note that -force makes Chocolatey re-run the chocolateyInstall.ps1 script, but it won't redownload the NuGet package. If you need to make a change, delete the package folder from c:\Chocolatey\lib\<packageName>. Then re-run chocolatey pack <packageName>.nuspec and run cinst again. Repeat as necessary.

Verify that everything worked as expected. All set? Let's push the package to Chocolatey.

> chocolatey push <packageName>.nupkg

That's it! You can verify that your package uplaoded successfully by going to the package list page ordered by created date.

In conclusion

Having real package management in Windows is a huge win. It makes installing software and setting up a development environment dirt simple and extremely fast. Spread the word to other developers your know, and announce your new Chocolatey packages. Inform the original authors that you created a Chocolatey package to help distribute their work to build awareness of Chocolatey. Lastly, take a look at the Chocolatey source on Github and see if you can contribute by looking through the open issues and possibly contributing a pull request or updating wiki documentation.

Thanks to R in the comments for pointing out some corrections

3 comments:

  1. Awesome! Thanks for the post!

    A couple of things though.
    1. The -force doesn't yet delete the installed pkg folder so while testing you will want to do that.
    2. If you have distro rights you can include the executables. If not, the chocolatey install works the same as a human so you don't need distro rights.
    3. I believe it is nuget setapikey still.

    Awesome stuff and I took a look at one of your packages. Looks great!

    ReplyDelete
    Replies
    1. Thanks for pointing that out!

      @1: -force makes Chocolatey re-run the chocolateyInstall.ps1 script, but it won't redownload the NuGet package. To clean that out, delete the folder from c:\Chocolatey\lib\

      @3: You're right - the command to set the api key is
      nuget setapikey -Source
      http://chocolatey.org/api/v2/

      Delete
    2. http://chocolatey.org/api/v2/

      Delete