#!/usr/bin/env python
import os
import sys
import argparse
import subprocess
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)
    appType = packageInfo['type']
    currentVersionNum = os.path.basename(os.getcwd())
    facilitiesConfig = toolconfig.getFacilityConfig()
    for facilityConfig in facilitiesConfig:
        commandsAndArgs = []
        packageReleaseFolder = os.path.join(facilityConfig[appType]['releaseFolder'], packageInfo['name'])
        releaseFolder = os.path.join(packageReleaseFolder, currentVersionNum)
        commandsAndArgs.append(('fileinfo', [packageReleaseFolder]))
        commandsAndArgs.append(('fileinfo', [releaseFolder]))
        results = multi_facility_process_helper_client.executeCommandsOnFacility(facilityConfig['name'],
                                                                                 commandsAndArgs)
        packageTopInfo = results[0]
        if not packageTopInfo:
            print "Skipping pushing release to ", facilityConfig['name'], " as the top level folder is missing"
            continue;
        fileinforet = results[1]
        if releaseFolder in fileinforet:
            if not freshen:
                print "Release ", currentVersionNum, " already exists on facility ", facilityConfig[
                    'name'], "Use --freshen to update a release that has previously been pushed."
                continue

        rsyncDestPath = facilityConfig['ssh'] + ":" + os.path.join(facilityConfig[appType]['releaseFolder'],
                                                                   packageInfo['name'], currentVersionNum)
        if globals.verbose:
            print "RSyncing to ", 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", 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 ", facilityConfig['name']
            commandsAndArgs = []
            arg = {}
            arg['name'] = packageInfo['name']
            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", currentVersionNum, "to", 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:])
