#!/usr/bin/env python
from __future__ import absolute_import
import os
import sys
import shutil
import tempfile
import re
import string
import multiprocessing
import unittest
import time
import sys
import threading
import random
import httplib
import socket
import urllib
import atexit
import logging
import os
import sys
import tempfile
# Assume we are run from the galaxy root directory, add lib to the python path
cwd = os.getcwd()
tool_shed_home_directory = os.path.join( cwd, 'test', 'tool_shed' )
default_tool_shed_test_file_dir = os.path.join( tool_shed_home_directory, 'test_data' )
# Here's the directory where everything happens.  Temporary directories are created within this directory to contain
# the hgweb.config file, the database, new repositories, etc.  Since the tool shed browses repository contents via HTTP,
# the full path to the temporary directroy wher eht repositories are located cannot contain invalid url characters.
tool_shed_test_tmp_dir = os.path.join( tool_shed_home_directory, 'tmp' )
os.environ[ 'TOOL_SHED_TEST_TMP_DIR' ] = tool_shed_test_tmp_dir
new_path = [ os.path.join( cwd, "lib" ), os.path.join( cwd, "test" ) ]
new_path.extend( sys.path[1:] )
sys.path = new_path
from galaxy import eggs, model
eggs.require( "nose" )
eggs.require( "NoseHTML" )
eggs.require( "NoseTestDiff" )
eggs.require( "twill==0.9" )
eggs.require( "Paste" )
eggs.require( "PasteDeploy" )
eggs.require( "Cheetah" )
# This should not be required, but it is under certain conditions, thanks to this bug: http://code.google.com/p/python-nose/issues/detail?id=284
eggs.require( "pysqlite" )
import twill
from paste import httpserver
# This is for the tool shed application.
import galaxy.webapps.tool_shed.app
from galaxy.webapps.tool_shed.app import UniverseApplication as ToolshedUniverseApplication
from galaxy.webapps.tool_shed import buildapp as toolshedbuildapp
# This is for the galaxy application.
from galaxy.app import UniverseApplication as GalaxyUniverseApplication
from galaxy.web import buildapp as galaxybuildapp
from galaxy.util import asbool
from galaxy.util.json import dumps
import nose.core
import nose.config
import nose.loader
import nose.plugins.manager
from functional import database_contexts
from base import nose_util
log = logging.getLogger( "tool_shed_functional_tests.py" )
default_tool_shed_test_host = "localhost"
default_tool_shed_test_port_min = 8000
default_tool_shed_test_port_max = 8999
default_tool_shed_locales = 'en'
default_galaxy_test_port_min = 9000
default_galaxy_test_port_max = 9999
default_galaxy_test_host = 'localhost'
# Use separate databases for Galaxy and tool shed install info by default,
# set GALAXY_TEST_INSTALL_DB_MERGED to True to revert to merged databases
# behavior.
default_install_db_merged = False
# should this serve static resources (scripts, images, styles, etc.)
STATIC_ENABLED = True
def get_static_settings():
    """Returns dictionary of the settings necessary for a galaxy App
    to be wrapped in the static middleware.
    This mainly consists of the filesystem locations of url-mapped
    static resources.
    """
    cwd = os.getcwd()
    static_dir = os.path.join( cwd, 'static' )
    #TODO: these should be copied from galaxy.ini
    return dict(
        #TODO: static_enabled needed here?
        static_enabled      = True,
        static_cache_time   = 360,
        static_dir          = static_dir,
        static_images_dir   = os.path.join( static_dir, 'images', '' ),
        static_favicon_dir  = os.path.join( static_dir, 'favicon.ico' ),
        static_scripts_dir  = os.path.join( static_dir, 'scripts', '' ),
        static_style_dir    = os.path.join( static_dir, 'june_2007_style', 'blue' ),
        static_robots_txt   = os.path.join( static_dir, 'robots.txt' ),
    )
def get_webapp_global_conf():
    """Get the global_conf dictionary sent as the first argument to app_factory.
    """
    # (was originally sent 'dict()') - nothing here for now except static settings
    global_conf = dict()
    if STATIC_ENABLED:
        global_conf.update( get_static_settings() )
    return global_conf
