Description of the headless booting sequence (Buckminster)
Below is a reasonably current version of an early design document for Buckminster Headless, describing reasons why the boot process, in particular, is somewhat convoluted. Note that some details in current implementation may differ from this description.
Goal: Buckminster must be possible to run from the command line, a.k.a. headless
Effectively, there should be a reasonable set of commands to do many of the relevant things you can do with Buckminster for two main reasons:
- To allow automation of things that you would otherwise be required to do interactively in the Eclipse IDE.
- Allow someone who absolutely does not wish to use the Eclipse IDE at all, a way to at least set up and work with a workspace with the help of Buckminster for further use with other tools (e.g. Emacs).
This mechanism will be supplied in two forms:
- An ordinary Buckminster feature/plugin set for installation into an Eclipse IDE instance will also more or less automatically allow the headless invocations to be done using that instance.
- A self-contained package of Buckminster with just as much of the Eclipse infrastructure and plugins/features required to run. I.e. this is a 'product' in Eclipse parlance.
Apart from the UI aspects present in the first form, the two forms should perform identically in core functionality. However, as both forms are bona fide Eclipse instances, optional plugins/features can be installed and make behavior and available mechanisms differ.
Not surprisingly, there are a number of challenges to overcome in order to make it work smoothly for the end user in various settings; differing platforms etc. Also, from a look-and-feel perspective the commands should behave exactly as any other command line tool - scriptable, transparent stdout/in/err handling etc.
Look and feel
Here we will focus on how the user perceives the command line.
A common pattern suggested for adoption is the 'launcher + command' pattern. This is evidenced by various product toolsets such as 'cleartool', 'p4', 'cvs' just to name a few.
Basically, there is the 'launcher'. The launcher can accept a number of option flags, which controls the launch and/or provides settings for a common context that all installed commands can make use of. As the launcher parses its command line, it may eventually hit on a non-option argument - this should be treated as the command name. The command name can also have option flags, and/or arguments. As this is still a part of the full command line seen by the launcher, it is the launchers responsibility to internally look up the implementation for the command and dispatch control to it, providing the rest of the command line in a suitable fashion for command parsing.
Thus, a format for using the launcher is something like this:
launcher [launcher-options] [command] [command-options]
Beyond the split between launcher-options v.s. command-options, from a user perspective it should be essentially opaque as to which options are parsed/handled where. In the general case, there should be no required order options must be specified in.
For Buckminster, there should be a launcher that is accessed by simple typing 'buckminster'. This should work on any supported platform.
The format for how to give options will benefit from following some form of common convention, and above all, be consistent (equally applies to both launcher-options and command-options).
A suggestion is to go with the convention of using one letter option names with one dash, and arbitrarily long (but abbreviatable) option names with two dashes. These two variants can be used interchangeably (or the developer only adds recognition of one of them). There is no implied correspondence with the short form letter and the initial letter in the long version.
An example from 'ls':
C:\tmp>ls --help Usage: ls [OPTION]... [PATH]... -A, --almost-all do not list implied . and .. -a, --all do not hide entries starting with . -B, --ignore-backups do not list implied entries ending with ~ -b, --escape print octal escapes for nongraphic characters -C list entries by columns -c sort by change time; with -l: show ctime -D, --dired generate output well suited to Emacs' dired mode -d, --directory list directory entries instead of contents -F, --classify append a character for typing each entry -f do not sort, enable -aU, disable -lst --format=WORD across -x, commas -m, horizontal -x, long -l, single-column -1, verbose -l, vertical -C --full-time list both full date and full time
Option names are always case-sensitive though.
The ultimate objective is to reach the org.eclipse.buckminster.cmdline plugin, more specifically its 'application' extension point. It is this entry point that gains control and which will interpret and handle (many, but not all, see below) launcher-options and then recognize any command name and dispatch to that, presenting it with the command-options only.
There are a number of design limitations arising from the use of Eclipse as the environment to work in, making the final solution somewhat convoluted.
First, on Windows, any direct use of the 'eclipse.exe' is not possible. It has a few main flaws:
- It is linked as a 'windows' application. This means it will start as a GUI application, i.e. no stdin/stdout, as well as having the effect of returning control to the calling application (the shell, typically) as soon as it is running under the control of the GUI. Also, it will eventually spawn 'javaw' instead of 'java' which are similar in problems. All this is unacceptable for a command-line tool, obviously.
- Even if this flag is switched to being a 'console' application, it further exhibits issues in not properly managing stdin/out/err to any child process as well as not propagating a child process exit code to callers. These are also serious impediments to a command-line tool.
An alternative to using the Eclipse supplied executable is to call the same things it does. The really important thing it does is actually calling a java 'main' entry point in the supplied startup.jar. Thus, the same thing can easily be done directly, approximately like this:
java -jar startup.jar [launcher options] command [command options]
This approach works fairly well since:
- All normal eclipse boot options are supported, i.e. -clean, -data, etc.
- No conflicts will arise since buckminster uses two dashes (i.e. --clean) in case of long names.
- It is completely platform independent.
What's missing is perhaps a more generic launcher that allows us to write:
buckminster [launcher options] command [command options]
and perhaps also be able to do what the normal Eclipse launcher does, i.e:
buckminster [-vm <path to java binary>] [launcher options] command [command options] [-vmargs vmargs]
Buckminster currently supplies two launcher scripts. One for Windows (a normal .bat file) and one that can be run by a bourne shell (works on all Linux and Unix platforms). The script will trap the -vm option and also consider everything after a -vmoptions to be options to pass to the java vm. The normal Eclipse launcher will also require putting the -vmoptions last.
Aside from the normal Eclipse launcher options, Buckminster will also recognize the following:
|--displaystacktrace||To avoid frightening the average user with really ugly output for sometimes very harmless errors, APPEXT won't print full stacktraces. This can be turned on with this option.|
|--help||Prints help information|
|--loglevel <level>||Sets the log level. Valid choices are debug,info,warning,and error|
|--eclipseloglevel <level>||Sets the eclipse log level. Valid choices are debug,info,warning,and error|
|--scriptfile <name of file>||Execute commands found in a file|
|--trapeclipselogger||Turns on trapping of the regular Eclipse log|
|--notrapctrlc||Turns off the ctrl-c handler|
Command names follow a namespace mechanism, as usual to avoid clashes in case more than one command wants to be known as 'foo'. The namespace for a given command is usually the same namespace as the enveloping plugin, but a plugin can also add levels to the namespace in case it wants to group commands inside it - this is all described in the extension point.
But also as usual, users dislike typing so much - thus, Buckminster will attempt to match command names bottom up; as long as there's only one possible match, Buckminster is happy and will dispatch. But, if collisions arise, the user may need to become specific. E.g. the commands com.domain_a.pluginX.foo and com.domain_b.pluginY.foo can't be reached as 'foo'; they will have to be used as 'pluginX.foo' and 'pluginY.foo' respectively (or, obviously using the full names).
Finally, a command can in the extension-point define one or more alias names; such names are also subject to the namespace.