#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import argparse
import ConfigParser
import datetime
import os
import platform
import shlex
import subprocess
import sys

USER_CONFIG = '~/.java_driver_tests.conf'

def read_config(section, option, data_type='string', default=None):
    '''Read configs as stored in the above defined USER_CONFIG.'''

    config = ConfigParser.ConfigParser()
    config.read([os.path.expanduser(USER_CONFIG)])

    if config.has_option(section, option):
        if data_type == 'string':
            to_return = config.get(section, option)
        elif data_type == 'boolean':
            to_return = config.getboolean(section, option)
        return default if default else to_return

    return default if default else False

def read_commandline(command):
    '''Simple shell read access.'''

    return subprocess.check_output(command, shell=True)

def execute(command):
    '''Simple shell execute access.'''

    print 'Running command:\n\t%s\n' % command
    subprocess.call(shlex.split(command))

def parse():
    '''Creates the argument parser for this tool.'''

    parser = argparse.ArgumentParser(description='command line tool for quick testing commands.')
    parser.add_argument('--test', help='run a specific unit test')
    parser.add_argument('--cassandra-version', help='run tests on a specific Cassandra version')
    parser.add_argument('--upload', action='store_true', help='upload cobertura site to configured server')
    parser.add_argument('--clean', action='store_true', help='runs the maven project from a clean environment')
    parser.add_argument('--automated', action='store_true', help='ensures that runs do not get hung up by user input requests')
    parser.add_argument('--testdocs', action='store_true', help='generates the test\'s Javadoc')
    parser.add_argument('--samplecode', action='store_true', help='prints generated sample CQL')
    args = parser.parse_args()
    return args

def check_path():
    '''Ensures this tool is run from the java-driver home directory.'''

    if not 'driver-core' in read_commandline('ls'):
        sys.exit('Execute this command from your java-driver root directory.')


def maybe_setup_loopbacks():
    '''Currently only setting loopbacks for Mac OSX, but feel free to contribute for other setups.'''

    if platform.system() == 'Darwin' and not read_config('general', 'no_loopbacks', data_type='boolean'):
        print 'Setting up CCM loopbacks...'
        try:
            loopbacks_enabled = read_commandline('ifconfig | grep "inet 127.0.1.4 netmask 0xff000000"')
            if not loopbacks_enabled:
                raise subprocess.CalledProcessError
        except subprocess.CalledProcessError:
            # For basic ccm
            execute('sudo ifconfig lo0 alias 127.0.0.2 up')
            execute('sudo ifconfig lo0 alias 127.0.0.3 up')

            # Additional loopbacks for the java-driver
            execute('sudo ifconfig lo0 alias 127.0.1.1 up')
            execute('sudo ifconfig lo0 alias 127.0.1.2 up')
            execute('sudo ifconfig lo0 alias 127.0.1.3 up')
            execute('sudo ifconfig lo0 alias 127.0.1.4 up')
            execute('sudo ifconfig lo0 alias 127.0.1.5 up')
            execute('sudo ifconfig lo0 alias 127.0.1.6 up')

def maybe_upload_cobertura_site():
    '''
    The following must be set in the above defined USER_CONFIG:
    [general]
    cobertura_server = xxx
    cobertura_directory = xxx

    If defined, the cobertura site will be rsync'd to a remote location.
    '''

    cobertura_server = read_config('general', 'cobertura_server')
    cobertura_directory = read_config('general', 'cobertura_directory')

    if cobertura_server and cobertura_directory:
        print 'rsync-ing cobertura site to %s:%s...' % (
                cobertura_server,
                cobertura_directory)
        execute('rsync -avz testing/cobertura-history %s:%s' % (
                cobertura_server,
                cobertura_directory))

def save_cobertura_site():
    '''Save cobertura site folders by date'''

    execute('mkdir -p testing/cobertura-history')
    today = datetime.date.today()
    execute('cp -r driver-core/target/site/cobertura testing/cobertura-history/cobertura-%s' % today)
    execute('rm -rf testing/cobertura-history/current')
    execute('cp -r driver-core/target/site/cobertura testing/cobertura-history/current')

def main():
    check_path()
    args = parse()

    # Check if an upload is all that is required
    if args.upload:
        maybe_upload_cobertura_site()
        sys.exit()

    if args.testdocs:
        execute('mvn javadoc:test-javadoc')
        print '\nTo view test Javadocs:'
        print '\topen driver-core/target/site/testapidocs/index.html'
        sys.exit()

    # Setup required ccm loopbacks
    maybe_setup_loopbacks()

    # Start building the mvn command
    cobertura_build_command = 'mvn'

    # Add the clean target, if asked or building the entire project
    if args.clean or not args.test:
        cobertura_build_command += ' clean'

    cobertura_build_command += ' versions:display-dependency-updates'   # Ensures dependencies are up to date
    cobertura_build_command += ' cobertura:cobertura'                   # Runs code coverage plugin
    cobertura_build_command += ' --projects driver-core'                # Runs only the main module

    if args.samplecode:
        cobertura_build_command += ' -Pdoc'                             # Runs the docs "tests" and prints sample code
    else:
        cobertura_build_command += ' -Plong'                            # Runs the integration tests, not just tests

    # Use a specific Cassandra version, if asked
    if args.cassandra_version:
        cobertura_build_command += ' -Dcassandra.version=%s' % args.cassandra_version

    if args.test:
        # Run against a single mvn test
        execute('%s'
                ' -Dmaven.test.failure.ignore=true'
                ' -DfailIfNoTests=false'
                ' -Dtest=%s' % (cobertura_build_command, args.test))
    else:
        # Run against the entire integration suite
        execute('%s' % cobertura_build_command)

        try:
            if args.automated or raw_input('Save Cobertura Report? [y/N] ').lower() == 'y':

                # Save out cobertura site files
                save_cobertura_site()

                # Perhaps move cobertura site files to a central location
                maybe_upload_cobertura_site()
        except KeyboardInterrupt:
            print

    # Optionally, open coverage report when done building
    if read_config('general', 'open_cobertura_site_after_build', 'boolean'):
        execute('open driver-core/target/site/cobertura/index.html')
    else:
        print '\nTo view Cobertura report:'
        print '\topen driver-core/target/site/cobertura/index.html'


if __name__ == '__main__':
    main()