tool_sheds_conf_xml_template = '''
    
    
    
'''
shed_tool_conf_xml_template = '''
'''
tool_conf_xml = '''
    
'''
tool_data_table_conf_xml_template = '''
'''
shed_data_manager_conf_xml_template = '''
'''
def run_tests( test_config ):
    return nose_util.run( test_config )
def main():
    # ---- Configuration ------------------------------------------------------
    tool_shed_test_host = os.environ.get( 'TOOL_SHED_TEST_HOST', default_tool_shed_test_host )
    tool_shed_test_port = os.environ.get( 'TOOL_SHED_TEST_PORT', None )
    galaxy_test_host = os.environ.get( 'GALAXY_TEST_HOST', default_galaxy_test_host )
    galaxy_test_port = os.environ.get( 'GALAXY_TEST_PORT', None )
    tool_path = os.environ.get( 'TOOL_SHED_TEST_TOOL_PATH', 'tools' )
    if 'HTTP_ACCEPT_LANGUAGE' not in os.environ:
        os.environ[ 'HTTP_ACCEPT_LANGUAGE' ] = default_tool_shed_locales
    tool_shed_test_file_dir = os.environ.get( 'TOOL_SHED_TEST_FILE_DIR', default_tool_shed_test_file_dir )
    if not os.path.isabs( tool_shed_test_file_dir ):
        tool_shed_test_file_dir = tool_shed_test_file_dir
    ignore_files = ()
    tool_dependency_dir = os.environ.get( 'TOOL_SHED_TOOL_DEPENDENCY_DIR', None )
    use_distributed_object_store = os.environ.get( 'TOOL_SHED_USE_DISTRIBUTED_OBJECT_STORE', False )
    if not os.path.isdir( tool_shed_test_tmp_dir ):
        os.mkdir( tool_shed_test_tmp_dir )
    tool_shed_test_proxy_port = None
    galaxy_test_proxy_port = None
    if 'TOOL_SHED_TEST_DBPATH' in os.environ:
        shed_db_path = os.environ[ 'TOOL_SHED_TEST_DBPATH' ]
    else:
        tempdir = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
        shed_db_path = os.path.join( tempdir, 'database' )
    shed_tool_data_table_conf_file = os.environ.get( 'TOOL_SHED_TEST_TOOL_DATA_TABLE_CONF', os.path.join( tool_shed_test_tmp_dir, 'shed_tool_data_table_conf.xml' ) )
    galaxy_shed_data_manager_conf_file = os.environ.get( 'GALAXY_SHED_DATA_MANAGER_CONF', os.path.join( tool_shed_test_tmp_dir, 'test_shed_data_manager_conf.xml' ) )
    galaxy_tool_data_table_conf_file = os.environ.get( 'GALAXY_TEST_TOOL_DATA_TABLE_CONF', os.path.join( tool_shed_test_tmp_dir, 'tool_data_table_conf.xml' ) )
    galaxy_tool_conf_file = os.environ.get( 'GALAXY_TEST_TOOL_CONF', os.path.join( tool_shed_test_tmp_dir, 'test_tool_conf.xml' ) )
    galaxy_shed_tool_conf_file = os.environ.get( 'GALAXY_TEST_SHED_TOOL_CONF', os.path.join( tool_shed_test_tmp_dir, 'test_shed_tool_conf.xml' ) )
    galaxy_migrated_tool_conf_file = os.environ.get( 'GALAXY_TEST_MIGRATED_TOOL_CONF', os.path.join( tool_shed_test_tmp_dir, 'test_migrated_tool_conf.xml' ) )
    galaxy_tool_sheds_conf_file = os.environ.get( 'GALAXY_TEST_TOOL_SHEDS_CONF', os.path.join( tool_shed_test_tmp_dir, 'test_sheds_conf.xml' ) )
    if 'GALAXY_TEST_TOOL_DATA_PATH' in os.environ:
        tool_data_path = os.environ.get( 'GALAXY_TEST_TOOL_DATA_PATH' )
    else:
        tool_data_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
        os.environ[ 'GALAXY_TEST_TOOL_DATA_PATH' ] = tool_data_path
    if 'GALAXY_TEST_DBPATH' in os.environ:
        galaxy_db_path = os.environ[ 'GALAXY_TEST_DBPATH' ]
    else:
        tempdir = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
        galaxy_db_path = os.path.join( tempdir, 'database' )
    shed_file_path = os.path.join( shed_db_path, 'files' )
    galaxy_file_path = os.path.join( galaxy_db_path, 'files' )
    hgweb_config_file_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    new_repos_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    galaxy_tempfiles = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    galaxy_shed_tool_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    galaxy_migrated_tool_path = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    galaxy_tool_dependency_dir = tempfile.mkdtemp( dir=tool_shed_test_tmp_dir )
    os.environ[ 'GALAXY_TEST_TOOL_DEPENDENCY_DIR' ] = galaxy_tool_dependency_dir
    hgweb_config_dir = hgweb_config_file_path
    os.environ[ 'TEST_HG_WEB_CONFIG_DIR' ] = hgweb_config_dir
    print "Directory location for hgweb.config:", hgweb_config_dir
    if 'TOOL_SHED_TEST_DBURI' in os.environ:
        toolshed_database_connection = os.environ[ 'TOOL_SHED_TEST_DBURI' ]
    else:
        toolshed_database_connection = 'sqlite:///' + os.path.join( shed_db_path, 'community_test.sqlite' )
    galaxy_database_auto_migrate = False
    if 'GALAXY_TEST_DBURI' in os.environ:
        galaxy_database_connection = os.environ[ 'GALAXY_TEST_DBURI' ]
    else:
        db_path = os.path.join( galaxy_db_path, 'universe.sqlite' )
        if 'GALAXY_TEST_DB_TEMPLATE' in os.environ:
            # Middle ground between recreating a completely new
            # database and pointing at existing database with
            # GALAXY_TEST_DBURI. The former requires a lot of setup
            # time, the latter results in test failures in certain
            # cases (namely tool shed tests expecting clean database).
            __copy_database_template(os.environ['GALAXY_TEST_DB_TEMPLATE'], db_path)
            galaxy_database_auto_migrate = True
        if not os.path.exists(galaxy_db_path):
            os.makedirs(galaxy_db_path)
        galaxy_database_connection = 'sqlite:///%s' % db_path
    if 'GALAXY_TEST_INSTALL_DBURI' in os.environ:
        install_galaxy_database_connection = os.environ[ 'GALAXY_TEST_INSTALL_DBURI' ]
    elif asbool( os.environ.get( 'GALAXY_TEST_INSTALL_DB_MERGED', default_install_db_merged ) ):
        install_galaxy_database_connection = galaxy_database_connection
    else:
        install_galaxy_db_path = os.path.join( galaxy_db_path, 'install.sqlite' )
        install_galaxy_database_connection = 'sqlite:///%s' % install_galaxy_db_path
    tool_shed_global_conf = get_webapp_global_conf()
    tool_shed_global_conf[ '__file__' ] = 'tool_shed_wsgi.ini.sample'
    kwargs = dict( admin_users = 'test@bx.psu.edu',
                   allow_user_creation = True,
                   allow_user_deletion = True,
                   database_connection = toolshed_database_connection,
                   datatype_converters_config_file = 'datatype_converters_conf.xml.sample',
                   file_path = shed_file_path,
                   global_conf = tool_shed_global_conf,
                   hgweb_config_dir = hgweb_config_dir,
                   job_queue_workers = 5,
                   id_secret = 'changethisinproductiontoo',
                   log_destination = "stdout",
                   new_file_path = new_repos_path,
                   running_functional_tests = True,
                   shed_tool_data_table_config = shed_tool_data_table_conf_file,
                   smtp_server = 'smtp.dummy.string.tld',
                   email_from = 'functional@localhost',
                   template_path = 'templates',
                   tool_path=tool_path,
                   tool_parse_help = False,
                   tool_data_table_config_path = galaxy_tool_data_table_conf_file,
                   use_heartbeat = False )
    for dir in [ tool_shed_test_tmp_dir ]:
        try:
            os.makedirs( dir )
        except OSError:
            pass
    print "Tool shed database connection:", toolshed_database_connection
    print "Galaxy database connection:", galaxy_database_connection
    # Generate the tool_data_table_conf.xml file.
    file( galaxy_tool_data_table_conf_file, 'w' ).write( tool_data_table_conf_xml_template )
    # Generate the shed_tool_data_table_conf.xml file.
    file( shed_tool_data_table_conf_file, 'w' ).write( tool_data_table_conf_xml_template )
    os.environ[ 'TOOL_SHED_TEST_TOOL_DATA_TABLE_CONF' ] = shed_tool_data_table_conf_file
    # ---- Build Tool Shed Application --------------------------------------------------
    toolshedapp = None
