#!/usr/bin/python
#
# OpenERP environment adminitrator
#

import sys, os, signal, ConfigParser
import argparse
import re
from os.path import abspath, lexists, join, basename, dirname, normpath, expanduser, expandvars, relpath, islink
from os import remove, rename, readlink, symlink, chmod
import stat
from glob import iglob
import signal
import psycopg2
import pprint
import datetime
import subprocess
import distutils
import bzrlib

try:
    import pysvn
except:
    print "Can't use SVN repositories. Please install pysvn. Debian: sudo aptitude install python-svn"

from oerpenv import *

def init(args):
    """
    Init an environment in the work path or in the declared path. 
    """
    print "Init environment."
    
    path = args.path
    repository = args.repository
    config_filename = args.config
    version = args.version

    if path is not None:
        config_filename = join(abspath(path), config_filename)

    repository = normpath(abspath(expanduser(expandvars(repository)))) if repository is not None else None

    try:
        oerpenv = OpenERPEnvironment(config_filename=config_filename, sources=repository, init=True, version=version)
    except RuntimeError, s:
        print s
        return -1

    try:
        for operation, local_branch_url, remote_branch_url in oerpenv.update(iterate=True):
            if operation == 'update':
                print "Updating %s from %s" % (local_branch_url, remote_branch_url)
            if operation == 'create':
                print "Creating %s from %s" % (local_branch_url, remote_branch_url)
    except bzrlib.errors.NotBranchError, m:
        print "Trouble creating/updating local repository."
        print "ERROR: %s" % m
        print "Please remove %s and execute the command again" % local_branch_url 
        return -1
    except bzrlib.errors.InvalidURL:
        print "Trouble acceding remote repository."
        print "The url <%s> in the environment.conf is invalid. Modify it and try again." % remote_branch_url 
        return -1

def setup(args):
    """
    Write default files to environment. 
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)

    for filename in defaults.default_files:
        with open(filename % { 'root': oerpenv.env_path }, 'w') as file:
            file.write(defaults.default_files[filename] % { 'root': oerpenv.root_path })

def update(args):
    """
    Update sources. 
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)

    try:
        for operation, local_branch_url, remote_branch_url in oerpenv.update(iterate=True, repositories=args.repositories):
            if operation == 'update':
                print "Updating %s from %s" % (local_branch_url, remote_branch_url)
            if operation == 'create':
                print "Creating %s from %s" % (local_branch_url, remote_branch_url)
    except bzrlib.errors.NotBranchError:
        print "Trouble creating/updating local repository."
        print "Please remove %s and execute the command again." % local_branch_url 
        return -1
    except bzrlib.errors.InvalidURL:
        print "Trouble acceding remote repository."
        print "Please check the url <%s> in the environment.conf and try again." % remote_branch_url 
        return -1
    except pysvn._pysvn.ClientError, m:
        print "Trouble acceding remote repository."
        if 'callback_ssl_server_trust_prompt' in m:
            print "You must accept the server certificate first. Execute the following command and answer 'p' to the question."
            print "cd sources; svn co %s %s; cd .." % (remove_branch_url, local_branch_url)
        else:
            print m
        return -1

def create(args):
    """
    Create a new python environment.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)

    print "Creating environment %s" % args.name[0]

    oerpenv.create_python_environment(args.name[0])

def add(args):
    """
    Add a branch with to the sources list.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.load()

    oerpenv.add_repository(args.name[0], args.url[0])

    oerpenv.save()

def install(args):
    """
    Install all software in the default environment of in the declared.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    print "Checking for availables applications."
    itemstoinstall = [ i.lower() for i in args.itemstoinstall ]
    installables = [ app for app in oerpenv.installables if app.name.lower() in itemstoinstall ] \
                    if len(itemstoinstall) > 0 \
                    else oerpenv.installables
    installables = list(installables)

    if len(installables) == 0:
        print "I cant find %s in installables." % ','.join([i.name for i in installables])
        print "Execute 'oerpenv list-installables' to view available applications to install."
        print "Or please check if you define it in the list 'installables' of section 'Environment' in the 'environment.conf' file."

    for app in installables:
        print "Installing %s" % app.name
        if app.install():
            print "Successfull installed"
        else:
            print "ERROR: Can't confirm the application or module is installed."
            print "Please, execute 'oerpenv test base' to check if server is working"
            print "To check if client is working execute 'openerp client'"
            print "If not working, recreate the python environment and try again"
            print

def list_installables(args):
    """
    List all availables applications in sources.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    for application in oerpenv.installables:
        print "--"
        print "Application:", application.name
        print "Version:", application.fullname
        print "Description:", application.description

