Demonstration: version resolution

There are essentially two aspects to Refix. One is the management of a repository of binary dependencies, which exists both locally and remotely, in a hierarchy of remote repositories if necessary. This is inspired by the Java tool Maven, and because it is conceptually familiar, we'll gloss over this for now and look instead at the other aspect - resolving version conflicts between binary dependencies. You'll see a little of the repository side of things on the way.

A broken solution

In the source code for Refix you'll find a test solution (Refix.TestSolution) which is about as broken as can be for a solution this small. It comprises four project, one of which is a simple console application that we can use to demonstrate both its brokenness and the power of Refix. Let's see what happens if we try to build the solution and run the application - I'm going to use MSBuild from the command line so we can capture everything in one window, and I'm going to restrict its output to warnings because, even in its broken state MSBuild lets it compile without error.

Screen shot 2010-06-14 at 07.05.06.png

As you can see, the solution has compiled, although MSBuild warned about conflicting versions. But when we try to run the console application, we get a FileLoadException trying to load a particular version of the assembly Refix.Test.A. The first thing we can demonstrate with Refix is exactly what state our solution is in before we start. To do this, we run two simple Refix commands. rfx extract extracts information about dependencies into Refix's own dependency files, which sit alongside each the project file. Don't worry, it provides a way to clean these up as well, and the existing files have not been touched at this stage. rfx visualize then produces a console visualisation of the solution and its dependencies.

Screen shot 2010-06-14 at 07.05.29.png

A brief view of the repository

You can see that there are two binary assemblies in play here, Refix.Test.A and Refix.Test.B, in a variety of version numbers. You'll find these assemblies under the .testrefixrepo folder in the root of the solution - this will also give you an idea of the repository structure that Refix uses.

Screen shot 2010-06-14 at 07.42.10.png

Here's an example repository metadata file, in this case for Refix.Test.B.

Screen shot 2010-06-14 at 07.18.15.png

You can see here that one of the versions of Refix.Test.B has an alternative version marked - version can be replaced with any subsequent 0.1.0.x version, a typical case of a backwardly compatible assembly. As things stand, Refix.Test.A has no such compatibility marked in the repository, and as we're about to see this causes us some problems.

First (failed) attempt to resolve

Let's see what Refix can do for us on this broken test solution by running the rfx prebuild command.

Screen shot 2010-06-14 at 07.06.08.png

This isn't very informative, so we'll run it again with the --graph option specified - rfx prebuild --graph. You'll notice, by the way, that all the screenshots use the terse form of the commands (e.g. rfx pre -g here), whereas in the text I give the full versions. These are fully interchangeable. Here's the output:

Screen shot 2010-06-14 at 07.06.33.png

Where version of Refix.Test.B was being referenced by a project, Refix has elected to use version instead. We've told it that this is a compatible version and so is allowed. For Refix.Test.A, this removes version from the picture altogether, but Refix is still unable to reconcile the two versions and, because it doesn't know if either is compatible with the other. This is highlighted in red.

Second attempt - successful if unrealistic

We're going to go ahead and tell Refix that version is forward compatible (slightly unrealistic, I know, but bear with us - this is a demo after all, and we'll come back to a more realistic assumption shortly). We issue an rfx alternative command, then run rfx prebuild again.

Screen shot 2010-06-14 at 07.07.27.png

Everything is now green, and you'll see that Refix has actually rewritten the four project files in the solution to take account of this. What is less clear is that having resolved a single compatible set of binary versions, it has placed a copy of each of them (with all dependencies) into a .refix folder in the root of our test solution, and this is where the HintPath in each project file now points. Again, don't panic - this is all reversible. Backup copies have been taken of all the files that have been changed.

Third attempt - successful and realistic

Let's revert to the backed up copies and clean all traces of Refix having been used with the refix clean --all command, before removing our forward compatible version of Refix.Test.A from the repository and inserting a slightly more realistic backward compatibility for that assembly:

Screen shot 2010-06-14 at 07.08.16.png

Refix should still be able to resolve all the versions in use in the assembly, but now its task is slightly more complicated. Let's take a look at the output of rfx prebuild --graph now.

Screen shot 2010-06-14 at 07.08.34.png

Success again, but notice that some yellow has crept into our graph. This indicates the need for a version change in a binary dependency of a binary reference. We can't do this simply by rewriting the project files, and so we need to use assembly binding redirection to point Refix.Test.B version at Refix.Test.A version instead of And the summary at the bottom shows us that Refix has done exactly that - it has inserted this element into application configuration files throughout the solution (including in the console application, which doesn't reference Refix.Test.B directly at all). Again, everything is backed up and can be reliable cleaned up afterwards. If Refix added a configuration file, it deletes it again; if it just added an element to it, it restores from a backup.

Wrapping it all up

OK, let's wrap it up by trying to build and run our newly Refixed solution. Here's the output of the same MSBuild command and the console application now:

Screen shot 2010-06-14 at 07.09.12.png

The solution compiles with no warnings, and the console application runs fine. The output shows that versions of both Refix.Test.A and Refix.Test.B are the only versions being used. Refix has successfully resolved the dependencies, tidied up our project files, and written any necessary assembly binding redirects for us. Because the references are now all pointing to a folder Refix has created, you don't need to commit any binary dependencies to your source control repository - just tell any developer who wants to work on your project to use Refix and, if necessary, the address of the remote Refix repository you connect to.

Finally, we clean up after ourselves, removing all traces of Refix having been involved by running rfx clean --all --verbose. We include the --verbose option this time so you can see exactly what Refix is cleaning up. We also run refix alternative again to clean up the compatible version we put into the test repository.

Screen shot 2010-06-14 at 07.36.48.png

Last edited Jun 14, 2010 at 7:55 AM by davidmus, version 4


No comments yet.