#!/usr/bin/env python3.7
# vim:se fileencoding=utf8 :
# Copyright (c) 2017-2018 Michał Górny
# 2-clause BSD license

# This is a Python helper script for eselect-repo that wraps routines
# for repositories.xml & repos.conf file. It helps us avoid ugly sed
# and/or dependency on non-common packages.

import argparse
import configparser
import locale
import lxml.etree
import os
import os.path
import tempfile


def transform_source(source_el, repo_name):
    """Transform <source/> into (sync-type, sync-uri) pair."""
    stype = source_el.get('type')
    suri = source_el.text
    # pass-through
    if stype in ('bzr', 'git', 'rsync', 'svn'):
        return (stype, suri)
    # map to 'hg' syncer
    elif stype == 'mercurial':
        return ('hg', suri)
    else:
        print('warning: {}: unsupported source type {}'.format(
            repo_name, stype))
        return None


def do_list(args):
    repos = {}
    for r in args.repositories_xml.getroot().findall('repo'):
        name = r.findtext('name')
        uris = [transform_source(s, name) for s in r.findall('source')]
        if name in args.repos_conf:
            sect = args.repos_conf[name]
            sync_params = (sect.get('sync-type'), sect.get('sync-uri'))
            if sync_params in uris:
                status = 'enabled'
            else:
                status = 'need-update'
        else:
            status = 'disabled'
        repos[name] = {
            'status': status,
            'url': r.findtext('homepage'),
        }

    for name in args.repos_conf:
        if name != 'DEFAULT' and name not in repos:
            repos[name] = {
                'status': 'local',
                'url': '',
            }

    for name, data in sorted(repos.items(),
                               key=lambda kv: locale.strxfrm(kv[0])):
        print('{} {} {}'.format(name, data['status'],
            data['url'] or ''))


def do_metadata(args):
    all_repos = set(x.findtext('name')
            for x in args.repositories_xml.getroot().findall('repo'))

    for r in args.repo:
        if r not in args.repos_conf:
            print('{} not-exist'.format(r))
            continue

        if r not in all_repos:
            state = 'local'
        elif 'sync-uri' not in args.repos_conf[r]:
            state = 'no-sync-uri'
        else:
            state = 'remote'
        local_path = args.repos_conf[r].get('location', '')
        print('{} {} {}'.format(r, state, local_path))


def do_remote_metadata(args):
    all_repos = dict((x.findtext('name'), x)
            for x in args.repositories_xml.getroot().findall('repo'))

    for r in args.repo:
        if r in args.repos_conf:
            print('{} enabled {}'.format(r, args.repos_conf[r].get('location', '')))
            continue
        if r not in all_repos:
            print('{} not-exist'.format(r))
            continue

        sources = all_repos[r].findall('source')
        for s in sources:
            sync_data = transform_source(s, r)
            if sync_data is not None:
                break
        else:
            print('{} unsupported'.format(r))
            continue

        print('{} remote {} {}'.format(r, sync_data[0], sync_data[1]))


def make_configparser(path):
    cfgp = configparser.ConfigParser(interpolation=None)
    if os.path.isdir(path):
        paths = [os.path.join(path, x) for x in os.listdir(path)
                 if not x.startswith('.') and not x.endswith('~')]
    else:
        paths = [path]
    # monkey-patch our path list in
    cfgp._erh_paths = paths
    cfgp.read(paths)
    return cfgp


def main():
    locale.setlocale(locale.LC_ALL, '')
    p = argparse.ArgumentParser()

    paths = p.add_argument_group('paths')
    paths.add_argument('--repos-conf', required=True,
            type=make_configparser,
            help='Location of repos.conf file')
    paths.add_argument('--repositories-xml', required=True,
            type=lxml.etree.parse,
            help='Location of repositories.xml file')

    actions = p.add_subparsers(title='actions', dest='action')
    actions.add_parser('list',
            help='List of remote & local repositories')

    metadata_action = actions.add_parser('metadata',
            help='Print metadata for given repos')
    metadata_action.add_argument('repo', nargs='+',
            help='Repository to print metadata for')

    metadata_action = actions.add_parser('remote-metadata',
            help='Print metadata for given remote repos')
    metadata_action.add_argument('repo', nargs='+',
            help='Repository to print metadata for')

    args = p.parse_args()

    if args.action == 'list':
        do_list(args)
    elif args.action == 'metadata':
        do_metadata(args)
    elif args.action == 'remote-metadata':
        do_remote_metadata(args)
    else:
        raise NotImplementedError('Action {} not implemented'.format(args.action))


if __name__ == '__main__':
    main()
