Some Notions Regarding Application Directories

Site: Home | LnBlog | The Joy of ROX | LinLog

The Joy of ROX: Main | News | Software | Wrappers and Resources | Contact


Some Ideas on Application Directories

By Peter A. Geer, Copyright (c) 2003

Making and distributing verbatim copies of this paper is permited, provided that the copyright notice and this notice are maintained.

This paper is just a collection of some of the ideas regarding the construction of AppDirs that I've been mulling over. It's half a problem list and half a wish list. Make of it what you will.

Command-line Support

AppDirs, being a product of ROX, are naturally biased toward graphical programs. Seeing how ROX only runs in a graphical environment, this isn't a particularly startling revalation. However, AppDirs are also a means of packaging software, and not all of that software has a GUI interface. In addition, some of that software is of the type you might want to run when you don't have access to a GUI.

The Problem

This hit me when I repackaged RealVNC as an AppDir. RealVNC comes with several executables, and it doesn't really make much sense to make an AppDir for each one, so I put them all in the same AppDir. Now, I normally start a VNC session by logging into the remote system via SSH and running vncserver. Since the vncserver executable resides in the AppDir, I need to start it from the command line. I can't rely on support from ROX-Filer, as I don't yet have a display on which for it to run. The other obvious choice is to apply Stephen Watson's AppDir support patch to BASH. Of course, this only works if you want to use BASH and want to actually patch the shell. If I want to use csh or ksh, I'm out of luck. (As chance would have it, I do use bash, but I don't really want to patch the shell myself.)

So how's a body supposed to run vncserver from an SSH session? Obviously you can always run /usr/apps/RealVNC/Linux-ix86/vncserver, but that's a very long path and is about the ugliest solution I could come up with. Sure, it works for programs you only run once every forth blue moon, but you don't want to do that for a program you run every day. Isn't that the entire reason we have a command search path? You could symlink /usr/apps/RealVNC/Linux-ix86/vncserver to /usr/bin/vncserver, but that isn't really much better and it doesn't work if any of the programs require any environment variables that are set in AppRun. It also bypasses any cool customizations in the AppRun and requires additional effort if you have binaries for more than one platform in the AppDir.

The Solution

I came up with a couple of solutions to this. The first is to create some new options for the AppRun. These options are --exec and --lsexec. The --exec option will run a binary in your binary directory and pass it any options left over on the command line. The --lsexec option simply performs an ls on the binary directory so that you can see what you can run. This solution allows us to leverage the AppRun script to do any setup and to determine the correct platform. We can even symlink the AppRun to something like /usr/bin/vnc to make running it even easier.

The second solution I came up with is to allow links to AppRun with the same name as the executables in the binary directory. So, for example, we can link /usr/apps/RealVNC/AppRun to /usr/bin/vncserver, /usr/bin/vncviewer, etc. The AppRun script will examine $0 and run the binary in the binary directory with the same name, passing it all the command-line arguments. This is pretty much the same deal as the other solution, but it requirse more symlinks and less special syntax.

The Complications

There were a couple of complications involved in these solutions. First, there was the fact that we're making a symlink to AppRun. This might not seem like a complication until you think about the code in the typical AppRun. The binary directory is built from the platform name and $APP_DIR. $APP_DIR is retrieved using code like this: APP_DIR=`dirname "$0"` APP_DIR=`cd $APP_DIR;pwd` export APP_DIRThe particularly astute reader will realize immediately that the problem is the dirname command. When $0 is /usr/bin/vnc, dirname "$0" will return /usr/bin. However, the AppDir is actually /usr/apps/RealVNC, and it is this path that we need in order to get the binary directory. The problem is that UNIX provides no easy way to get to the real path of a linked executable.