def list_addons(args):
    """
    List availables addons in sources. Show all addons if not filter expression declared.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    for addon in oerpenv.addons(args.filter_string):
        state = 'e' if addon.is_enable(oerpenv) else 'd' if addon.is_saned(oerpenv) else 'b'
        print "{1} {0:<25} {2:<40} {3}".format(addon.token, state, addon.name, relpath(addon.path))

def enable_addon(args):
    """
    Enabel addons on the environment. Create a symbolic link.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    path_map = oerpenv.get_addonsourcepath()
    if 'server' not in path_map:
        raise "Server is not installed"

    addons_path = path_map['server']

    ignore_filter = re.compile(args.ignore_filter) if args.ignore_filter is not None else None

    addons = dict([ (addon.token, addon) for addon in oerpenv.addons()
                   if ignore_filter is None or ignore_filter.search(addon.path) is None ])
    addons_set = set(addons.keys())

    ignore_depends = args.ignore_depends

    if 'all' in args.addon:
        to_install = addons_set
    else:
        to_install = set( args.addon )

    c_t = len(to_install)

    if not lexists(addons_path):
        print "Execute 'oerpenv install' before 'oerpenv enable'"
        return -1

    if not to_install <= addons_set:
        print "No available addons '%s'." % ' '.join(to_install)
        return -1

    who_install = {}
    yet_enabled = set()

    c = 0

    while to_install:
        addon_name = to_install.pop()

        if addon_name in addons:
            addon = addons[addon_name]
        else:
            print "ERROR: %s try to install %s, but is unavailable." % (who_install[addon_name], addon_name)
            continue

        for item in set(addon.depends):
            who_install[item] = addon_name

        if not ignore_depends:
            to_install.update(addon.depends)
        
        if addon.is_enable(oerpenv):
            print "Updating %s (%i)" % (addon_name, len(to_install))
        else:
            print "Installing %s (%i)" % (addon_name, len(to_install))

        yet_enabled.add(addon_name)
        to_install = to_install - yet_enabled
        addon.enable(oerpenv, force=True)

        if 'base' in to_install:
            to_install.remove('base')

        c = c + 1

    if c_t > c:
            print "Can't install %s modules" % (c_t - c)

    return 0

def disable_addon(args):
    """
    Disable addons on the environment. Remove a symbolic link.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    addons_path = oerpenv.get_addonsourcepath()['server']

    files = iglob(join(addons_path, args.addon[0]))

    for addon_path in files:
        addon = Addon(addon_path)
        if addon.is_enable(oerpenv):
            print "Removing %s." % Addon(files).token
            addon.disable(oerpenv)
        else:
            print "Addon %s not enabled." % args.addon[0]

    return 0

def create_dummy_addon(args):
    """
    Create a dummy addon. Useful to create new addon.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    source_path = join(oerpenv.sources_path, args.addon[0])
    if lexists(source_path):
        print "Exists directory %s. Please remove it if you want a new dummy addon" % source_path
        return
    print "Creating dummy addon on %s" % source_path

    # Create addon path structure
    os.mkdir(source_path)
    for subdir in ['i18n', 'process', 'report', 'security', 'test', 'wizard']:
        os.mkdir(join(source_path, subdir))

    # Create __init__.py files
    for subdir in ['.', 'report', 'wizard']:
        with open(join(source_path, subdir, '__init__.py'), 'w') as file:
            file.write(defaults.openerp_header)
            file.write(defaults.init_body)
            file.write(defaults.openerp_footer)

    with open(join(source_path, oerpenv.desc_filename), 'w') as file:
        pp = pprint.PrettyPrinter(indent=4, stream=file)
        file.write(defaults.openerp_header)
        pp.pprint(defaults.addon_description(args.addon[0]))
        file.write(defaults.openerp_footer)

    oerpenv.save()

def test_addon(args):
    """
    Execute the server in test mode for this addon.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)
    addons_path = oerpenv.get_addonsourcepath()['server']

    if not all([lexists(join(addons_path, token)) for token in args.addon]):
        print "Not all addons are enable." 
        print "Execute 'oerpenv enable %s' before run this command." % ' '.join(args.addon) 
        return -1

    if args.snapshot is not None:
        print "Recovering snapshot '%s' of the database '%s'." % (args.snapshot, args.database)
        if not tools.recover_snapshot(args.database, args.snapshot, oerpenv):
            print "ERROR: Cant recover snapshot %s." % args.snapshot
            return -1
        dbname = args.database
    else:
        dbname = args.database if args.database is not None else "test_db_%s" % '_'.join(args.addon)

    try:
        if not tools.exists_db(dbname):
            print "Create db %s" % dbname
            tools.create_database(dbname);
    except PostgresNotRunningError, m:
        print m.message
        return -1

    print "Running test %s" % ','.join(args.addon)
    try:
        op = "-i" if args.keep_db else "-i"
        initarg = [op] + [ ','.join(args.addon) ]
        options = ['--stop-after-init', '--test-enable'] # Para la version 7.0
        if oerpenv.server_config_filename:
            options += [ '--config', oerpenv.server_config_filename ]
        if oerpenv._config['Environment.version'] in '6.0':
            options += [ '--test-report-directory', oerpenv.reports_path ]
        if args.debug:
            options += ['--debug', '--log-level=debug']
        else:
            options += ['--log-level=test']
        if args.commit:
            options += ['--test-commit']
        print "Executing:\n openerp-server", " ".join(options + initarg + ['-d', dbname])
        oerpenv.execute('openerp-server', initarg + ['-d', dbname] + options)
    except KeyboardInterrupt:
        print "KeyboardInterrupt event."
        exit(-1)
    except OSError, m:
        print "Error in the environment."
        print "ERROR: %s" % m
        print "If you move the environment please rebuild default python environment and check directories in environment.conf file."
        print "If all ok, be sure you executed 'oerpenv install' before run this command."

    notify_send = distutils.spawn.find_executable('notify-send')
    if notify_send:
        src_p = subprocess.Popen([ notify_send, 'Test finished'])

    if args.keep_db:
        pass
    else:
        print "Drop db %s" % dbname
        tools.drop_database(dbname);

    print "TEST FINISHED."

def start_client(args):
    """
    Execute the server in test mode for this addon.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    client_config_filename = join(oerpenv.env_path, 'etc', oerpenv.client_config_filename)

    print "Running client in environment %s" % args.environment
    try:
        oerpenv.execute('openerp-client', ['-c', client_config_filename])
    except KeyboardInterrupt:
        print "KeyboardInterrupt event."

def server_start(args):
    """
    Start the server.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    snapshot = args.snapshot if args.snapshot is not None else oerpenv.snapshot
    database =  args.database if args.database is not None else oerpenv.database
    debug =  args.debug or oerpenv.debug
    update =  args.update if args.update is not None else oerpenv.modules_update
    install =  args.install if args.install is not None else oerpenv.modules_install
    production =  args.production or oerpenv.production
    force_start = args.force_start or False
    language =  args.language if args.language is not None else oerpenv.language
    extracommands =  args.extracommands if args.extracommands is not None else oerpenv.extracommands

    options = []

    if database and database is not None:
        options += [ '-d', database ]

    if oerpenv.server_config_filename:
        options += [ '--config', oerpenv.server_config_filename ]

    if debug:
        options += [ '--debug' ]
        #options += [ '--log-level=debug_rpc', '--logfile=%s/openerp-server.log' % oerpenv.root_path ]

    if production:
        options += [ '--without-demo=all','--test-disable' ]

    if language is not None:
        options += [ '--load-language',language,'--language',language ]

    if not update is None and len(update) > 0:
        options += sum([ ['-u', module ] for module in update ], [])

    if not install is None and len(install) > 0:
        options += sum([ ['-i', module ] for module in install ], [])

    if extracommands is not None:
        options += extracommands

    if snapshot:
        if database is None:
            print "ERROR: Cant recover snapshot %s, because not defined database" % snapshot
            return -1
        print "Recovering snapshot '%s' of the database '%s'." % (snapshot, database)
        if not tools.recover_snapshot(database, snapshot, oerpenv):
            print "ERROR: Cant recover snapshot %s." % snapshot
            return -1
    try:
        pidfilename = join(oerpenv.root_path, '.server_pid')
        if lexists(pidfilename) and (not force_start):
            print "A server is running or .server_pid has not been deleted at the end of the server."
            print "Execute 'oerpenv stop' to stop the server and remove this file."
            return -1
        print "Running with options: %s" % ' '.join(options)
        pid = oerpenv.execute('openerp-server', options, no_wait=not debug)
        if not debug and pid is not None:
            f = open(pidfilename, 'w')
            f.write("%i" % pid)
            f.close()
        if pid is not None:
            #os.kill(pid, signal.SIGINT)
            pass
        else:
            print "Process terminated unexpectedly"
    except KeyboardInterrupt:
        print "KeyboardInterrupt event."
    except OSError, m:
        import sys, traceback
        print "Environment Error."
        print "ERROR: %s" % m
        traceback.print_exc(file=sys.stdout)
        print "If you move the environment please rebuild default python environment and check directories in environment.conf file."
        print "If all ok, be sure you executed 'oerpenv install' before run this command."

def server_stop(args):
    """
    Stop the server.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    pidfilename = join(oerpenv.root_path, '.server_pid')
    try:
        with open(pidfilename, 'r') as f:
            pid = int(f.readline())
        os.kill(pid, signal.SIGINT)
    except IOError, m:
        print "No server information."
        print "ERROR: %s" % m
        return -1
    except OSError, m:
        print "No server running."
        print "ERROR: %s" % m
        return -1
    os.remove(pidfilename)
    return 0

