#!/usr/bin/python3

"""
This script tries to set ordering in which packages ought to be sent to builders.
Input: file with names of packages. If not given packages are read from stdin. One package name per line.
Output: sorted packages on stdout.

If the script goes in a infinite loop, that means there is a cycle or other bug.
"""

import argparse
import os
import re
import sys

BR_PATTERN = re.compile(r'BuildRequires:\s+(.*?)(\s|$)')
PACKAGE_PATTERN_WITH_N = re.compile(r'%package\s+-n\s+(.*)')
PACKAGE_PATTERN = re.compile(r'%package\s+(.*)')

try:
    import rpm
    DIR = rpm.expandMacro('%_topdir')
except ModuleNotFoundError:
    try:
        import subprocess
        DIR = subprocess.check_output(['rpm', '-E', '%_topdir']).decode('utf-8').strip()
    except:
        DIR = os.getenv("HOME") + '/rpm/packages'

BUILD_REQUIRES = {}
PACKAGES = {}
SPECS = {}
VISITED = {}
LEAVES = False


def parse_spec(name):
    global PACKAGES, SPECS, BUILD_REQUIRES, VISITED
    res = []
    try:
        with open(os.path.join(DIR, name, name + '.spec'), 'r') as f:
            for line in f:
                br = BR_PATTERN.match(line)
                if br:
                    p = br.group(1)
                    res.append(p)
                if line.startswith('%package'):
                    pn = PACKAGE_PATTERN_WITH_N.match(line)
                    if pn:
                        package = pn.group(1)
                        PACKAGES[package] = name
                    else:
                        pn = PACKAGE_PATTERN.match(line)
                        if pn:
                            ext = pn.group(1)
                            if ext:
                                package = name + '-' + ext
                                PACKAGES[package] = name
        BUILD_REQUIRES[name] = res[:]
        PACKAGES[name] = name
        SPECS[name] = True
        VISITED[name] = False
    except:
        pass


def print_spec(spec):
    global PACKAGES, SPECS, BUILD_REQUIRES, VISITED

    if not VISITED[spec]:
        VISITED[spec] = True
        for br in BUILD_REQUIRES[spec]:
            name = PACKAGES.get(br, '')
            if name in SPECS:
                if LEAVES:
                    return
                elif not VISITED[name]:
                    print_spec(name)
        print(spec)


if __name__ == "__main__":
    argparser = argparse.ArgumentParser()
    argparser.add_argument('path', nargs='?', help='input file with list of packages, if not passed list is read from stdin')
    argparser.add_argument('-l', action='store_true', help='show only leaves in dependency graph')
    args = argparser.parse_args()
    LEAVES = args.l
    with (args.path and open(args.path, 'r') or sys.stdin) as f:
        for line in f:
            spec = os.path.basename(os.path.normpath(line.rstrip())).removesuffix('.spec')
            parse_spec(spec)

    for spec in SPECS:
        print_spec(spec)
