#!/usr/bin/env python
# Copyright (c) 2020 by Cisco Systems, Inc.
 
import os
import sys
import fcntl
import argparse
import subprocess
import re

'''
Current arbitrary tags in code.
Parentversion, PIPD and skiprelease is not populated
as part of XR packaging, but used in install code.
default all to none for rpm4 output.
'''
custom_mdata = {
                "SUPPCARDS" : '(none)', 
                "VMTYPE": '(none)',
                "CISCOHW" : '(none)', 
                "PACKAGETYPE" : '(none)',
                "PKGTYPE" : '(none)', 
                "PACKAGEPRESENCE" : '(none)', 
                "RESTARTTYPE" : '(none)',
                "INSTALLMETHOD" : '(none)', 
                "XRVERSION" : '(none)', 
                "XRRELEASE" : '(none)',
                "PARENTVERSION" : '(none)', 
                "PIPD" : '(none)', 
                "SKIPRELEASE" : '(none)', 
                "CARDTYPE" : '(none)'
               }
def run_cmd (cmd):
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE, shell=True)
    out, error = process.communicate()
    sprc = process.returncode
    if sprc is None or sprc != 0:
        out = error
        raise RuntimeError("Error CMD=%s returned --->%s" % (cmd, out))
    else:
        ''' rpm returns exit code 0 even when error is populated '''
        if not out:
            out = error
            raise RuntimeError("Error CMD=%s returned --->%s" % (cmd, out))
    return out.strip()

''' 
Query GROUP tag for custom metadata in package.
If result has tag like suppcards, GROUP tag holds custom metadata.
else, continue with original query tag.
In case, we have mix of packages in query, raise an exception.
'''
def query_custom_tag (opts):
    query_grp_tag = False
    groupdata = {}
    for pkg in opts:
        if not os.path.isfile (pkg):
            continue
        try:
            stroutput = None
            rpmcmd = "rpm -qp --qf {} {}".format (
                     "\'[%{GROUP}\\n]\'", pkg
                     )
            stroutput = run_cmd (rpmcmd)
            if 'SUPPCARDS' in stroutput.upper():
                query_grp_tag = True
                groupdata[pkg] = stroutput
            else:
                if query_grp_tag:
                    raise Exception ("Mixed packages in input.")
                    query_grp_tag = False
        except:
            raise
    return query_grp_tag, groupdata

'''
Parse input for query string, we are only interested in queries
for custom tags.
'''
def parseCli ():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-q", 
        dest="query",
        action='store_true',
        required=False)

    parser.add_argument(
        "--qf",
        "--queryformat",
        dest="querystring",
        required=False)
 
    parser.add_argument(
        "-p", 
        dest="querypkg", 
        action='store_true',
        required=False)

    parser.add_argument(
        "--new", 
        dest="newfmt",
        action='store_true',
        required=False)

    parser.print_usage = None

    namespace, opts = parser.parse_known_args ()
    return namespace, opts
 
if __name__ == "__main__":
    querystr = None
    opts = None
    namespace = None

    try:
        namespace, opts = parseCli ()
    except:
        pass
    if namespace and namespace.querystring:
        querystr = namespace.querystring.lower()
    inargs = ' '.join(sys.argv[1:])
 
    '''
        Check if it is a query on a package for custom metadata.
        If so, check that the rpm being queried do hold custom tag.
        If not, get data from GROUP tag in rpm.
    '''
    query_grp_tag = False
    if namespace and namespace.query and namespace.querypkg and namespace.querystring:
        resultdict = {}
        groupdata = {}
        rpmstroutput = ''
        if any (item in querystr.upper() for item in custom_mdata.keys()):
            if namespace.newfmt:
                query_grp_tag = True
            else:
                query_grp_tag, groupdata = query_custom_tag (opts)

            ''' rpm has needed custom tags, handover to rpm'''
            if not query_grp_tag:
                try:
                    sys.argv[0] = "rpm"
                    os.execvp("rpm", sys.argv)
                except:
                    pass        
            else:
                for pkg in opts:
                    pkgargs = inargs
                    if not os.path.isfile (pkg):
                        continue
                    for x in opts:
                        if pkg == x:
                            continue
                        elif not os.path.isfile (x):
                            continue
                        pkgargs = pkgargs.replace (x, '')
                    resultdict[pkg] = ''
                    stroutput = groupdata[pkg]
                    data = stroutput.split(',')[-1]
                    cfg = dict([(item.partition(':')[0].upper(),
                                item.partition(':')[2]) 
                                for item in data.split(';') if not 
                                item.strip().startswith('#') and item.strip()])
                    '''custom tag SUPPCARDS used to hold data with ',' as delimiter'''
                    if cfg.has_key('SUPPCARDS'):
                        cfg['SUPPCARDS'] = ','.join(cfg['SUPPCARDS'].split('-'))
                    pkgdict = dict (custom_mdata)
                    pkgdict.update (cfg)
                    ''' Edit querystr to query for standard tags'''
                    newquerystr = namespace.querystring
                    for item in custom_mdata.keys():
                        newquerystr = re.sub ("%{{{}}}".format(item), pkgdict[item], newquerystr, flags=re.I)
                    newquerystr = newquerystr.strip('[]')

                    ''' Run the rpm query '''
                    try:
                        pkgargs = pkgargs.replace (namespace.querystring, "\'%s\'"%(newquerystr))
                        rpmcmd = "rpm {}".format(pkgargs)
                        stroutput = run_cmd(rpmcmd)
                        resultdict[pkg] = stroutput
                    except:
                        raise
                rpmstroutput = '\n'.join(resultdict.values())
        else:
            try:
                ''' 
                Query on package but not for custom tag. Hand over control 
                to rpm 
                '''
                sys.argv[0] = "rpm"
                os.execvp("rpm", sys.argv)
            except:
                pass

        print (rpmstroutput)
    else:
        ''' It is not a query on package, hand over control to rpm '''
        try:
            sys.argv[0] = "rpm"
            os.execvp("rpm", sys.argv)
        except:
            pass
    sys.exit (0)