def web_start(args):
    """
    Start the web client.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    debug =  args.debug or oerpenv.debug
    extracommands =  args.extracommands if args.extracommands is not None else oerpenv.extracommands

    options = []

    if extracommands is not None:
        options += extracommands

    if oerpenv.web_config_filename:
        options += [ '--config', oerpenv.web_config_filename ]

    try:
        pidfilename = join(oerpenv.root_path, '.web_pid')
        if lexists(pidfilename):
            print "A web client is running or .web_pid has not been deleted at the end of the web client."
            print "Execute 'oerpenv web-stop' to stop the web client and remove this file."
            return -1
        print "Running with options: %s" % ' '.join(options)
        pid = oerpenv.execute('openerp-web', options, no_wait=not debug, check_for_termination=True)
        if not debug and pid is not None:
            f = open(pidfilename, 'w')
            f.write("%i" % pid)
            f.close()
        if pid is not None:
            pass
            #os.kill(pid, signal.SIGINT)
        else:
            print "Process terminated unexpectedly"
    except KeyboardInterrupt:
        print "KeyboardInterrupt event."
    except OSError, m:
        print "Environment Error."
        print "ERROR: %s" % m
        print "If you move the environment please rebuild default python environment and check directories in environment.conf file."
        print "If all ok, be sure you executed 'oerpenv install' before run this command."

def web_stop(args):
    """
    Stop the web client.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    pidfilename = join(oerpenv.root_path, '.web_pid')
    try:
        with open(pidfilename, 'r') as f:
            pid = int(f.readline())
        os.kill(pid, signal.SIGINT)
    except IOError, m:
        print "No web client information."
        print "ERROR: %s" % m
        return -1
    except OSError, m:
        print "No web client running."
        print "ERROR: %s" % m
        return -1
    os.remove(pidfilename)
    return 0


def search_object(args):
    """
    Search addons with this object.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    print "Definition:"
    for addon in oerpenv.addons(object_filter=args.objects[0]):
        print "%35s:%s" % (addon.token, addon.name)

    print "Inherited:"
    for addon in oerpenv.addons(inherited_filter=args.objects[0]):
        print "%35s:%s" % (addon.token, addon.name)
 
def search_entity(args):
    """
    Search in xml some declared entity with id
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)
 
    for addon in oerpenv.addons(entity_filter=args.entity[0]):
        print "%35s:%s:%s" % (addon.token, addon.name, ':'.join([ e for e in addon.entity(args.entity[0])]))
        #for filename, entity, = addon.entities

def show_addon(args):
    """
    Show addon information.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    addons = dict([ (addon.token, addon) for addon in oerpenv.addons(token_filter=args.objects[0]) ])
    if args.objects[0] in addons:
        addon = addons[args.objects[0]]
        print "Token:", addon.token
        print "Name:", addon.name
        print "Version:", addon.version
        print "Author:", addon.author
        print "Description:", addon.description
        print "Web:", addon.website
        print "Depends:", ','.join(addon.depends)
        objects = addon.objects
        print "Defined Objects:", ','.join(objects[0]) 
        print "Inhereted Objects:", ','.join(objects[1])
        print "Source:", addon.path 

def list_db(args):
    """
    List availables databases.
    """
    try:
        conn = psycopg2.connect("")
        cur = conn.cursor()
        cur.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in ('template0', 'template1', 'postgres') order by datname", (defaults.user,))
        rows = cur.fetchall()
        for (table,) in rows:
            print table
    except psycopg2.OperationalError, m:
        print "Is postgres running?"
        print "ERROR: %s" % m

def shell_db(args):
    """
    Execute a shell for sql commands over the database.
    """
    P = subprocess.Popen(['psql', args.database])
    P.wait()
    pass

def create_db(args):
    """
    Create a void database.
    """
    try:
        tools.create_database(args.database[0])
    except psycopg2.OperationalError, m:
        print "Is postgres running?"
        print "ERROR: %s" % m

def drop_db(args):
    """
    Remove a database.
    """
    try:
        tools.drop_database(args.database[0])
    except psycopg2.OperationalError, m:
        print "Is postgres running?"
        print "ERROR: %s" % m

def init_db(args):
    """
    Prepare a minimalistic OpenERP database.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    try:
        oerpenv.execute('openerp-server', ['--init', 'base', '-d', args.database[0], '--stop-after-init'])
    except KeyboardInterrupt:
        print "KeyboardInterrupt event."
    except OSError, m:
        print "Error in the environment."
        print "ERROR: %s" % m
        print "If you move the environment please rebuild default python environment and check directories in environment.conf file."
        print "If all ok, be sure you executed 'oerpenv install' before run this command."
    pass

def dump_db(args):
    """
    Create a backup file of a database.
    """
    dbname = args.database[0]
    if args.outfile is None:
        outfile = "%s.dump" % dbname
    else:
        outfile = args.outfile
    P = subprocess.Popen(['pg_dump', '-Fc', '--compress', '9', '-f', outfile, dbname])
    P.wait()
    pass

def snapshot(args):
    """
    Generate a database snapshot.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    snapshots = oerpenv.snapshots_path

    dbname = args.database[0]
    snapshot_name = args.name
    outfile = join(snapshots, "%s_%s.dump" % (dbname, snapshot_name))
    
    P = subprocess.Popen(['pg_dump', '-Fc', '--compress', '9', '-f', outfile, dbname])
    r = P.wait()
    if r:
        print "ERROR: Cant dump the snapshot."
 
def restore(args):
    """
    Restore a database snapshot.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    snapshots = oerpenv.snapshots_path

    dbname = args.database[0]
    snapshot_name = args.name
    infile = join(snapshots, "%s_%s.dump" % (dbname, snapshot_name))

    # Check if exists database
    cmd = ['psql', '-c', '\\q', '-d', dbname ]
    P = subprocess.Popen(cmd, stderr=subprocess.PIPE)
    r = P.wait()
    create_db = (r == 2)

    cmd = ['pg_restore', '-x', '-O', '--disable-triggers', '-Fc' ]
    if create_db:
            cmd.append('-C')
            cmd.append('-d')
            cmd.append('template1')
    else:
            cmd.append('-1')
            cmd.append('-c')
            cmd.append('-d')
            cmd.append(dbname)
    cmd.append(infile)

    P = subprocess.Popen(cmd)
    r = P.wait()

    if r:
        print "ERROR: Cant recover the snapshot."