#    if not toolshed_database_connection.startswith( 'sqlite://' ):
#        kwargs[ 'database_engine_option_max_overflow' ] = '20'
    if tool_dependency_dir is not None:
        kwargs[ 'tool_dependency_dir' ] = tool_dependency_dir
    if use_distributed_object_store:
        kwargs[ 'object_store' ] = 'distributed'
        kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample'
    kwargs[ 'global_conf' ] = tool_shed_global_conf
    if not toolshed_database_connection.startswith( 'sqlite://' ):
            kwargs[ 'database_engine_option_pool_size' ] = '10'
    toolshedapp = ToolshedUniverseApplication( **kwargs )
    database_contexts.tool_shed_context = toolshedapp.model.context
    log.info( "Embedded Toolshed application started" )
    # ---- Run tool shed webserver ------------------------------------------------------
    tool_shed_server = None
    tool_shed_global_conf[ 'database_connection' ] = toolshed_database_connection
    toolshedwebapp = toolshedbuildapp.app_factory( tool_shed_global_conf,
                                                   use_translogger=False,
                                                   static_enabled=True,
                                                   app=toolshedapp )
    if tool_shed_test_port is not None:
        tool_shed_server = httpserver.serve( toolshedwebapp, host=tool_shed_test_host, port=tool_shed_test_port, start_loop=False )
    else:
        random.seed()
        for i in range( 0, 9 ):
            try:
                tool_shed_test_port = str( random.randint( default_tool_shed_test_port_min, default_tool_shed_test_port_max ) )
                log.debug( "Attempting to serve app on randomly chosen port: %s" % tool_shed_test_port )
                tool_shed_server = httpserver.serve( toolshedwebapp, host=tool_shed_test_host, port=tool_shed_test_port, start_loop=False )
                break
            except socket.error, e:
                if e[0] == 98:
                    continue
                raise
        else:
            raise Exception( "Unable to open a port between %s and %s to start Galaxy server" % ( default_tool_shed_test_port_min, default_tool_shed_test_port_max ) )
    if tool_shed_test_proxy_port:
        os.environ[ 'TOOL_SHED_TEST_PORT' ] = tool_shed_test_proxy_port
    else:
        os.environ[ 'TOOL_SHED_TEST_PORT' ] = tool_shed_test_port
    t = threading.Thread( target=tool_shed_server.serve_forever )
    t.start()
    # Test if the server is up
    for i in range( 10 ):
        # Directly test the app, not the proxy.
        conn = httplib.HTTPConnection( tool_shed_test_host, tool_shed_test_port )
        conn.request( "GET", "/" )
        if conn.getresponse().status == 200:
            break
        time.sleep( 0.1 )
    else:
        raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
    log.info( "Embedded web server started" )
    # ---- Optionally start up a Galaxy instance ------------------------------------------------------
    if 'TOOL_SHED_TEST_OMIT_GALAXY' not in os.environ:
        # Generate the tool_conf.xml file.
        file( galaxy_tool_conf_file, 'w' ).write( tool_conf_xml )
        # Generate the shed_tool_conf.xml file.
        tool_sheds_conf_template_parser = string.Template( tool_sheds_conf_xml_template )
        tool_sheds_conf_xml = tool_sheds_conf_template_parser.safe_substitute( shed_url=tool_shed_test_host, shed_port=tool_shed_test_port )
        file( galaxy_tool_sheds_conf_file, 'w' ).write( tool_sheds_conf_xml )
        # Generate the tool_sheds_conf.xml file.
        shed_tool_conf_template_parser = string.Template( shed_tool_conf_xml_template )
        shed_tool_conf_xml = shed_tool_conf_template_parser.safe_substitute( shed_tool_path=galaxy_shed_tool_path )
        file( galaxy_shed_tool_conf_file, 'w' ).write( shed_tool_conf_xml )
        # Generate the migrated_tool_conf.xml file.
        migrated_tool_conf_xml = shed_tool_conf_template_parser.safe_substitute( shed_tool_path=galaxy_migrated_tool_path )
        file( galaxy_migrated_tool_conf_file, 'w' ).write( migrated_tool_conf_xml )
        os.environ[ 'GALAXY_TEST_SHED_TOOL_CONF' ] = galaxy_shed_tool_conf_file
        # Generate shed_data_manager_conf.xml
        if not os.environ.get( 'GALAXY_SHED_DATA_MANAGER_CONF' ):
            open( galaxy_shed_data_manager_conf_file, 'wb' ).write( shed_data_manager_conf_xml_template )
        galaxy_global_conf = get_webapp_global_conf()
        galaxy_global_conf[ '__file__' ] = 'config/galaxy.ini.sample'
        kwargs = dict( allow_user_creation = True,
                       allow_user_deletion = True,
                       admin_users = 'test@bx.psu.edu',
                       allow_library_path_paste = True,
                       install_database_connection = install_galaxy_database_connection,
                       database_connection = galaxy_database_connection,
                       database_auto_migrate = galaxy_database_auto_migrate,
                       datatype_converters_config_file = "datatype_converters_conf.xml.sample",
                       check_migrate_tools = False,
                       enable_tool_shed_check = True,
                       file_path = galaxy_file_path,
                       global_conf = galaxy_global_conf,
                       hours_between_check = 0.001,
                       id_secret = 'changethisinproductiontoo',
                       job_queue_workers = 5,
                       log_destination = "stdout",
                       migrated_tools_config = galaxy_migrated_tool_conf_file,
                       new_file_path = galaxy_tempfiles,
                       running_functional_tests=True,
                       shed_data_manager_config_file = galaxy_shed_data_manager_conf_file,
                       shed_tool_data_table_config = shed_tool_data_table_conf_file,
                       shed_tool_path = galaxy_shed_tool_path,
                       template_path = "templates",
                       tool_data_path = tool_data_path,
                       tool_dependency_dir = galaxy_tool_dependency_dir,
                       tool_path = tool_path,
                       tool_config_file = [ galaxy_tool_conf_file, galaxy_shed_tool_conf_file ],
                       tool_sheds_config_file = galaxy_tool_sheds_conf_file,
                       tool_parse_help = False,
                       tool_data_table_config_path = galaxy_tool_data_table_conf_file,
                       update_integrated_tool_panel = False,
                       use_heartbeat = False )
        # ---- Build Galaxy Application --------------------------------------------------
        if not galaxy_database_connection.startswith( 'sqlite://' ) and not install_galaxy_database_connection.startswith( 'sqlite://' ):
            kwargs[ 'database_engine_option_pool_size' ] = '10'
            kwargs[ 'database_engine_option_max_overflow' ] = '20'
        galaxyapp = GalaxyUniverseApplication( **kwargs )
        log.info( "Embedded Galaxy application started" )
        # ---- Run galaxy webserver ------------------------------------------------------
        galaxy_server = None
        galaxy_global_conf[ 'database_file' ] = galaxy_database_connection
        galaxywebapp = galaxybuildapp.app_factory( galaxy_global_conf,
                                                   use_translogger=False,
                                                   static_enabled=True,
                                                   app=galaxyapp )
        database_contexts.galaxy_context = galaxyapp.model.context
        database_contexts.install_context = galaxyapp.install_model.context
        if galaxy_test_port is not None:
            galaxy_server = httpserver.serve( galaxywebapp, host=galaxy_test_host, port=galaxy_test_port, start_loop=False )
        else:
            random.seed()
            for i in range( 0, 9 ):
                try:
                    galaxy_test_port = str( random.randint( default_galaxy_test_port_min, default_galaxy_test_port_max ) )
                    log.debug( "Attempting to serve app on randomly chosen port: %s" % galaxy_test_port )
                    galaxy_server = httpserver.serve( galaxywebapp, host=galaxy_test_host, port=galaxy_test_port, start_loop=False )
                    break
                except socket.error, e:
                    if e[0] == 98:
                        continue
                    raise
            else:
                raise Exception( "Unable to open a port between %s and %s to start Galaxy server" % \
                                 ( default_galaxy_test_port_min, default_galaxy_test_port_max ) )
        if galaxy_test_proxy_port:
            os.environ[ 'GALAXY_TEST_PORT' ] = galaxy_test_proxy_port
        else:
            os.environ[ 'GALAXY_TEST_PORT' ] = galaxy_test_port
        t = threading.Thread( target=galaxy_server.serve_forever )
        t.start()
        # Test if the server is up
        for i in range( 10 ):
            # Directly test the app, not the proxy.
            conn = httplib.HTTPConnection( galaxy_test_host, galaxy_test_port )
            conn.request( "GET", "/" )
            if conn.getresponse().status == 200:
                break
            time.sleep( 0.1 )
        else:
            raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
        log.info( "Embedded galaxy web server started" )
    # We don't add the tests to the path until everything is up and running
    new_path = [ os.path.join( cwd, 'test' ) ]
    new_path.extend( sys.path[1:] )
    sys.path = new_path
    # ---- Find tests ---------------------------------------------------------
    if tool_shed_test_proxy_port:
        log.info( "Functional tests will be run against %s:%s" % ( tool_shed_test_host, tool_shed_test_proxy_port ) )
    else:
        log.info( "Functional tests will be run against %s:%s" % ( tool_shed_test_host, tool_shed_test_port ) )
    if galaxy_test_proxy_port:
        log.info( "Galaxy tests will be run against %s:%s" % ( galaxy_test_host, galaxy_test_proxy_port ) )
    else:
        log.info( "Galaxy tests will be run against %s:%s" % ( galaxy_test_host, galaxy_test_port ) )
    success = False
    try:
        # Pass in through script set env, will leave a copy of ALL test validate files.
        os.environ[ 'TOOL_SHED_TEST_HOST' ] = tool_shed_test_host
        os.environ[ 'GALAXY_TEST_HOST' ] = galaxy_test_host
        if tool_shed_test_file_dir:
            os.environ[ 'TOOL_SHED_TEST_FILE_DIR' ] = tool_shed_test_file_dir
        test_config = nose.config.Config( env=os.environ, ignoreFiles=ignore_files, plugins=nose.plugins.manager.DefaultPluginManager() )
        test_config.configure( sys.argv )
        # Run the tests.
        result = run_tests( test_config )
        success = result.wasSuccessful()
    except:
        log.exception( "Failure running tests" )
    log.info( "Shutting down" )
    # ---- Tear down -----------------------------------------------------------
    if tool_shed_server:
        log.info( "Shutting down embedded web server" )
        tool_shed_server.server_close()
        tool_shed_server = None
        log.info( "Embedded web server stopped" )
    if toolshedapp:
        log.info( "Shutting down tool shed app" )
        toolshedapp.shutdown()
        toolshedapp = None
        log.info( "Embedded tool shed application stopped" )
    if 'TOOL_SHED_TEST_OMIT_GALAXY' not in os.environ:
        if galaxy_server:
            log.info( "Shutting down galaxy web server" )
            galaxy_server.server_close()
            galaxy_server = None
            log.info( "Embedded galaxy server stopped" )
        if galaxyapp:
            log.info( "Shutting down galaxy app" )
            galaxyapp.shutdown()
            galaxyapp = None
            log.info( "Embedded galaxy application stopped" )
    if 'TOOL_SHED_TEST_NO_CLEANUP' not in os.environ:
        try:
            for dir in [ tool_shed_test_tmp_dir ]:
                if os.path.exists( dir ):
                    log.info( "Cleaning up temporary files in %s" % dir )
                    shutil.rmtree( dir )
        except:
            pass
    if success:
        return 0
    else:
        return 1
def __copy_database_template( source, db_path ):
    """
    Copy a 'clean' sqlite template database (from file or URL) to specified
    database path.
    """
    os.makedirs( os.path.dirname( db_path ) )
    if os.path.exists( source ):
        shutil.copy( source, db_path )
        assert os.path.exists( db_path )
    elif source.startswith("http"):
        urllib.urlretrieve( source, db_path )
    else:
        raise Exception( "Failed to copy database template from source %s" % source )
if __name__ == "__main__":
    try:
        sys.exit( main() )
    except Exception, e:
        log.exception( str( e ) )
        exit(1)