In my previous post, I promised an update on the status of horn. I need to stay focused and have my eye on the prize this time round.
While developing horn recently we reached quite a puzzling impasse with the interesting dependency map that exists between Nhibernate and castle. The problem is that Nhibernate references castle and castle references Nhibernate.
When upgrading my OSS stack, these are the sequence of steps I perform in order to build this troublesome dependency map:
- Build Castle.DynamicProxy2 and copy the output to the Nhibernate bin directory
- Build Nhibernate and copy to the castle bin directory
- Build castle
note: Here is an overveiw of the horn DSL..
A long debate ensued on the Horn user group and we eventually reached a consensus that we had to somehow split the castle code base up in such a way that we could build individual parts of the castle source and thus avoid the circular reference. The castle code base is quite a beast as anyone who has ever performed an svn update or check out will testify, there are a lot of interwoven, inter-project dependencies between this behemoth of a solution. We needed someway of building the castle.DynamicProxy2.dll and any dependencies it might have on the code base. The default.build nant file that builds the castle source code was written to build all projects and has no hooks for building sub-projects. We would need some underhand tactics and some more Dsl trickery to somehow change the castle nant build script with changes of our own.
Here is the Dsl descriptor which houses the instructions that is needed to build the newly birthed castle.tools package that will produce the Castle.DynamicProxy2.dll as part of its output.
1install castle.tools:
2 description "Dynamic Proxy Generator for the CLR."
3
4 prebuild:
5 cmd "xcopy /s /y \"../Patch\" ."
6
7 include:
8 repository(castle, part("Tools"), to("Tools"))
9 repository(castle, part("Core"), to("Core"))
10 repository(castle, part("common.xml"), to("common.xml"))
11 repository(castle, part("common-project.xml"), to("common-project.xml"))
12 repository(castle, part("CastleKey.snk"), to("CastleKey.snk"))
13
14 build_with nant, buildfile("Tools/Tools.build"), FrameworkVersion35
15
16 switches:
17 parameters "sign=true","common.testrunner.enabled=false", "common.silverlight=false"
18
19 shared_library "SharedLibs/net/2.0"
20 output "build/net-3.5/debug"
21
22 package.homepage = "http://www.castleproject.org/"
23 package.forum = "http://groups.google.co.uk/group/castle-project-users?hl=en"
The first point of interest in this Dsl instance is at lines line 4 and 5
4 prebuild:
5 cmd "xcopy /s /y \"../Patch\" ."
A prebuild block was authored that gets parsed into the horn metamodel. Put simply, the code will attempt to execute any DOS commands that are placed in the prebuild block. This is a very temporary measure as the scope for danger is big if we let users enter their own DOS commands here. We will replace them with actual Dsl instructions at a later refactoring and when we know exactly what to create.
The intention of the xcopy is to patch the castle nant files with modifications we made that allow us to build this fragment of the castle code. We are acutally quite crudelly copying modified copies of the nant files over the freshly retieved real castle files. Crude as it is, it really was the only way bar petitioning the good people of castle to change their code or allow us to supply patches. This was quicker and more polite.
I then went leftfield and made a refactoring that is described in the include block of code:
7 include:
8 repository(castle, part("Tools"), to("Tools"))
9 repository(castle, part("Core"), to("Core"))
10 repository(castle, part("common.xml"), to("common.xml"))
11 repository(castle, part("common-project.xml"), to("common-project.xml"))
12 repository(castle, part("CastleKey.snk"), to("CastleKey.snk"))
The include block contains instructions of what parts of which project we want to build. We can retrieve directories or files from what has been christened a repository.
A repository in the context of horn is a node in the horn package tree that can be thought of as the whole of the code base. In this example it is the entirity of the castle trunk. All the parts are retrieved from the castle package tree node. The castle package tree node or repository will synchronise itself with the remote svn repository if the code is out of date. This opens up the opportunity of pulling together different parts of different repositories into more interesting and user defined builds.
The moral of this story is that although we were at first hit with a very difficult problem, the solution ended up opening up many opportunities for horn. I was quickly able to add a further build descriptor for castle.windsor.
The net result is that we are able to build Nhibernate and the relevant parts of castle. Next up, I want to tackle the infamous Rhino stack. Manually building Rhino is one of the reasons I was keen to tackle horn. I have had more problems building this stack than any other, much as I love the end result. This is a fight I intend to win by hook or by crook.
On a selfish note, I really like the way horn Dsl has evolved but then, I would.
The funny thing is, just after completing this work, the castle developers started debating splitting the castle code base as is discussed in this thread.
If anybody from castle is reading this thread then they should consider using horn as a means of pulling their split up stack together and building.
If any of this is of interest to you then please join the Horn user group for updates or check out the source here.
We had the same discussion on the Castle development mailing list the end of last year about splitting up the projects properly, but there was no real decision made so it stayed as it is today.
ReplyDeleteThere are several Castle committers signed up watching the Horn development. We will keep horn on our minds while we discuss these changes.
As long as you guys are monitoring the project then that is good.
ReplyDeleteIn the mean time, I will try and push the feature set.
So little time and so much development to be done.