WorkBench Developer's Guide

This is the source of information for developers working on WorkBench.

The contents will be enhanced and extended based in feed back sent to dev@pysvn.tigris.org.

Architecture

Threading

Workbench uses two threads.

The foreground thread operates the GUI and only fast operations should be performed in event handlers otherwise the responsiveness of the UI will suffer.

Slow operations are performed on a background thread. The background thread processes work that is added to a work queue.

No GUI operations are allowed to be performed on the background thread. This is because on some platforms the GUI will crash.

An event handler typcially needs to do some work on the foreground thread and some on the background thread.

Arranging to move between threads can involve a lot of code in the event handlers. However Workbench has greatly simplified the coding of event handlers by using using python generators.

The threading and event helper code is in wb_app.py and wb_background_thread.py. To understand the code you will need to be familier with the __call__() special method, how to call a function with arbitary args and keywords and python generators and the yield keyword.

Any event handler that needs access to the background thread is wrapped via the eventWrapper() function. An example from wb_frame.py:

wx.EVT_MENU( self, wb_ids.id_SP_History, self.app.eventWrapper( self.OnSpHistory ) )

The eventWrapper function wraps the self.OnSpHistory function inside an EventScheduling object.

Inside the event handler move to the background by:

yield self.app.backgroundProcess

And move to the foreground by:

yield self.app.foregroundProcess

The project_info object has two pysvn client objects, client_fg for use on the foreground thread and client_bg for use on the background thread. You must use the client object that matches the thread the code is running on otherwise pysvn will raise an exception that the it is already in use.

In this example from wb_subversion_list_handler_common.py you can see that the function yields to the background before calling annotate using the client_bg object. Then after annotate has completed the function yields to the foreground to do GUI operations, creating the AnnotateFrame.

Notice the use of the ok variable that carries status until the function is back in the foreground where it can react by calling appropiate GUI operations.

def Cmd_File_Annotate( self, all_rows ):
    for filename in [self.getFilename( row ) for row in all_rows]:
        self.app.setProgress( 'Annotating %(count)d', 0 )

        self.app.setAction( 'Annotate %s...' % filename )

        yield self.app.backgroundProcess

        ok = False
        try:
            annotation = self.project_info.client_bg.annotate( filename )
            ok = True
        except pysvn.ClientError, e:
            self.app.log_client_error( e )

        yield self.app.foregroundProcess

        if not ok:
            break

        h_frame = wb_subversion_annotate.AnnotateFrame( self.app, self.project_info, filename, annotation )
        h_frame.Show( True )

    self.app.clearProgress()
    self.app.setAction( 'Ready' )

Development

Code style

If you wish to contribute code to WorkBench please keep the style inline with the existing code.

Element Style Example
module name Lower case with underscore (_) to seperate words. wb_app.py
class Camel case with initial uppercase letter. class WbApp
def Camel case with initial lowercase letter. def setAction():
variables Lower case with underscore (_) to seperate words. current_file = 'a.txt'
plural variable names Use the all_ prefix for plural variables, do not append s, its to easy to confuse singluar with plural. all_files = []
Compare to None Always use is or is not to test a for None. Use of == can trigger unexpected calls to __eq__ and __cmp__ class methods. if status.entry is None:

Running WorkBench from SVN trunk

In the Sources folder run one of the make files to create the generated source files (wb_version.py and wb_images.py).

Unless you are trying to create binary images of WorkBench use:

make -f wb_common.mak wb_version.py wb_images.py

Now you can run WorkBench using one of the helper scripts.

PlatformCommand
Windowsrun_wb.cmd
Unixwb.sh
Mac OS Xrun_wb.sh

Debugging WorkBench

WorkBench has a number of features to aid debugging: