diff --git a/SConstruct b/SConstruct
deleted file mode 100644
index aa3fd85bd440876410572aa052b48720bcc54b6c..0000000000000000000000000000000000000000
--- a/SConstruct
+++ /dev/null
@@ -1,46 +0,0 @@
-import re
-import os
-import sys
-
-import yaml
-
-from git_util import GitUtil
-from path_helpers import path
-
-
-def get_plugin_version():
-    version = GitUtil(None).describe()
-    m = re.search('^v(?P<major>\d+)\.(?P<minor>\d+)(-(?P<micro>\d+))?', version)
-    if m.group('micro'):
-        micro = m.group('micro')
-    else:
-        micro = '0'
-    version_string = "%s.%s.%s" % (m.group('major'),
-            m.group('minor'), micro)
-    return version_string
-
-
-SOFTWARE_VERSION = get_plugin_version()
-env = Environment(tools = ["default", "disttar"],
-        DISTTAR_EXCLUDEDIRS=['.git'],
-        DISTTAR_EXCLUDERES=[r'\.sconsign\.dblite'],
-        DISTTAR_EXCLUDEEXTS=['.gz', '.pyc', '.tgz', '.swp'])
-
-plugin_root = path('.').abspath()
-properties_target = plugin_root.joinpath('properties.yml')
-properties = {'plugin_name': 'wheeler.%s' % plugin_root.name,
-              'package_name': str(plugin_root.name),
-              'version': SOFTWARE_VERSION}
-properties_target.write_bytes(yaml.dump(properties))
-archive_name = '%s-%s.tar.gz' % (properties['package_name'], SOFTWARE_VERSION)
-
-# This will build an archive using what ever DISTTAR_FORMAT that is set.
-tar = env.DistTar('%s' % properties['package_name'], [env.Dir('#')])
-renamed_tar = env.Command(env.File(archive_name), None,
-        Move(archive_name, tar[0]))
-Depends(renamed_tar, tar)
-Clean(renamed_tar, tar)
-
-if 'PLUGIN_ARCHIVE_DIR' in os.environ:
-    target_archive_dir = os.environ['PLUGIN_ARCHIVE_DIR']
-    Install(target_archive_dir, renamed_tar)
diff --git a/__init__.py b/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c97ea66c3321fdd97f01b8647508d69931d5b29 100644
--- a/__init__.py
+++ b/__init__.py
@@ -0,0 +1,172 @@
+"""
+Copyright 2011 Ryan Fobel
+
+This file is part of dmf_control_board.
+
+dmf_control_board is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+dmf_control_board is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with dmf_control_board.  If not, see <http://www.gnu.org/licenses/>.
+"""
+from collections import OrderedDict
+from datetime import datetime
+
+import gtk
+import zmq
+from flatland import String, Boolean, Float, Form
+from logger import logger
+from gui.protocol_grid_controller import ProtocolGridController
+from plugin_helpers import (AppDataController, StepOptionsController,
+                            get_plugin_info)
+from plugin_manager import (IPlugin, IWaveformGenerator, Plugin, implements,
+                            PluginGlobals, ScheduleRequest, emit_signal,
+                            get_service_instance)
+from app_context import get_app
+from path_helpers import path
+
+
+PluginGlobals.push_env('microdrop.managed')
+
+class ZeroMQServicePlugin(Plugin, AppDataController, StepOptionsController):
+    """
+    This class is automatically registered with the PluginManager.
+    """
+    implements(IPlugin)
+    version = get_plugin_info(path(__file__).parent.parent).version
+    plugins_name = get_plugin_info(path(__file__).parent.parent).plugin_name
+
+    '''
+    AppFields
+    ---------
+
+    A flatland Form specifying application options for the current plugin.
+    Note that nested Form objects are not supported.
+
+    Since we subclassed AppDataController, an API is available to access and
+    modify these attributes.  This API also provides some nice features
+    automatically:
+        -all fields listed here will be included in the app options dialog
+            (unless properties=dict(show_in_gui=False) is used)
+        -the values of these fields will be stored persistently in the microdrop
+            config file, in a section named after this plugin's name attribute
+    '''
+    AppFields = Form.of(
+        String.named('service_address').using(default='', optional=True),
+    )
+
+    '''
+    StepFields
+    ---------
+
+    A flatland Form specifying the per step options for the current plugin.
+    Note that nested Form objects are not supported.
+
+    Since we subclassed StepOptionsController, an API is available to access and
+    modify these attributes.  This API also provides some nice features
+    automatically:
+        -all fields listed here will be included in the protocol grid view
+            (unless properties=dict(show_in_gui=False) is used)
+        -the values of these fields will be stored persistently for each step
+    '''
+    StepFields = Form.of(
+        Boolean.named('service_enabled').using(default=False, optional=True),
+    )
+
+    def __init__(self):
+        self.name = self.plugins_name
+        self.context = zmq.Context.instance()
+        self.socks = OrderedDict()
+        self.timeout_id = None
+        self._start_time = None
+
+    def on_plugin_enable(self):
+        # We need to call AppDataController's on_plugin_enable() to update the
+        # application options data.
+        AppDataController.on_plugin_enable(self)
+        self.context = zmq.Context()
+        self.reset_socks()
+        if get_app().protocol:
+            pgc = get_service_instance(ProtocolGridController, env='microdrop')
+            pgc.update_grid()
+
+    def close_socks(self):
+        # Close any currently open sockets.
+        for name, sock in self.socks.iteritems():
+            sock.close()
+        self.socks = OrderedDict()
+
+    def reset_socks(self):
+        self.close_socks()
+        app_values = self.get_app_values()
+        if self.timeout_id is not None:
+            gtk.timeout_remove(self.timeout_id)
+            self.timeout_id = None
+        if app_values['service_address']:
+            # Service address is available
+            self.socks['req'] = zmq.Socket(self.context, zmq.REQ)
+            self.socks['req'].connect(app_values['service_address'])
+
+    def on_app_options_changed(self, plugin_name):
+        if plugin_name == self.name:
+            self.reset_socks()
+
+    def on_plugin_disable(self):
+        self.close_socks()
+        if get_app().protocol:
+            pgc = get_service_instance(ProtocolGridController, env='microdrop')
+            pgc.update_grid()
+
+    def step_complete(self, return_value=None):
+        app = get_app()
+        if app.running or app.realtime_mode:
+            emit_signal('on_step_complete', [self.name, return_value])
+
+    def on_step_run(self):
+        options = self.get_step_options()
+        self.reset_socks()
+        if options['service_enabled'] and self.socks['req'] is None:
+            # Service is supposed to be called for this step, but the socket is
+            # not ready.
+            self.step_complete(return_value='Fail')
+        elif options['service_enabled'] and self.socks['req'] is not None:
+            logger.info('[ZeroMQServicePlugin] Send signal to service to '
+                        'start.')
+            # Request start of service.
+            self.socks['req'].send('start')
+            if not self.socks['req'].poll(timeout=4000):
+                self.reset_socks()
+                logger.error('[ZeroMQServicePlugin] Timed-out waiting for '
+                                'a response.')
+            else:
+                # Response is ready.
+                response = self.socks['req'].recv()
+                if response == 'started':
+                    logger.info('[ZeroMQServicePlugin] Service started '
+                                'successfully.')
+                    self.socks['req'].send('notify_completion')
+
+                    response = self.socks['req'].recv()
+                    logger.info('[ZeroMQServicePlugin] Service response: %s', response)
+                    if response == 'completed':
+                        logger.info('[ZeroMQServicePlugin] Service completed task '
+                                    'successfully.')
+                        self.step_complete()
+                    else:
+                        logger.error('[ZeroMQServicePlugin] Unexpected response: %s' %
+                                     response)
+                        self.step_complete(return_value='Fail')
+        else:
+            self.step_complete()
+
+    def enable_service(self):
+        pass
+
+PluginGlobals.pop_env()
diff --git a/hooks/Linux/on_plugin_install.sh b/hooks/Linux/on_plugin_install.sh
new file mode 100644
index 0000000000000000000000000000000000000000..19bf66611814afab0a6c30b04017c7eea3017334
--- /dev/null
+++ b/hooks/Linux/on_plugin_install.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+PYTHON_EXE=$1
+$PYTHON_EXE ../../on_plugin_install.py
diff --git a/hooks/Windows/on_plugin_install.bat b/hooks/Windows/on_plugin_install.bat
new file mode 100644
index 0000000000000000000000000000000000000000..617a8286917f64dc54b0627f06cb4bf3d7e8ccf8
--- /dev/null
+++ b/hooks/Windows/on_plugin_install.bat
@@ -0,0 +1 @@
+%1 ..\..\on_plugin_install.py
diff --git a/hooks/Windows/on_plugin_install.exe b/hooks/Windows/on_plugin_install.exe
new file mode 100644
index 0000000000000000000000000000000000000000..2e6aa4f40e0ba6fabfae628dd3976df1f76b4eb7
Binary files /dev/null and b/hooks/Windows/on_plugin_install.exe differ
diff --git a/microdrop/__init__.py b/microdrop/__init__.py
deleted file mode 100644
index 9c97ea66c3321fdd97f01b8647508d69931d5b29..0000000000000000000000000000000000000000
--- a/microdrop/__init__.py
+++ /dev/null
@@ -1,172 +0,0 @@
-"""
-Copyright 2011 Ryan Fobel
-
-This file is part of dmf_control_board.
-
-dmf_control_board is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-dmf_control_board is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with dmf_control_board.  If not, see <http://www.gnu.org/licenses/>.
-"""
-from collections import OrderedDict
-from datetime import datetime
-
-import gtk
-import zmq
-from flatland import String, Boolean, Float, Form
-from logger import logger
-from gui.protocol_grid_controller import ProtocolGridController
-from plugin_helpers import (AppDataController, StepOptionsController,
-                            get_plugin_info)
-from plugin_manager import (IPlugin, IWaveformGenerator, Plugin, implements,
-                            PluginGlobals, ScheduleRequest, emit_signal,
-                            get_service_instance)
-from app_context import get_app
-from path_helpers import path
-
-
-PluginGlobals.push_env('microdrop.managed')
-
-class ZeroMQServicePlugin(Plugin, AppDataController, StepOptionsController):
-    """
-    This class is automatically registered with the PluginManager.
-    """
-    implements(IPlugin)
-    version = get_plugin_info(path(__file__).parent.parent).version
-    plugins_name = get_plugin_info(path(__file__).parent.parent).plugin_name
-
-    '''
-    AppFields
-    ---------
-
-    A flatland Form specifying application options for the current plugin.
-    Note that nested Form objects are not supported.
-
-    Since we subclassed AppDataController, an API is available to access and
-    modify these attributes.  This API also provides some nice features
-    automatically:
-        -all fields listed here will be included in the app options dialog
-            (unless properties=dict(show_in_gui=False) is used)
-        -the values of these fields will be stored persistently in the microdrop
-            config file, in a section named after this plugin's name attribute
-    '''
-    AppFields = Form.of(
-        String.named('service_address').using(default='', optional=True),
-    )
-
-    '''
-    StepFields
-    ---------
-
-    A flatland Form specifying the per step options for the current plugin.
-    Note that nested Form objects are not supported.
-
-    Since we subclassed StepOptionsController, an API is available to access and
-    modify these attributes.  This API also provides some nice features
-    automatically:
-        -all fields listed here will be included in the protocol grid view
-            (unless properties=dict(show_in_gui=False) is used)
-        -the values of these fields will be stored persistently for each step
-    '''
-    StepFields = Form.of(
-        Boolean.named('service_enabled').using(default=False, optional=True),
-    )
-
-    def __init__(self):
-        self.name = self.plugins_name
-        self.context = zmq.Context.instance()
-        self.socks = OrderedDict()
-        self.timeout_id = None
-        self._start_time = None
-
-    def on_plugin_enable(self):
-        # We need to call AppDataController's on_plugin_enable() to update the
-        # application options data.
-        AppDataController.on_plugin_enable(self)
-        self.context = zmq.Context()
-        self.reset_socks()
-        if get_app().protocol:
-            pgc = get_service_instance(ProtocolGridController, env='microdrop')
-            pgc.update_grid()
-
-    def close_socks(self):
-        # Close any currently open sockets.
-        for name, sock in self.socks.iteritems():
-            sock.close()
-        self.socks = OrderedDict()
-
-    def reset_socks(self):
-        self.close_socks()
-        app_values = self.get_app_values()
-        if self.timeout_id is not None:
-            gtk.timeout_remove(self.timeout_id)
-            self.timeout_id = None
-        if app_values['service_address']:
-            # Service address is available
-            self.socks['req'] = zmq.Socket(self.context, zmq.REQ)
-            self.socks['req'].connect(app_values['service_address'])
-
-    def on_app_options_changed(self, plugin_name):
-        if plugin_name == self.name:
-            self.reset_socks()
-
-    def on_plugin_disable(self):
-        self.close_socks()
-        if get_app().protocol:
-            pgc = get_service_instance(ProtocolGridController, env='microdrop')
-            pgc.update_grid()
-
-    def step_complete(self, return_value=None):
-        app = get_app()
-        if app.running or app.realtime_mode:
-            emit_signal('on_step_complete', [self.name, return_value])
-
-    def on_step_run(self):
-        options = self.get_step_options()
-        self.reset_socks()
-        if options['service_enabled'] and self.socks['req'] is None:
-            # Service is supposed to be called for this step, but the socket is
-            # not ready.
-            self.step_complete(return_value='Fail')
-        elif options['service_enabled'] and self.socks['req'] is not None:
-            logger.info('[ZeroMQServicePlugin] Send signal to service to '
-                        'start.')
-            # Request start of service.
-            self.socks['req'].send('start')
-            if not self.socks['req'].poll(timeout=4000):
-                self.reset_socks()
-                logger.error('[ZeroMQServicePlugin] Timed-out waiting for '
-                                'a response.')
-            else:
-                # Response is ready.
-                response = self.socks['req'].recv()
-                if response == 'started':
-                    logger.info('[ZeroMQServicePlugin] Service started '
-                                'successfully.')
-                    self.socks['req'].send('notify_completion')
-
-                    response = self.socks['req'].recv()
-                    logger.info('[ZeroMQServicePlugin] Service response: %s', response)
-                    if response == 'completed':
-                        logger.info('[ZeroMQServicePlugin] Service completed task '
-                                    'successfully.')
-                        self.step_complete()
-                    else:
-                        logger.error('[ZeroMQServicePlugin] Unexpected response: %s' %
-                                     response)
-                        self.step_complete(return_value='Fail')
-        else:
-            self.step_complete()
-
-    def enable_service(self):
-        pass
-
-PluginGlobals.pop_env()
diff --git a/on_plugin_install.py b/on_plugin_install.py
new file mode 100644
index 0000000000000000000000000000000000000000..80fb487a1cf874faf5aa0c194605fa0419322302
--- /dev/null
+++ b/on_plugin_install.py
@@ -0,0 +1,12 @@
+from datetime import datetime
+import logging
+
+from path_helpers import path
+from pip_helpers import install
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    logging.info(str(datetime.now()))
+    requirements = path(__file__).parent.joinpath('requirements.txt').abspath()
+    logging.info(install(['-U', '-r', requirements]))
diff --git a/release.py b/release.py
new file mode 100755
index 0000000000000000000000000000000000000000..47788c40b3d5ed0849655804a587517bda9c5c45
--- /dev/null
+++ b/release.py
@@ -0,0 +1,22 @@
+import tarfile
+import yaml
+
+from microdrop_utility import Version
+
+package_name = 'dstat_zeromq_plugin'
+plugin_name = 'wheeler.dstat_zeromq_plugin'
+
+# create a version sting based on the git revision/branch
+version = str(Version.from_git_repository())
+
+# write the 'properties.yml' file
+properties = {'plugin_name': plugin_name, 'package_name': package_name,
+              'version': version}
+with open('properties.yml', 'w') as f:
+    f.write(yaml.dump(properties))
+
+# create the tar.gz plugin archive
+with tarfile.open("%s-%s.tar.gz" % (package_name, version), "w:gz") as tar:
+    for name in ['__init__.py', 'test_service.py', 'properties.yml',
+                 'requirements.txt']:
+        tar.add(name)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..02ec117e150a927f354885c99756c08c2618bf0c
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+pyzmq
diff --git a/site_scons/__init__.py b/site_scons/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/site_scons/git_util.py b/site_scons/git_util.py
deleted file mode 100644
index 6fecf25e9a83201373ec037430c0a66ece9c5d02..0000000000000000000000000000000000000000
--- a/site_scons/git_util.py
+++ /dev/null
@@ -1,93 +0,0 @@
-import os
-from subprocess import Popen, PIPE, check_call, CalledProcessError
-import re
-
-from path_helpers import path
-
-
-class GitError(Exception):
-    pass
-
-
-class GitUtil(object):
-    def __init__(self, root_path='.'):
-        self.root_path = path(root_path)
-        if root_path is None:
-            dir_node = path(os.getcwd())
-            while not dir_node.dirs('.git') and dir_node:
-                dir_node = dir_node.parent
-            if not dir_node:
-                raise GitError('No git root found.')
-            self.root_path = dir_node
-        self._git = None
-        assert(self.root_path.dirs('.git'))
-
-
-    @property
-    def git(self):
-        if self._git:
-            return self._git
-
-        cmds = ['git']
-        if os.name == 'nt':
-            exceptions = (WindowsError,)
-            cmds += ['git.cmd']
-        else:
-            exceptions = (OSError,)
-
-        valid_cmd = False
-        for cmd in cmds:
-            try:
-                check_call([cmd], stdout=PIPE, stderr=PIPE)
-            except exceptions:
-                # The command was not found, try the next one
-                pass
-            except CalledProcessError:
-                valid_cmd = True
-                break
-        if not valid_cmd:
-            raise GitError, 'No valid git command found'
-        self._git = cmd
-        return self._git
-
-
-    def command(self, x):
-        try:
-            x.__iter__
-        except:
-            x = re.split(r'\s+', x)
-        cwd = os.getcwd()
-
-        os.chdir(self.root_path)
-        cmd = [self.git] + x
-        stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE).communicate()
-        os.chdir(cwd)
-
-        if stderr:
-            raise GitError('Error executing git %s' % x)
-        return stdout.strip()
-
-
-    def describe(self):
-        return self.command('describe')
-
-
-    def summary(self, color=False):
-        if color:
-            format_ = '''--pretty=format:%Cred%h%Creset - %s %Cgreen(%cr)%Creset'''
-        else:
-            format_ = '''--pretty=format:%h - %s (%cr)'''
-        return self.command(['''log''', '''--graph''', format_,
-                    '''--abbrev-commit''', '''--date=relative'''])
-
-
-    def rev_parse(self, ref='HEAD'):
-        return self.command(['rev-parse', ref])
-
-
-    def show(self, ref='HEAD', color=False, extra_args=None):
-        extra_args = [extra_args, []][extra_args is None]
-        args = ['show', ref]
-        if color:
-            args += ['--color']
-        return self.command(args + extra_args)
diff --git a/site_scons/site_tools/disttar/__init__.py b/site_scons/site_tools/disttar/__init__.py
deleted file mode 100644
index 4b0e0f07f936e7f9173a89a6a9a738505676a481..0000000000000000000000000000000000000000
--- a/site_scons/site_tools/disttar/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from disttar import *
diff --git a/site_scons/site_tools/disttar/disttar.py b/site_scons/site_tools/disttar/disttar.py
deleted file mode 100644
index 7f7a13e2fe67c925b275a0dad30d86196149b774..0000000000000000000000000000000000000000
--- a/site_scons/site_tools/disttar/disttar.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# DistTarBuilder: tool to generate tar files using SCons
-# Copyright (C) 2005, 2006  Matthew A. Nicholson
-# Copyright (C) 2006-2010 John Pye
-#
-# This file is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License version 2.1 as published by the Free Software Foundation.
-#
-# This file is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-
-import os,sys
-from SCons.Script import *
-import re
-
-
-def file_handler(fpath, source, excluderes, excludeexts):
-    from path import path
-
-    fpath = path(fpath)
-    if not fpath.ext in excludeexts:
-        failre = False
-        for r in excluderes:
-            #print "Match(  %s   against   %s)" % (r,relpath)
-            if r.search(fpath):
-                failre = True
-                #print "Excluding '%s' from tarball" % fpath
-                break
-        if not failre:
-            #print "Adding source",fpath
-            source.append(str(fpath))
-
-
-def disttar_emitter(target, source, env):
-    source,origsource = [], source
-
-    excludeexts = env.Dictionary().get('DISTTAR_EXCLUDEEXTS',[])
-    excludedirs = env.Dictionary().get('DISTTAR_EXCLUDEDIRS',[])
-    re1 = env.Dictionary().get('DISTTAR_EXCLUDERES',[])
-    excluderes = [re.compile(r) for r in re1]
-
-    # assume the sources are directories... need to check that
-    for item in origsource:
-        if os.path.isfile(str(item)):
-            file_handler(item, source, excluderes, excludeexts)
-        else:
-            for root, dirs, files in os.walk(str(item)):
-                # don't make directory dependences as that triggers full build
-                # of that directory
-                if root in source:
-                    #print "Removing directory %s" % root
-                    source.remove(root)
-
-                # loop through files in a directory
-                for name in files:
-                    relpath = os.path.join(root,name)
-                    file_handler(relpath, source, excluderes, excludeexts)
-
-                for d in excludedirs:
-                    if d in dirs:
-                        dirs.remove(d)  # don't visit CVS directories etc
-
-    return target, source
-
-def disttar_string(target, source, env):
-    """This is what gets printed on the console. We'll strip out the list
-        or source files, since it tends to get very long. If you want to see the 
-        contents, the easiest way is to uncomment the line 'Adding to TAR file'
-        below. """
-    return 'DistTar(%s,...)' % target[0]
-
-def disttar(target, source, env):
-        """tar archive builder"""
-
-        import tarfile
-
-        env_dict = env.Dictionary()
-
-        if env_dict.get("DISTTAR_FORMAT") in ["gz", "bz2"]:
-                tar_format = env_dict["DISTTAR_FORMAT"]
-        else:
-                tar_format = ""
-
-        # split the target directory, filename, and stuffix
-        base_name = str(target[0]).split('.tar')[0]
-        (target_dir, dir_name) = os.path.split(base_name)
-
-        # create the target directory if it does not exist
-        if target_dir and not os.path.exists(target_dir):
-                os.makedirs(target_dir)
-
-        # open our tar file for writing
-        print >> sys.stderr, 'DistTar: Writing %s' % str(target[0])
-        print >> sys.stderr, '  with contents: %s' % [str(s) for s in source]
-        tar = tarfile.open(str(target[0]), "w:%s" % tar_format)
-
-        # write sources to our tar file
-        for item in source:
-                item = str(item)
-                sys.stderr.write(".")
-                #print "Adding to TAR file: %s/%s" % (dir_name,item)
-                tar.add(item,'%s/%s' % (dir_name,item))
-
-        # all done
-        sys.stderr.write("\n") #print "Closing TAR file"
-        tar.close()
-
-def disttar_suffix(env, sources):
-        """tar archive suffix generator"""
-
-        env_dict = env.Dictionary()
-        if env_dict.has_key("DISTTAR_FORMAT") and env_dict["DISTTAR_FORMAT"] in ["gz", "bz2"]:
-                return ".tar." + env_dict["DISTTAR_FORMAT"]
-        else:
-                return ".tar"
-
-def generate(env):
-    """
-    Add builders and construction variables for the DistTar builder.
-    """
-
-    disttar_action=SCons.Action.Action(disttar, disttar_string)
-    env['BUILDERS']['DistTar'] =  Builder(
-            action=disttar_action
-            , emitter=disttar_emitter
-            , suffix = disttar_suffix
-            , target_factory = env.fs.Entry
-    )
-
-    env.AppendUnique(
-        DISTTAR_FORMAT = 'gz'
-    )
-
-def exists(env):
-        """
-        Make sure this tool exists.
-        """
-        try:
-                import os
-                import tarfile
-        except ImportError:
-                return False
-        else:
-                return True
-
-# vim:set ts=4 sw=4 noexpandtab: