Installing OpenWrap from the sources

OpenWrap normally relies on a central server for providing the initial shell and its associated packages. However, when you get on a new machine, you don’t necessarily want to get the release server, or it’s down.

Fear not, for the process is dead easy.

Get the sources

First things first, you need to get yourself the source code. It’s at http://github.com/openrasta/openwrap. If you don’t know how to use git, go install msysgit, open yourself a github account, fork OpenWrap to your account (by clicking on the fork command from the project’s page), and at a command line, type the following command to clone your fresh new repository.

<div><b>PS C:\tmp></b><i> git clone git://github.com/yourusername/openwrap.git</i></div>

Do the same thing for the shell source code, which you can find at http://github.com/openrasta/openwrap-bootstrap.git.

Build and install the shell

The openwrap-bootstrap project contains the shell. It’s a very small executable that has the sole responsibility of finding the OpenWrap packages and executing them.

To build it, simply open the solution and run it. The shell will ask you if you want to install itself and add the correct path to your path environment variable (this is the i option). Once this is done, close the shell, as if you have no access to the server, it will crash on you with a nice error message.

Install OpenWrap in your System Repository

Now open a console where you cloned OpenWrap. The beauty of the per-project deployment of OpenWrap is that you don’t need any install of the packages themselves on your machine. We’ll leverage this feature to build and run the OpenWrap packages.

Go to the /wraps folder, and use the add-wrap openwrap –system command. This is the command you provide to get OpenWrap installed, and you do it with the –system flag so it goes to your system repository.

<div><b>PS C:\src\openwrap\wraps></b><i> o add-wrap openwrap -system</i></div>
# OpenWrap v1.0.0.0 ['C:\src\openwrap\wraps\_cache\openwrap-1.0.0.18871048\bin-net35\OpenWrap.dll']
Wrap descriptor found.
Project repository present.
Copying 'openwrap-1.0.0.18871048' from 'Current directory' to 'System repository'
Copying 'openfilesystem-1.0.0.18676829' from 'Current directory' to 'System repository'
Copying 'sharpziplib-0.85.5.452' from 'Current directory' to 'System repository'
Making sure the cache is up-to-date...

You’re done. You’ll now be able to execute OpenWrap commands from anywhere.

Ads

Building polyglot packages for OpenWrap and NuPack

As we approach a first full-featured OpenWrap release, it’s time to provide package builders some guidance in how to build good packages.

For a week now, the OpenWrap client has supported the NuPack package and feed format for assemblies. We don’t support powershell scripts so far, as OpenWrap doesn’t have a dependency on it, but assemblies in the /lib folder are fully supported.

Test your packages

The easiest way to test a nupack package is to use the convert-nupack command available in OpenWrap.

<div><b>PS C:\tmp></b><i> o convert-nupack .\Castle.Core.1.1.0.nupkg.zip Castle.Core.1.1.0.wrap</i></div>
# OpenWrap v1.0.0.0 ['C:\Users\sebastien.lambla\AppData\Local\OpenWrap\wraps\_cache\openwrap-1.0.0.18826071\bin-net35\OpenWrap.dll']
Package successfully converted.

This will convert the NuPack into an OpenWrap package. You can then add this package to your system repository or to any other project as usual.

Understand framework profiles

The resolution logic between NuPack and OpenWrap is slightly different.

NuPack will add references to the dlls it finds in a folder called /lib/[Framework][Version], and only in that package.

OpenWrap, because it focuses on solving dependency resolution at run-time too, supports dynamically swapping assemblies by name, and will process any compatible assembly in the package. An example will make it clearer.

The Newtonsoft.Json package contains a .net 2.0 specific dll in /lib/20 called Newtonsoft.Json.Net20.dll, and a 3.5 version in /lib/35. Only one of those references should be included.

NuPack will only add the /20 or the /35 libraries to your project. OpenWrap however will find two assemblies named differently, and provided you are resolving those assemblies in a .net 3.5 environment, will import both.

The correct way to package your assembly is to name the same assembly targeting different frameworks the same, and put them in the correct folder.

To sum up, here’s the structure that should be used to package your assemblies targeting different versions.

NuPack

  • /lib

    • /20

      • Newtonsoft.Json.dll (formerly /lib/20/Newtonsoft.Json.Net20.dll)
    • /35

      • Newtonsoft.Json.dll (formerly /lib/35/Newtonsoft.Json.dll)

OpenWrap

  • /bin-net20

    • Newtonsoft.Json.dll (formerly /lib/20/Newtonsoft.Json.Net20.dll)
  • /bin-net35

    • Newtonsoft.Json.dll (formerly /lib/35/Newtonsoft.Json.dll)

Version your packages

Versioning of packages is vital for good package management. I’m not entirely sure what the versioning behaviour for NuPack is, but OpenWrap is quite opiniated. Each package can and should be versioned using the Major.Minor._Build.Revision _format.

When you take a dependency on a package version however, OpenWrap will ignore the Revision component, and automatically import any new revision of a package next time you update.

The reason for this is to enable hot patching packages to correct issues without users having to change the dependency they declared.

Let’s take an example. Let’s push a package to a remote repository.

<div><b>PS C:\tmp></b><i> o publish-wrap server .\castle.core-2.5.1.0.wrap -debug</i></div>
# OpenWrap v1.0.0.0 ['C:\Users\sebastien.lambla\AppData\Local\OpenWrap\wraps\_cache\openwrap-1.0.0.18839165\bin-net35\OpenWrap.dll']
Publishing package 'castle.core-2.5.1.0.wrap' to 'server'

I now add a dependency to my project (you would do the same using xml in your .nuspec if you build for NuPack).

depends: castle.core = 2.5.1.0

And I ask OpenWrap to fetch the latest packages.

<div><b>PS C:\tmp\castle.user></b><i> o update-wrap</i></div>
# OpenWrap v1.0.0.0 ['C:\tmp\castle.user\wraps\_cache\openwrap-1.0.0.18839165\bin-net35\OpenWrap.dll']
'Project repository' up-to-date as 'openwrap-1.0.0.18839165' <= 'openwrap-1.0.0.18839165'.
'System repository' up-to-date as 'Castle.Core-2.5.1' <= 'Castle.Core-2.5.1'.
Copying 'Castle.Core-2.5.1.0' from 'server' to 'Project repository'
'Project repository' up-to-date as 'openfilesystem-1.0.0.18676829' <= 'openfilesystem-1.0.0.18676829'.
'Project repository' up-to-date as 'sharpziplib-0.85.5.452' <= 'sharpziplib-0.85.5.452'.
Making sure the cache is up-to-date...

Of course, you would’ve had the same result by simply asking OpenWrap to add the pacakge with the add-wrap command.

If I now push a new version of castle.core, say 2.5.1.1, and execute an update, the package will be automatically updated to the latest version, no question asked.

To recap:

  • Do change the revision part to deploy hot fixes to your package so people don’t have to update their dependency files

  • Do change the build, minor or major components when you want to let people depend on a different version of your API.

    • Update the build component when you add new classes or method

    • Update the minor component when you rename, remove or change the signature on your API.

    • Update the major as you wish.

Don’t sign your assemblies

One of the features OpenWrap provides is dynamic swapping of assemblies based on your framework version and platform (x86, MSIL, etc). This can only work if you don’t depend on signed assemblies, and if you don’t sign yours.

If you have signed assemblies in your workflow, you will have to create publisher policy redirections, a lot of xml that goes in your .config files. We may automate this process in the future, but if you’re going to automatically add those entries to enable new versions of an assembly to be used, you may as well Keep it Simple Stupid and not sign them.

There is no reason to use assembly versioning when package versioning is in place. Contrary to what some may think, it doesn’t provide identification of assemblies (anyone can generate a key), it doesn’t protect your assembly from decompilation, it is only used for ensuring that software compiled against a certain version of an assembly doesn’t get updated without a recompile, which is exactly what we’re trying to avoid.

Understand your dependencies

If you follow the versioning model I mentioned above, you will know which range of versions your assemblies depend on.

Problem is, at a very minimum, it’s unlikely that version 3 of NHibernate will have exactly the same API surface as version 2. Don’t take an unversioned dependency!

Always try to provide at the very least a Major.Minor dependency in your descriptor. If you’re worried about the future and people being broken, this is exactly the reason for the Revision auto-update behaviour we’ve discussed earlier.

If a new version of a package comes out and doesn’t break your package, you can simply edit the package with a modified revision range, and people will get automatically updated next time they issue an update-wrap command.

Conclusion

Building packages is not an easy thing to do, and supporting multiple uncoordinated package managers is not easy either. If you follow these guidelines, you should however manage to build your packages correctly.

Ads

o create-blog -name “Hello World”

I have had a blog for a long time, and I’ll continue maintaining it for all the social events I organize in London. But When I was offered the chance to join the codebetter.com crew, there was no way I could say no.

I’m Sebastien Lambla, and I write two OSS frameworks you’ll hear about a lot: OpenRasta, one of the most popular ReSt and Web frameworks on .net, and OpenWrap, a package manager for .net. Expect big announcements very soon!

Ads