def extradite(args):
    """
    Copy database from remote/local server to local/remote server.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    snapshots = oerpenv.snapshots_path

    operation = args.operation.pop()
    host = args.host.pop()
    dbname = args.database.pop()

    cmd = []
    if operation == 'from':
        drp_cmd = [ 'psql', '-c' ,'DROP DATABASE IF EXISTS \"%s\"' % dbname ]
        src_cmd = [ 'ssh', host, 'pg_dump', '-Fc', '--compress', '9', dbname ]
        dst_cmd = [ 'pg_restore', '-x', '-C', '-O', '--disable-triggers', '-Fc', '-d', 'postgres' ]
    elif operation == 'to':
        drp_cmd = [ 'ssh', host, 'psql', '-c' ,'DROP DATABASE IF EXISTS %s' % dbname ]
        src_cmd = [ 'pg_dump', '-Fc', '--compress', '9', dbname ]
        dst_cmd = [ 'ssh', host, 'pg_restore', '-x', '-C', '-O', '--disable-triggers', '-Fc', '-d', 'postgres' ] 
    else:
        print "ERROR: Invalid operation. Options are from or to."
        return

    drp_p = subprocess.Popen(drp_cmd) #, stdout=subprocess.PIPE)
    drp_p.poll()
    src_p = subprocess.Popen(src_cmd, stdout=subprocess.PIPE)
    dst_p = subprocess.Popen(dst_cmd, stdin=src_p.stdout, stdout=subprocess.PIPE)
    src_p.stdout.close()
    output = dst_p.communicate()
    dst_p.poll()
    src_p.poll()
        
    return

def pip(args):
    """
    Install Python packages in the virtual environment.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    command =  args.command[0] if args.command[0] in [
        'help', 'install', 'bundle', 'freeze', 'install',
        'search', 'uninstall', 'unzip', 'zip' ] else 'help'
    parameters =  args.parameters

    options = [ command ]

    if parameters is not None:
        options += parameters

    pid = oerpenv.execute('pip', options, no_wait=0)

def csv2xml(args):
    """
    Convert CSV files to an XML files.
    """
    infile =  args.infile.pop()
    outfile =  args.outfile.pop()
    id_template =  args.id_template if args.id_template is not None else None
    maps = args.map if args.map is not None else []

    # Read maps of references
    import xml.etree.ElementTree as ET
    mapping_dict = {}
    mapping = {}
    for map in maps:
        filename, model, name, fields = map.split(':')
        tree = ET.parse(filename)
        root = tree.getroot()
        mapping_dict[model] = {}
        for record in root.findall("./data/record[@model='%s']"%model):
            mapping_dict[model][record.find("./field[@name='%s']"%name).text] = record.attrib['id']
        for field in fields.split(','):
            mapping[field] = mapping_dict[model]

    with open(infile) as IN:
        import csv
        from Cheetah.Template import Template

        templateDef = """\
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
    <data noupdate="True">
        #for $id, $record in $records
        <record model='$model' id='$id'>
            #for $key, $value in $record.items()
            #if $key in $mapping
                <field name='$key' ref='$mapping[$key][$value]'/>
            #else
                <field name='$key'>$value</field>
            #end if
            #end for
        </record> 
        #end for
    </data>
</openerp>
        """
        reader = csv.DictReader(IN)
        if id_template is not None:
            pass
        elif 'code' in reader.fieldnames:
            id_template = "%(code)s"
        else:
            id_template = "%(_id)s"

        records = list(reader)
        records = zip(range(len(records)), records)
        records = [ (id_template % dict(r, _id=id), r) for id, r in records ]

        nameSpace={'model': '.'.join(infile.split('.')[:-1]),
                   'records': records,
                   'mapping': mapping}
        t = Template(templateDef, searchList=[nameSpace])

        with open(outfile, 'w') as OUT:
            print >> OUT, t


