Table of Contents
Table of Contents
The project is in an early stage and you will probably not be able to compile it easily or use it for significant work. There are lots of things which are not documented yet, as they only work occasionally ;). As the current written code is only a framework, no real application of it yet exists, there are still much things to invent. Get involved.
This software package represents a meta program used to manage unix programs. It is a class library in the domain of system administration. It is similar to Microsoft .NET or corba or Unix as it is language independent. Indeed, a method can be written in any language, because the interface of a method is the same as that of a unix command. That means a method is passed an array of arguments, it has a standard input, standard output and standard error channel and returns a small integer exit code. The difference to a shell script is that there is no actual execve system call involved in calling a method, but the method is in a shared object that can be linked dynamically into the running process. With interpreted languages like perl, first the interpreter is dynamically linked into the current process which in turn executes the method written in the target language. That means that the second call of a certain method only involves some lookup in internal data structures to find the already loaded (c++, perl) and byte-compiled (perl) implementation.
But this is only half of the story. The power of object orientation to
a certain degree comes from the fact that you have abstract interfaces
and concrete implementations which are interchangeable to a certain extend.
This fact is still true of course, when you map the OO paradigm to
the Unix shell and the domain of system management. But unfortunately
this principle was not honored by the software that exists on posix
compatible systems so far. An example of an interface relating to
system management and configuration is internet server software configuration.
There a many ways to configure on which port a piece of software should
listen. In apache, you write Listen or BindAddress, the tcpserver from
ucspi-tcp expects a command line argument, the inetd superserver expects
it as the first column of a table in a free-form textfile.
It is therefore impossible to know where an arbitrary server listens
if you do not write specialized parser code for every configuration
file format in existence.
It would be so much easier to have an interface that has a method called
port
that you can call to either query the
port or set it.
Then you can call the exact same method on any server that implements the
interface and don't have to care about syntax rules.
That's a common concept to an OO Programmer.
Forum
There are some examples of object oriented concepts in current unix software that move towards object orientation. These approaches have two problems. First, they are developed by different designers and do not share a common model or structure. Second, they only implicitely implement an object model and do not provide things that are a common good in the OO world such as reflection or a meta class protocol. I will give examples on such implicit OO patterns found in current unix software.
The debian distribution offers kind of meta programs that one uses to configure the system in turn. One example is the update-inetd that adds, removes, disables or enables an internet server in your system and takes care of the difference between an xinetd configuration and an inetd configuration. One uses the exact same command regardless of the superserver used.
The apache web server and the proftp server share the same configuration file format. One uses the same syntactical constructs to configure features that both software systems equally provide, such as port configuration. Or seen the from the other side, the apache web server and the proftp server are two implementations of the same interface, which is the apache-style configuration file format.
This section describes the Object Model in its only existing current implementation, as a posix application.
A method call can be made from the shell prompt, simply by typing
the name of the method and arguments. Indeed, unix is already object
oriented, because one can type pwd to get the
current directory. Seen the object oriented way, the user just called
the method pwd
on the object that corresponds
to the current directory. If we see directories as objects, in the
standard unix model, every object would be of the same class, as
the set of methods that can be called is the same, independent of the
current directory. Of course this is not entirely true, because the
command make would behave differently depending
on the current directory. It depends on a file called
Makefile
. So one can see a directory containing a
Makefile
to be of the class that has a make
method in its interface specification.
Now consider changing the PATH
environment variable depending on information from the current directory.
There exists an environment variable called PROMPT_COMMAND
in the bash, that calls a command everytime a prompt is printed. Other
shells have similar facilities. When there is a directory called
.methods
in the current working dir, then one can
simply add $(pwd)/.methods to the current PATH
environment variable to change the set of commands/methods that can be
executed.
To make the previous paragraph clear, look at the fact, that even completions depend on the current object you are in, because you have another set of methods that you can call, you get some completions for them installed in the shell. These are removed as soon as you change your current object (cd to another direcotry). This installation of completions is of course done only, when the object is accessed via the shell on an interactive console.
The object model is comparable to javascript, because it is prototype based and does not make a distinction between class and object. But certain objects can be more used as a class than certain others just by not setting variables in them but using them only as a provider of methods.
There exists an implementation with a C++ core that can execute methods written in C++ efficiently (by loading a shared object), and also perl (by loading libperl.so dynamically) and javascript (by loading libmozjs). Methods can still be written in any language as long as it is possible to call execve(2) on some file.
It is possible to store the class data (superclass list, etc.) in a directory. It will be possible to store multiple classes in a single file, the implementation exists and has still bugs that make in unusable. Objects do not even need to be stored on disk, but can be created in RAM only by using a ramdisk, that is implemented using LD_PRELOAD and overrides stdio syscalls such as fopen, fread, fwrite, fseek. So it is possible to generate a bunch of objects from a /etc/fstab or /etc/passwd file on the fly and treat its contents as normal objects. The implementation for this feature exists but is still buggy.
There are different ways to store the variables of a class, one can write them into a file in the object directory or store all variables of all objects in a single flat file or dbm file. An sql schema will not exist unless one finds a reason to use a full blown database. An XML backend should be implemented, too.
Variables are simply methods that modify a backend store if called with extra arguments or print out a value from that backend store if called without extra args. Vector types support add, del, count, find and other operations. Table types support a limited subset of the semantics of SQL (WHERE clauses, field selection), but the syntactical interface is not SQL compatible and much less powerful.
The processing and compilation of method source files is handled by the framework. If the method source is well-formed, it is usually enough to execute compile-method <method-name>. In the more complicated case one has to write a class that handles the pecularities of a language to make the above mentioned possible. Adding a language is as easy as defining some file extensions and writing a method that generates a makefile that conforms to some specification of required make targets.
There is a reflection interface used to iterate through the methods and variables of a class and list their properties.
There is a navigation interface that allows you to do some tree operations on a tree of objects, such as finding siblings, children and ancestors. It is similar to xpath but of course much simpler.
Variables come in different types. These are for example string, vector, table, boolean.
drwxr-xr-x 11 sascha sascha 408 2005-07-21 18:51 . drwxr-xr-x 30 sascha sascha 976 2005-07-20 11:00 .. -rw-r--r-- 1 sascha sascha 171 2005-07-07 21:20 .bmemberstores boolean variables
-rw-r--r-- 1 sascha sascha 205 2005-06-26 21:21 .clsdescthe class documentation
drwxr-xr-x 3 sascha sascha 136 2005-06-28 11:27 .fmemberstores vector and table variables
drwxr-xr-x 4 sascha sascha 96 2005-05-24 23:07 .garbageabandoned source files are put here
drwxr-xr-x 4 sascha sascha 96 2005-05-24 23:07 .includeinclude files used by more than one method
-rw-r--r-- 1 sascha sascha 112 2005-07-20 10:34 .inheritthe list of superclasses
drwxr-xr-x 3 sascha sascha 592 2005-06-11 05:25 .methdscmethod documentation
drwxr-xr-x 3 sascha sascha 3,2K 2005-07-31 09:37 .methodscompiled methods
drwxr-xr-x 7 sascha sascha 168 2005-07-14 17:02 .methsrcmethod source files
drwxr-xr-x 3 sascha sascha 104 2005-07-06 11:34 .varidscvariables documentation
$ prompt
export DATADIRS="/home/sascha/dispatch/dispatch/core/docbook:/home/sascha/dispatch/dispatch/core-classes/universal:/home/sascha/dispatch/dispatch/core-classes/Universal/variable:/home/sascha/dispatch/dispatch/core-classes/Universal/navigation:/home/sascha/dispatch/dispatch/core-classes/Universal/reflection:/home/sascha/dispatch/dispatch/core-classes/Universal/loader:/home/sascha/dispatch/dispatch/core-classes/Universal/abbrev:/home/sascha/dispatch/dispatch/core-classes/methsrc:/home/sascha/dispatch/dispatch/core-classes/Methsrc/abbrev:/home/sascha/dispatch/dispatch/core-classes/operator:/home/sascha/dispatch/dispatch/core-classes/documentation:/home/sascha/dispatch/dispatch/core-classes/Documentation/builder:/objects/autoconf";
export DISPATCHPATHS="/home/sascha/dispatch/dispatch/core-classes/universal/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/variable/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/navigation/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/reflection/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/loader/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/abbrev/.methods:/home/sascha/dispatch/dispatch/core-classes/methsrc/.methods:/home/sascha/dispatch/dispatch/core-classes/Methsrc/abbrev/.methods:/home/sascha/dispatch/dispatch/core-classes/documentation/.methods:/home/sascha/dispatch/dispatch/core-classes/Documentation/builder/.methods:/objects/autoconf/.methods";
export DISPATCH_CWD="/home/sascha/dispatch/dispatch/core/docbook";
export PATH="/home/sascha/dispatch/dispatch/core-classes/universal/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/variable/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/navigation/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/reflection/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/loader/.methods:/home/sascha/dispatch/dispatch/core-classes/Universal/abbrev/.methods:/home/sascha/dispatch/dispatch/core-classes/methsrc/.methods:/home/sascha/dispatch/dispatch/core-classes/Methsrc/abbrev/.methods:/home/sascha/dispatch/dispatch/core-classes/documentation/.methods:/home/sascha/dispatch/dispatch/core-classes/Documentation/builder/.methods:/objects/autoconf/.methods:/home/sascha/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games::/sbin:/usr/sbin:/usr/local/sbin";
export DISPATCHVARS="DATADIRS DATADIRSATTR DISPATCHPATHS DISPATCH_CWD PATH";
if [ "$DISPATCHCOMPLETIONS" ]; then for c in $DISPATCHCOMPLETIONS; do complete -r $c; done; unset DISPATCHCOMPLETIONS; fi;
complete -C /home/sascha/dispatch/dispatch/core-classes/universal/.methods/complete-class @;
complete -C /home/sascha/dispatch/dispatch/core-classes/universal/.methods/complete-class cdo;
complete -C /home/sascha/dispatch/dispatch/core-classes/methsrc/.methods/complete-method-source cm;
complete -C /home/sascha/dispatch/dispatch/core-classes/methsrc/.methods/complete-method-source compile-method;
complete -C /home/sascha/dispatch/dispatch/core-classes/methsrc/.methods/complete-method-source source-cache-file;
complete -C /home/sascha/dispatch/dispatch/core-classes/methsrc/.methods/complete-method-source source-file-name;
complete -C /home/sascha/dispatch/dispatch/core-classes/documentation/.methods/complete-manpage oman;
complete -C /home/sascha/dispatch/dispatch/core-classes/documentation/.methods/complete-manpage edit-manpage;
export DISPATCHCOMPLETIONS="@ cdo cm compile-method source-cache-file source-file-name oman edit-manpage";
You can see a list of paths in the DATADIRS
variable. These are
the objects that add up to your current object. They are written in descending
order, from subclass to superclass, with the current object being the first
path in the list. The paths list is actually a flattened tree: multiple
inheritance is supported.
DISPATCH_CWD
is redundant and is still used but deprecated.
The PATH
variable is important to understand the concept of the
method dispatch.
You can see paths in this list that have the same base name as those in
DATADIRS
, but with a .methods
directory
added. When there is no .methods
directory, that
object occurs in the DATADIRS
, but not in the PATH
.
DISPATCHVARS
lists all modified variables again and is
probably redundant
DISPATCHCOMPLETIONS
lists the currently installed completions
and is probably not redundant, because as you can see it is actually used
to wipe out all old completions, before installing new ones.
The method@ object method [ args ] is used to invoke a method of an object that is not the current directory. It is roughly equivalent to cd object; method [ args ]
Most examples are not implemented yet.
$ @ Apt/stable install foopackage # call apt-get -c=... install foopackage
$ @ grub timeout 23 # change the timeout value in the grub configuration file
$ @ grub/linux-2.6.17 root '(hd2,3)' # set the root option of a specific grub entry
$ @ apache/inet port 80
$ @ proftpd/inet port 80
$ @ tty noecho
$ @ /etc/inetd.conf/telnet user baruser
There is a paper i wrote for my upcoming talk at the Chaos Communication Congress.
I also created some slides for the same talk.
There are classes and methods that deal with documentation. To view the
documentation of a given method or variable just call the method oman
,
which probably boils down to running the command
oman clsname in the shell (to view the documentation for
the clsname method, which is available in every object as it is from class
universal).
When you run oman
without arguments, you get a man page for the current
class. So you can run @ Universal/reflection oman to
get a documentation for that class.
Sourceforge Project Page - including forums, cvs, tarballs, news, etc.