#!/usr/bin/python
#
# client showing use of command_hook_mirror

from simplestreams import mirrors
from simplestreams.mirrors import command_hook

import argparse
import logging
import sys
import os
import yaml

LOG = logging.getLogger('sstream-sync')
LOG.setLevel(logging.ERROR)
LOG.addHandler(logging.StreamHandler())

def which(program):
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, _fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None


def warn(msg):
    sys.stderr.write("WARN: %s" % msg)


def main():
    parser = argparse.ArgumentParser()
    defhook = command_hook.DEFAULT_HOOK_NAME

    hooks = [("--hook-%s" % hook.replace("_", "-"), hook, False)
             for hook in command_hook.HOOK_NAMES]
    hooks.append(('--hook', defhook, False,))
    
    parser.add_argument('--config', '-c',
                        help='read config file',
                        type=argparse.FileType('rb'))

    for (argname, cfgname, required) in hooks:
        parser.add_argument(argname, dest=cfgname, required=False)

    parser.add_argument('--keep', action='store_true', default=False,
                        help='keep items in target up to MAX items '
                             'even after they have fallen out of the source')
    parser.add_argument('--max', type=int, default=None,
                        help='store at most MAX items in the target')
    parser.add_argument('--item-skip-download', action='store_true',
                        default=False,
                        help='Do not download items that are to be inserted.')

    parser.add_argument('--path', default="streams/v1/index.sjs",
                        help='sync from index or products file in mirror')
    parser.add_argument('mirror_url')
    cmdargs = parser.parse_args()

    known_cfg = [('--item-skip-download', 'item_skip_download', False),
                 ('--max', 'max', False),
                 ('--keep', 'keep', False),
                 ('mirror_url', 'mirror_url', True),
                 ('--path', 'path', True)]
    known_cfg.extend(hooks)

    cfg = {}
    if cmdargs.config:
        cfg = yaml.safe_load(cmdargs.config)
        if not cfg:
            cfg = {}

    known_names = [i[1] for i in known_cfg]
    unknown = [key for key in cfg if key not in known_names]
    if unknown:
        warn("unknown keys in config: %s\n" % str(unknown))

    missing = []
    fallback = cfg.get(defhook, getattr(cmdargs, defhook, None))

    for (argname, cfgname, required) in known_cfg:
        val = getattr(cmdargs, cfgname)
        if val is not None:
            cfg[cfgname] = val
        if val == "":
            cfg[cfgname] = None
        print cfgname, val

        if ((cfgname in command_hook.HOOK_NAMES or cfgname == defhook)
            and cfg.get(cfgname) is not None):
            if which(cfg[cfgname]) is None:
                msg = "invalid input for %s. '%s' is not executable\n"
                sys.stderr.write(msg % (argname, val))
                sys.exit(1)

        if (cfgname in command_hook.REQUIRED_FIELDS and
            cfg.get(cfgname) is None and not fallback):
            missing.append((argname, cfgname,))

    if missing:
        sys.stderr.write("must provide input for (--hook/%s for default):\n"
                         % defhook)
        for (flag, cfg) in missing:
            sys.stderr.write("  cmdline '%s' or cfgname '%s'\n" % (flag, cfg))
        sys.exit(1)

    smirror = mirrors.UrlMirrorReader(cfg['mirror_url'])
    tmirror = command_hook.CommandHookMirror(config=cfg)
    tmirror.sync(smirror.reader, cfg['path'])

if __name__ == '__main__':
    main()
