Thursday, April 13, 2006

 

Justin Finnerty's "desync" package

Justin Finnerty created his Eiffel Struggle entry desync because he wanted to clean up duplicate files left behind by his replication of directories. Justin had been using rsync to replicate working directories and backups - but tools such as rsync use simple criteria (such as name and timestamp) to identify the files to manage, so over a period of time some cruft had accumulated. Desync helps to sort out this cruft.

It wasn't Justin's application itself that caught my interest (because I use subversion and darcs to replicate working directories, and rsync-backup to replicate backup directories, so I don't have the problems that desync fixes).

What caught my interest was the range of programming and packaging techniques that Justin had employed.

Installation is handled by the Gnu autoconf three-step: ./configure, make, sudo make install. The configure command checks to see which Eiffel compiler you have, where GOBO is located, etc, and builds the appropriate makefile. You then invoke make twice - once to build the system and once to install it. If you have more than one Eiffel compiler, you can tell configure which one to use.

Test cases are provided so that you can confirm that desync is working after you build it but before you install it.

The makefile is comprehensive, including targets for uninstall, clean, distclean, etc. There are also targets for building development versions, and for automating the process of switching the Eiffel compiler that you are using.

Desync uses the GOBO package in three different ways:
  1. The GOBO libraries are used for their vendor-independence,
  2. GOBO's xace files handle the Eiffel side of the build, and
  3. GOBO's gepp preprocessor is used to workaround differences in the syntax accepted by different Eiffel compilers.
If you haven't seen gepp at work, it takes a file with suffix ".ge" and preprocesses it, leaving the result in a corresponding ".e" file. Preprocessor directives can be used to conditionally include code. For example, the following fragment includes the "insert" keyword only if SmartEiffel is the target:
inherit
SYNCHRONISED_DIRECTORY
#ifdef SE
insert
#endif
DT_SHARED_SYSTEM_CLOCK
KL_SHARED_STANDARD_FILES
KL_SHARED_FILE_SYSTEM
On the Eiffel side, Justin needed to provide some utility classes that support his application. There's a small cluster to implement "agent" functionality that is not available in Visual Eiffel. There's also a "collection" cluster with some interesting data structures including quadlinks - nodes that may be linked to other nodes that are above, below, to the left or to the right. A "configuration" cluster brings together command-line option handling, help messages and reading of the configuration file. A "file system objects" cluster takes care of filesystem properties (such as symbolic links). There are also some FACTORY classes, and a logging/reporting framework.

SmartEiffel's Observer classes did what Justin needed, so he modified them for use by other compilers.

For documentation, Justin has used Aurelio Jargas's txt2tags utility, which generates "man pages" and HTML pages from lightly-marked-up textfiles.

That adds up to a lot of interesting tools, techniques and technologies that Justin has used, above and beyond the Eiffel code of his core application.

Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?