Extending bocca

Adding commands to bocca
Command-line concepts

bocca [options] action subcommand [suboptions] [positional arguments]

  • action is usually a verb, and at present is one of create, change, display, remove, rename
  • subcommand is usually a noun, and represents the project entity to which the action is applied and also the name of the module implementing the action interface. For example, bocca will support at least the following possibilities for subcommand: project, package, interface, class, port, component, library. See discussion of current implementation below.
  • Bocca, like cvs and subversion, has the idea of a working directory (tree), but unlike CVS and subversion a single directory on the file system is not limited to a single project or a single bocca tools version. This works because the metadata files encode the project as part of the filenames. The .bocca/ metadata dir can thus contain information for more than one project and even more than one version of bocca (provided the metadata scheme remains stable wrt filenaming).
  • We also define a second, visible, metadata subdirectory in the project tree, BOCCA (all caps, no period) which is used for storing metadata that can contain user-editable files and should be under revision control. It is used for storing defaults (user editable) in the projectName.defaults file, as well as for portable serializations of the project structure (not user editable). The hidden .bocca metadata directory is not meant to be under revision control.
  • Bocca commands are dispatched in a two-step scheme to insure that the correct bin and libraries get used even though the system bocca version may differ from the one used in a project.
    • Any 'bocca' script will hunt down the boccalib-PROJECTNAME installation of bocca that goes with the project in the working directory. If the project choice is ambiguous, bocca -p PROJECT can disambiguate it. (Note that current concensus is to not have project-specific boccalib installations.)
    • Once the right boccalib is located, the arguments are redispatched (without requoting or other evil transformation) to the script boccalib-PROJ/bin/cct which manages the subcommands in the canonical python dictionary dispatch. Before the dispatch, the canonical BOCCA_*, PATH, and PYTHON* environment variables are set.

  • bocca create project PROJECTNAME is the entry point to the system. Until this is done, nothing else should work. This is like the CVS init or the first CVS checkout. It takes an option for the project template (defaulting to make-tut-0.5).

  • Multiple build templates We should (eventually) be able to take the same bocca metadata files and generate entirely different build systems (autotools, scons, etc). To this end I set up the template structure in boccalib. Expect that with each template set there's going to be a corresponding set of specific python tooling. For example we have templates/make-tut-0.5 (the current approximation) and there should probably be a matching boccalib/template-utils/make-tut-0.5/*.py for anything which turns out to be nongeneric across all build templates.

Intuitive use is not dumb (software is)
  • bocca clones
    • tree cloning: Copying an entire project tree must be legal and not write into the old tree on subsequent operations, which means no encoding absolute paths anywhere in python or the metadata except to external entities (babel).
    • component cloning: Copying the directory of a specific component to create a new component within an existing project. E.g. cp -r foo_ComponentA foo_ComponentB. The metadata will be incorrect. We cannot stop people from trying. We can detect that they did it and indeed we do check for directory cloning in the bocca script and refuse to proceed. We must have a 'clone component' subcommand of bocca.
    • project mixing: Overlays are good. Support creating more than one project in the same directory or even more impressive nesting distinct projects in the same directory hierarchy. This is the first thing any naive CVS user tries to do. By introducing the PROJECTNAME explicitly in metadata filenames, we can support this trivially. The bocca dispatcher handles this case; we must make sure any metadata files are structured as well.

Subcommand implementation
  • Every bocca subcommand (a.k.a. noun) is represented by a file in boccalib/cct/. Files in boccalib/cct/ which are NOT subcommands should have names that start with one underscore, like _validate.py. Care should be taken in the definition of the suboptions to avoid confusing the heck out of the user if possible. Each subcommand should be in a file with the name of the subcommand, containing a package with the same name, but capitalized, e.g., project.py contains class Project. This is something the dispatchers relies on when dispatching commands.
  • The easiest way to create a new subcommand is to copy the example stub boccalib/cct/example.py and modify it as needed. Things to note that we should do.
    • Stick to optparse as much as possible. It gets us the help system for free and puts a nice clean syntactic model on the commands. The BVertex class creates the parser and invokes defineArgs and processArgs methods that each subcommand implements — this is pretty minimal amount of effort that gives us uniform command-line parsing.
    • The -d option of the bocca (bocca -d action subcommand [suboptions]) turns on the debugging flag; please follow the example for print statement debugging, i.e.:

from cct._debug import *
...
print >>DEBUGSTREAM, 'Some debugging info'

    • Document the subcommand (noun) file and each action it implements following the the python docstring standard. The help system depends on this.
    • Note that our stuff should all be in subdirectories of boccapy/boccalib-- creating scripts in the package top of boccalib corresponds to polluting the global namespace of python, a rather antisocial thing to do. Similarly all the loose scripts from proto/bin and util/ need to be migrated and reformed into subcommands or we end up with a horribly polluted Unix PATH; that's the whole point of having a dispatcher named bocca.
  • Example: the following bocca commands result in the dependency structure visualized below.

bocca create project testproj1
cd testproj1
bocca create interface bocca.test.SomeInterface
bocca create interface --extends bocca.test.SomeInterface bocca.test.SomeOtherInterface
bocca create port bocca.test.APort
bocca create port --extends bocca.test.SomeInterface --extends bocca.test.APort bocca.test.AnotherPort
bocca display project

Resulting graph:

img/wiki_up//Picture 1.png

Generated SIDL files in testproj1/ports/sidl:

bocca.test.APort.sidl
bocca.test.AnotherPort.sidl
bocca.test.SomeInterface.sidl
bocca.test.SomeOtherInterface.sidl

Editing cycle
We can build/edit in place thanks to the goodness of python. An example.
  • ./configure --with-babel-config=/home/test/babel_testing/install-104-pgf/bin/babel-config --prefix=`pwd`/install
  • make install
  • Open an emacs or window in boccalib/cct in which to edit subcommands.
  • In the first window do the cycle: (make install; install/bin/bocca -d testARGS) between edits. The make install is trivial.
  • Bear in mind of course that you need to take care not to have bocca declare the source tree to itself be a bocca project, that is, only run bocca commands in a directory that is not part of the boccapy sources.


Created by: baallan last modification: Monday 16 of April, 2007 [18:15:16 UTC] by norris

The original document is available at http://www.cca-forum.org/wiki/tiki-index.php?page=Extending%20bocca