#!/usr/bin/env python
from __future__ import print_function

import os
import sys
import argparse
import subprocess
import traceback
import globals
import toolconfig
import multi_facility_process_helper_client
from globals import UserParamsException


def pushRelease(freshen):
    """Submits a release to the build and release process.
    This is largely a process of rsync'ing the contents of this folder to the correct places.
    We identify this package and use the tool configuration to determine rsync dest locations.
    You have to run cram push from the folder containing the release.
    We also honor rsync include and exclude files that are present in the .cram folder.
    Global include and exclude files are .cram/push_include and .cram/push_exclude.
    Facility_specific include and exclude files are .cram/<facility>_push_include and .cram/<facility>_push_exclude.
    """
    packageInfo = toolconfig.readPackageConfig(autoDescribeRelease=True)
    appName = packageInfo['name']
    appType = packageInfo['type']
    for facility in toolconfig.getListOfFacilities():
        pushReleaseToFacility(appName, appType, facility, freshen);

def pushReleaseToFacility(appName, appType, facility, freshen):
    currentVersionNum = os.path.basename(os.getcwd())
    commandsAndArgs = []
    facilityConfig = toolconfig.getConfigForFacility(facility)
    packageReleaseFolder = os.path.join(facilityConfig[appType]['releaseFolder'], appName)
    releaseFolder = os.path.join(packageReleaseFolder, currentVersionNum)
    commandsAndArgs.append(('fileinfo', [packageReleaseFolder]))
    commandsAndArgs.append(('fileinfo', [releaseFolder]))
    try:
        results = multi_facility_process_helper_client.executeCommandsOnFacility(facilityConfig['name'], commandsAndArgs)
    except multi_facility_process_helper_client.connectionException as e:
        print("Skipping pushing release to facility {0} as we are unable to talk to the server.".format(facilityConfig['name']))
        if globals.verbose:
            traceback.print_exc(file=sys.stdout)
        return

    packageTopInfo = results[0]
    if not packageTopInfo:
        print("Skipping pushing release to {0} as the top level folder is missing".format(facilityConfig['name']))
        return;
    fileinforet = results[1]
    if releaseFolder in fileinforet:
        if not freshen:
            print("Release {0} already exists on facility {1} Use --freshen to update a release that has previously "
                  "been pushed.".format(currentVersionNum, facilityConfig['name']))
            return

    rsyncDestPath = facilityConfig['ssh'] + ":" + os.path.join(facilityConfig[appType]['releaseFolder'],
                                                               appName, currentVersionNum)
    if globals.verbose:
        print("RSyncing to {0}".format(rsyncDestPath))

    rsync_manifest_args = []
    includePath = os.path.join(".cram", "push_include")
    if os.path.exists(includePath):
        rsync_manifest_args.extend(["--include-from", includePath])
    includePath = os.path.join(".cram", facilityConfig['name'] + "_push_include")
    if os.path.exists(includePath):
        rsync_manifest_args.extend(["--include-from", includePath])
    excludePath = os.path.join(".cram", "push_exclude")
    if os.path.exists(excludePath):
        rsync_manifest_args.extend(["--exclude-from", excludePath])
    excludePath = os.path.join(".cram", facilityConfig['name'] + "_push_exclude")
    if os.path.exists(excludePath):
        rsync_manifest_args.extend(["--exclude-from", excludePath])
    if globals.verbose:
        print("Manifest args {0}".format(rsync_manifest_args))
    rsyncextraargs = "-rltD"
    if globals.verbose:
        rsyncextraargs = "-rltDv"
    if toolconfig.usesGateway(facilityConfig['name']):
        subprocess.check_call(
            ['rsync', rsyncextraargs] + rsync_manifest_args + ['-e', 'ssh ' + facilityConfig['gateway'] + ' ssh',
                                                               '.', rsyncDestPath])
    else:
        subprocess.check_call(['rsync', rsyncextraargs] + rsync_manifest_args + ['-e', 'ssh', '.', rsyncDestPath])
    if appType in ['SIOC', 'HIOC']:
        if globals.verbose:
            print("Fixing up envPaths on {0}".format(facilityConfig['name']))
        commandsAndArgs = []
        arg = {}
        arg['name'] = appName
        arg['type'] = appType
        arg['facility'] = facilityConfig['name']
        arg['releaseFolder'] = facilityConfig[appType]['releaseFolder']
        arg['linkFolder'] = facilityConfig[appType]['linkFolder']
        arg['release'] = currentVersionNum
        commandsAndArgs.append(('fixEnvPathsForAllIOCs', arg))
        results = multi_facility_process_helper_client.executeCommandsOnFacility(facilityConfig['name'],
                                                                                 commandsAndArgs)

    print("Pushed release {0} to {1}".format(currentVersionNum, facilityConfig['name']))


def execute(args):
    parser = argparse.ArgumentParser(prog="cram push",
                                     description="Pushes a release (the contents of the current folder) to all the facilities. This is largely a process of rsync'ing the contents of the current folder " + os.getcwd() + " to the releaseFolder's in all the facilities for this software package. You must run cram push from the folder containing the release. The folder name must match the version.")
    parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose logging')
    parser.add_argument('-f', '--freshen', action='store_true', help='Freshen/updates an existing release')
    args = parser.parse_args(args)
    globals.verbose = args.verbose

    try:
        pushRelease(args.freshen)
    except UserParamsException as upe:
        if not globals.verbose and not globals.isunittests:
            print(upe)
            sys.exit(-1)
        else:
            raise


if __name__ == "__main__":
    execute(sys.argv[1:])