def activate(args):
    """
    Active bash instance in virtual environment.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    print "Activating"
    path=join(oerpenv.env_path, 'bin', 'activate')
    P = subprocess.Popen(['bash', path ])
    P.wait()

def repath(args):
    """
    Change path to enviroment scripts.
    """
    oerpenv = OpenERPEnvironment(config_filename=args.config)
    oerpenv.set_python_environment(args.environment)

    binpath_re = re.compile('^#!(.*)(bin/)(.*)$')
    linkpath_re = re.compile('^(.*)(sources/.*)$')


    print "Repathing links...",
    for root, dirs, files in os.walk("./default", topdown=False):
        for filename in files:
            ori_filename = join(root,filename)
            if islink(ori_filename):
                ori_link = abspath(join(dirname(ori_filename), readlink(ori_filename)))
                if ori_link.find(oerpenv.env_path):
                    m = linkpath_re.search(ori_link)
                    if m:
                        ori_path, ori_link = m.groups()
                        tar_link = abspath(join(oerpenv.root_path, ori_link))
                        remove(ori_filename)
                        symlink(tar_link, ori_filename)
    print "Done"

    print "Repathing scripts...",
    for root, dirs, files in os.walk("./default/bin", topdown=False):
        for filename in files:
            ori_filename = join(root,filename)
            with  open(ori_filename) as f:
                l = f.readline()
                m = binpath_re.search(l)
                if m:
                    ori_path, default_bin, bin_file = m.groups()
                    new_first_line =  "#!%s\n" % abspath(join(oerpenv.env_path, default_bin, bin_file))
                    tar_filename = join(root, filename + '.new')
                    with open(tar_filename, 'w') as df:
                        df.write(new_first_line)
                        for l in f:
                            df.write(l)
                        df.close()
                        f.close()
                        rename(tar_filename, ori_filename)
                        chmod(ori_filename,
                              stat.S_IXOTH | stat.S_IXGRP | stat.S_IXUSR |
                              stat.S_IROTH | stat.S_IRGRP | stat.S_IRUSR |
                              stat.S_IWUSR)
                else:
                    f.close()
    print "Done"

def main():
    parser = argparse.ArgumentParser()

    subparsers = parser.add_subparsers(help='commands',
                                       description='The OpenERP environment administrator help you to administrate OpenERP environments. You can use the following commands.')

    # The init command
    parser_init = subparsers.add_parser('init', help=init.__doc__)

    parser_init.add_argument('path', metavar='path', type=str, nargs='?',
                             help='Path to the environment to init.')
    parser_init.add_argument('--repository', '-r', metavar='repository', type=str, nargs='?',
                             help='Local repository of sources.')
    parser_init.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_init.add_argument('--version', '-v', metavar='version', type=str, nargs='?',
                             help='OpenERP version to setup')
    parser_init.set_defaults(func=init,
                             config=defaults.config_filename,
                             version=defaults.version)

    # The setup command
    parser_setup = subparsers.add_parser('setup', help=init.__doc__)

    parser_setup.add_argument('--repository', '-r', metavar='repository', type=str, nargs='?',
                             help='Local repository of sources.')
    parser_setup.set_defaults(func=setup,
                             config=defaults.config_filename,
                             version=defaults.version)

    # The update command
    parser_update = subparsers.add_parser('update', help=update.__doc__)
    parser_update.add_argument('repositories', metavar='repositories', type=str, nargs='*',
                             help='Repositories to update. None means all.')
    parser_update.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_update.set_defaults(func=update,
                             repositories=None,
                             config=defaults.config_filename)

    # The create command
    parser_create = subparsers.add_parser('create', help=create.__doc__)
    parser_create.add_argument('name', metavar='name', type=str, nargs=1,
                             help='Name for the python environment.')
    parser_create.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_create.set_defaults(func=create,
                             config=defaults.config_filename)

    # The add command
    parser_add = subparsers.add_parser('add', help=add.__doc__)
    parser_add.add_argument('name', metavar='name', type=str, nargs=1,
                             help='Name of the branch.')
    parser_add.add_argument('url', metavar='url', type=str, nargs=1,
                             help='URL to the repository.')
    parser_add.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_add.set_defaults(func=add,
                             config=defaults.config_filename)

    # The install command
    parser_install = subparsers.add_parser('install', help=install.__doc__)
    parser_install.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_install.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_install.add_argument('itemstoinstall', metavar='item_to_install', type=str, nargs='*',
                             help='Item to install.')
    parser_install.set_defaults(func=install,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             )

    # The list_installables command
    parser_list_installables = subparsers.add_parser('list-installables', help=list_installables.__doc__)
    parser_list_installables.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_list_installables.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_list_installables.set_defaults(func=list_installables,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The list_addons command
    parser_list_addons = subparsers.add_parser('list-addons', help=list_addons.__doc__)
    parser_list_addons.add_argument('filter_string', metavar='filter_string', type=str, nargs='?',
                             help='String filter.')
    parser_list_addons.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_list_addons.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_list_addons.set_defaults(func=list_addons,
                             filter_string='',
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The enable_addon command
    parser_enable_addon = subparsers.add_parser('enable', help=enable_addon.__doc__)
    parser_enable_addon.add_argument('addon', metavar='addon', type=str, nargs='+',
                             help='Addon name.')
    parser_enable_addon.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_enable_addon.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_enable_addon.add_argument('--ignore-filter', '-i', metavar='ignore_filter', type=str, nargs='?',
                             help='Ignore addons with directory accepted by this regular expression.')
    parser_enable_addon.add_argument('--ignore-depends', '-d', action='store_true',
                             help='Not install dependecies.')
    parser_enable_addon.set_defaults(func=enable_addon,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             filter=None)

    # The disable_addon command
    parser_disable_addon = subparsers.add_parser('disable', help=disable_addon.__doc__)
    parser_disable_addon.add_argument('addon', metavar='addon', type=str, nargs=1,
                             help='Addon name.')
    parser_disable_addon.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_disable_addon.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_disable_addon.set_defaults(func=disable_addon,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The dummy command
    parser_create_dummy_addon = subparsers.add_parser('dummy', help=create_dummy_addon.__doc__)
    parser_create_dummy_addon.add_argument('addon', metavar='addon', type=str, nargs=1,
                             help='Addon name.')
    parser_create_dummy_addon.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_create_dummy_addon.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_create_dummy_addon.set_defaults(func=create_dummy_addon,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The test command
    parser_test_addon = subparsers.add_parser('test', help=test_addon.__doc__)
    parser_test_addon.add_argument('addon', metavar='addon', type=str, nargs='+',
                             help='Addon name.')
    parser_test_addon.add_argument('--database', '-d', metavar='database', type=str, nargs='?',
                             help='Database name.')
    parser_test_addon.add_argument('--snapshot', '-s', metavar='snapshot', type=str, nargs='?',
                             help='Snapshot name.')
    parser_test_addon.add_argument('--keep-db', '-k', action='store_true',
                             help='Don\'t drop db at end.')
    parser_test_addon.add_argument('--commit', '-m', action='store_true',
                             help='Commit test changes in database.')
    parser_test_addon.add_argument('--debug', '-g', action='store_true',
                             help='Set server in debug mode.')
    parser_test_addon.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_test_addon.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_test_addon.set_defaults(func=test_addon,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             )

    # The client command
    parser_start_client = subparsers.add_parser('client', help=start_client.__doc__)
    parser_start_client.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_start_client.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_start_client.set_defaults(func=start_client,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The server-start subcommand
    parser_server_start = subparsers.add_parser('server-start', help=server_start.__doc__)
    parser_server_start.add_argument('--database', '-D',  metavar='database', type=str, nargs='?',
                             help='Database name.')
    parser_server_start.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_server_start.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_server_start.add_argument('--snapshot', '-s', metavar='snapshot', type=str, nargs='?',
                             help='Snapshot of the database.')
    parser_server_start.add_argument('--debug', '-d', action='store_true',
                             help='Start server in debug mode. Stop until an exception.')
    parser_server_start.add_argument('--force-start', '-f', action='store_true',
                             help='Forces server start. Does not check whether a process file is present or not.')
    parser_server_start.add_argument('--production', '-p', action='store_true',
                             help='Start server in production mode. No test and demos.')
    parser_server_start.add_argument('--update', '-u', metavar='MODULES', type=str, nargs='*',
                             help='Update modules')
    parser_server_start.add_argument('--install', '-i', metavar='MODULES', type=str, nargs='*',
                             help='Install modules')
    parser_server_start.add_argument('--language', '-l', metavar='LANG', type=str, nargs='?',
                             help='Default Language')
    parser_server_start.add_argument('extracommands', nargs='*', help='Commands direct to openerp-server')
    parser_server_start.set_defaults(func=server_start,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             extracommands=None)

    # The stop subcommand
    parser_server_stop = subparsers.add_parser('server-stop', help=server_stop.__doc__)
    parser_server_stop.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_server_stop.set_defaults(func=server_stop,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The web-start subcommand
    parser_web_start = subparsers.add_parser('web-start', help=web_start.__doc__)
    parser_web_start.add_argument('--debug', '-d', action='store_true',
                             help='Start web client in debug mode. Stop until an exception.')
    parser_web_start.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_web_start.add_argument('extracommands', nargs='*', help='Commands direct to openerp-web')
    parser_web_start.set_defaults(func=web_start,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             extracommands=None)

    # The stop subcommand
    parser_server_stop = subparsers.add_parser('web-stop', help=web_stop.__doc__)
    parser_server_stop.set_defaults(func=web_stop,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The search_object command
    parser_search_object = subparsers.add_parser('search-object', help=search_object.__doc__)
    parser_search_object.add_argument('objects', metavar='objects', type=str, nargs=1,
                             help='Object name.')
    parser_search_object.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_search_object.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_search_object.set_defaults(func=search_object,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The search_entity command
    parser_search_entity = subparsers.add_parser('search-entity', help=search_entity.__doc__)
    parser_search_entity.add_argument('entity', metavar='entity', type=str, nargs=1,
                             help='Entity name.')
    parser_search_entity.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_search_entity.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_search_entity.set_defaults(func=search_entity,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The show_addon command
    parser_show_addon = subparsers.add_parser('show', help=show_addon.__doc__)
    parser_show_addon.add_argument('objects', metavar='objects', type=str, nargs=1,
                             help='Object name.')
    parser_show_addon.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_show_addon.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_show_addon.set_defaults(func=show_addon,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The list-db command
    parser_list_db = subparsers.add_parser('list-db', help=list_db.__doc__)
    parser_list_db.set_defaults(func=list_db)

    # The shell-db command
    parser_shell_db = subparsers.add_parser('shell-db', help=shell_db.__doc__)
    parser_shell_db.add_argument('database', metavar='database', type=str, nargs='?',
                             help='Database name.')
    parser_shell_db.set_defaults(func=shell_db,
                             database=defaults.user)

    # The create-db command
    parser_create_db = subparsers.add_parser('create-db', help=create_db.__doc__)
    parser_create_db.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_create_db.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_create_db.set_defaults(func=create_db,
                             config=defaults.config_filename)

    # The drop-db command
    parser_drop_db = subparsers.add_parser('drop-db', help=drop_db.__doc__)
    parser_drop_db.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_drop_db.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_drop_db.set_defaults(func=drop_db,
                             config=defaults.config_filename)

    # The init-db command
    parser_init_db = subparsers.add_parser('init-db', help=init_db.__doc__)
    parser_init_db.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_init_db.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_init_db.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_init_db.set_defaults(func=init_db,
                             environment=defaults.python_environment,
                             config=defaults.config_filename)

    # The snapshot command
    parser_snapshot = subparsers.add_parser('snapshot', help=snapshot.__doc__)
    parser_snapshot.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_snapshot.add_argument('name', metavar='name', type=str, nargs='?',
                             help='Snapshot name.')
    parser_snapshot.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_snapshot.set_defaults(func=snapshot,
                             name=datetime.datetime.today().strftime("%Y%m%d%H%M%S"),
                             config=defaults.config_filename)

    # The extradite command
    parser_extradite = subparsers.add_parser('extradite', help=extradite.__doc__)
    parser_extradite.add_argument('operation', metavar='name', type=str, nargs=1,
                             help='from or to.')
    parser_extradite.add_argument('host', metavar='database', type=str, nargs=1,
                             help='Host origin/target of the database')
    parser_extradite.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_extradite.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_extradite.set_defaults(func=extradite,
                             config=defaults.config_filename)

    # The restore command
    parser_restore = subparsers.add_parser('restore', help=restore.__doc__)
    parser_restore.add_argument('database', metavar='database', type=str, nargs=1,
                             help='Database name.')
    parser_restore.add_argument('name', metavar='name', type=str, nargs='?',
                             help='Snapshot name.')
    parser_restore.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_restore.set_defaults(func=restore,
                             config=defaults.config_filename)

    # The pip command
    parser_pip = subparsers.add_parser('pip', help=pip.__doc__)
    parser_pip.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_pip.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_pip.add_argument('command', metavar='command', type=str, nargs=1,
                             help='Pip command [help, install, bundle, freeze, install, search, uninstall, unzip, zip]')
    parser_pip.add_argument('parameters', nargs='*', help='Parameters to pip command')
    parser_pip.set_defaults(func=pip,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             parameters=None)

    # The csv2xml command
    parser_csv2xml = subparsers.add_parser('csv2xml', help=csv2xml.__doc__)
    parser_csv2xml.add_argument('infile', metavar='infile', type=str, nargs=1,
                             help='CSV file to convert in xml')
    parser_csv2xml.add_argument('outfile', metavar='outfile', type=str, nargs=1,
                             help='XML destination file')
    parser_csv2xml.add_argument('id_template', metavar='id_template', type=str, nargs='?',
                             help='Template for record id')
    parser_csv2xml.add_argument('--map', '-m', metavar='map', type=str, nargs='*',
                                help='Map a reference to an id in XML file. Format: [filename.xml]:[model]:[ID field]:[separated by comma list of fields witch refer the record model]')
    parser_csv2xml.set_defaults(func=csv2xml,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             id_template=None)

    # The activate command
    parser_activate = subparsers.add_parser('activate', help=activate.__doc__)
    parser_activate.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_activate.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_activate.set_defaults(func=activate,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             parameters=None)

    # The activate command
    parser_repath = subparsers.add_parser('repath', help=repath.__doc__)
    parser_repath.add_argument('--environment', '-e', metavar='environment', type=str, nargs='?',
                             help='Python environment name.')
    parser_repath.add_argument('--config', '-c', metavar='config', type=str, nargs='?',
                             help='Environment configuration file.')
    parser_repath.set_defaults(func=repath,
                             environment=defaults.python_environment,
                             config=defaults.config_filename,
                             parameters=None)

    # Parse and execute
    args = parser.parse_args()

    try:
        args.func(args)
    except NoEnvironmentConfigFileError, m:
        print "ERROR:", m.message
        print """
Go to a environment directory where environment.conf exists, or
create one using 'oerpenv init' command.
"""
        return -1
    except NoVersionAvailableError, m:
        print "ERROR:", m.message
        print """
I can't manage this version. Please advise to developers using
this link http://launchpad.org/oerpenv/bugs. 


"""
        return -1
    return 0


#def signal_handler(signal, frame):
#    print "WARNING: STOP by user."
#    sys.exit(-1)

if __name__ == "__main__":
#    signal.signal(signal.SIGINT, signal_handler)

    r = main()
    sys.exit(r)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
