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

from simplestreams import mirrors
from simplestreams.mirrors import command_hook
from simplestreams import log
from simplestreams import util

import argparse
import sys
import os
import yaml


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,
                        dest='keep_items',
                        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, dest='max_items',
                        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=None,
                        help='sync from index or products file in mirror')

    parser.add_argument('--verbose', '-v', action='count', default=0)
    parser.add_argument('--log-file', default=sys.stderr,
                        type=argparse.FileType('w'))

    parser.add_argument('mirror_url')
    cmdargs = parser.parse_args()

    known_cfg = [('--item-skip-download', 'item_skip_download', False),
                 ('--max', 'max_items', False),
                 ('--keep', 'keep_items', 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

        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,))

    pfm = util.path_from_mirror_url
    (cfg['mirror_url'], cfg['path']) = pfm(cfg['mirror_url'], cfg.get('path'))

    print("cfg['path']=%s cfg['mirror']=%s" % (cfg['path'], cfg['mirror_url']))

    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)

    level = (log.ERROR, log.INFO, log.DEBUG)[min(cmdargs.verbose, 2)]
    log.basicConfig(stream=cmdargs.log_file, level=level)

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

if __name__ == '__main__':
    main()

# vi: ts=4 expandtab syntax=python