I could come up with only two solutions to this problem. The first, and the one I prefer, is two lines of in-line Python that uses a function called realpath to print out the path to the actual file. The only problem I can think of with regard to this solution is that it requires Python 2.2 or greater, which adds a more or less unnecessary dependency to the AppDir. On the other hand, a good deal of the ROX applications that most of the AppDir users probably use, such as Wallpaper, Archive, and others, all require Python, so I guess this isn't all that unreasonable as a requirement. In addition, we can always check for the presence and version of Python in the shell script, so it's not like a user without it is completely out of luck. He just can't make symlinks to AppRun.

The other solution, which I have yet to implement, involves a whole lot of complicated shell. We would need to test if $0 is a symlink and then determine the real path using some brain-damaged method like piping the output of ls -l into sed and grep. Needless to say, this is bound to be buggy and fail in unpredictable ways on different flavors of UNIX due to its dependency on the output format of ls -l. And, as the UNIX Haters Handbook tells us, there is a "profound truism" that goes, "Some people, when confronted with a Unix problem, think "I know, I'll use sed. Now they have two problems."

The Choices System

The Choices system is an attractive alternative to the hundred million dot files in $HOME that we're all used to. Unfortunately, in my adventures repackaging applications as AppDirs, I've found that converting existing applications to use the Choices system is more trouble than it's worth. To do it right, you need to patch the program itself. Depending on the program, this can be trivial or a big pain in the rear-end. It can also create a problem of scale: maintaining five patch-kits is no problem for one person, but maintaining 50 can eat up a lot of time - especially if some of them need to be updated frequently. Plus you have to tell your users that you've changed the location of the configuration files, which means that either the user needs to migrate any existing files to the new location by hand, or your AppDir has to offer to do it for him. Not to mention the fact that you're just screwed if any other application depends on reading the configuration data from a particular place.

And what happens if our user decides that ROX actually kind of sucks and he's going back to KDE? Or what if he wants to mount his home directory via NFS and not all the systems on the network have ROX on them? Or maybe they have ROX, but they also have conventional installs of some of the programs we've repackaged. Or perhaps we're just too slow repackaging the latest, greatest version of our intrepid user's favorite program and he decides to grab an RPM instead. In any of these situations, the user has to copy his configuration data back to the conventional dot file and/or directories. If he's lucky, he'll even remember to do this right away instead of sitting there wondering what happened to his settings.

One obvious alternative is to put the actual data in the user's Choices directory and symlink the appropriate dot directory to that. Of course, some programs have both a dot file and a dot directory, so that isn't quite as perfect as one might hope. And with this method, instead of having one directory ($HOME) clogged with config files and program directories, you now have two. One of them just happens to be mostly symlinks, which really isn't an improvement.

Choices and the Command Line

In repackaging programs as AppDirs, I mostly use the Choices system for storing information used by the AppRun script. For example, I might have a toggle on a game AppDir to run with or without sound and save the choice in the Choices directory to be used as the default in the future. Right now, my system of storing and retrieving choices is very, very primitive. To save a choice, I echo the value of a shell variable into a file in the program Choices directory. To retrieve a value, I cat the corresponding file in the Choices directory and assign the output to a shell variable.

Needless to say, this system sucks. It works, but that's about the only thing it has going for it. I would very much like to change over to an XML based system, but I just haven't had a chance to write a program for that. And even if I did, my choices are limited. I could write it in C and distribute it as a dependency to all my repackaged AppDirs, but that's a big pain in the neck. Nobody wants to have to download a set of utilities in order to run one stinking program. Alternatively, I could write it in Perl or Python, which would not require compilation and would thus allow me to distribute it right in the AppDir. However, it would require that the user have Perl/Python installed and also have the correct XML parser module. This has the potential to be painful as well. If I ever get around to doing this, I'm thinking the best path is to use Python. Many ROX applications, such as Archive, require Python, so it's more likely to be on most users' systems already. In addition, Python comes with its own XML parsing module which, hopefully, is part of the standard installation on most systems. (I do recall having problems with ROX Memo using the Python package from Slackware Linux 8.0 or so. I don't know if the problem was with Memo or the Python package, though.)

Programs I'd Like to See/Write

You may have noticed the ROX-CLI link on my resources page. This was something of an attempt to address this.