#!/usr/bin/env python3
# new afribuild for rhel8 +

import urllib.request
import os
import sys
import os.path
import csv
import argparse
import tarfile
import subprocess

class Afribuild:
    base = "https://sourcep.dedicated.co.za/source/"
    packages = {}

    def __init__(self):
        try:
            fh = urllib.request.urlopen(self.base + 'version.list')
            reader = csv.reader(line.decode('utf-8') for line in fh)
        except Exception:
            fh = os.popen("curl -k '%s'" % (self.base + 'version.list'), 'r')
            reader = csv.reader(fh)

        for row in reader:
            if not row:
                continue
            if row[0].startswith('#'):
                continue
            if len(row) < 4:
                continue
            self.packages[row[0]] = row[1:]
        fh.close()

    def list(self):
        """List all packages their version and the software url"""
        for p in self.packages.keys():
            data = self.packages[p]
            print(f"{p:<20} {data[0]:<10} {data[1]}")

    def versionExpand(self, version):
        """
        Generates a version number as a large int to make comparing easy
        Eg: 1.2.3 -> 100020003
        """
        total = 0
        try:
            parts = version.split('.')
        except AttributeError:
            return int(version)

        mult = 10000 ** (len(parts) - 1)
        for p in parts:
            total += int(p) * mult
            mult //= 10000
        return total

    def versionGet(self, software):
        """Return the latest available version of the software"""
        return self.packages[software][0]

    def urlExpand(self, url):
        """Makes sure the url is not relative"""
        if "://" not in url:
            url = self.base + url
        return url

    def buildshellDownload(self, software):
        """Downloads build shell and makes it executable"""
        shellurl = self.packages[software][2]
        shellurl = self.urlExpand(shellurl)
        sname = os.path.basename(shellurl)

        try:
            fh = urllib.request.urlopen(shellurl)
            data = fh.read()
        except Exception:
            subprocess.call(["curl", "-k", "-o", sname, shellurl])
            return sname

        with open(sname, "wb") as f:
            f.write(data)

        os.chmod(sname, 0o755)
        return sname

    def upgrade(self, software):
        """Upgrade software"""
        print(f"Installing/upgrading '{software}'")

        builddir = os.path.join(os.environ['HOME'], "build")
        os.makedirs(builddir, exist_ok=True)
        os.chdir(builddir)

        url = self.urlExpand(self.packages[software][1])
        tfname = os.path.basename(url)

        print("Downloading from " + url + " to " + tfname)

        try:
            with urllib.request.urlopen(url) as fh, open(tfname, "wb") as f:
                f.write(fh.read())
        except Exception:
            subprocess.call(["curl", "-k", "-o", tfname, url])

        # Determine compression type
        if "gz" in tfname:
            rflag = "r:gz"
            cmd = ["tar", "-xzvf", tfname]
        elif "bz2" in tfname:
            rflag = "r:bz2"
            cmd = ["tar", "-xjvf", tfname]
        else:
            rflag = "r"
            cmd = ["tar", "-xf", tfname]

        # Find directory inside tar
        tfh = tarfile.open(tfname, rflag)
        directory = tfh.getmembers()[0].name.split('/')[0]
        tfh.close()

        if os.path.exists(directory):
            subprocess.call(["rm", "-rf", directory])

        subprocess.call(cmd)
        os.chdir(directory)

        buildtool = self.buildshellDownload(software)
        subprocess.call(["./" + buildtool])


def main():
    parser = argparse.ArgumentParser(
        description="Afribuild package manager"
    )

    parser.add_argument("--list", "-l", action="store_true",
                        help="List all available software and their versions")

    parser.add_argument("--version", "-v", type=str,
                        help="Current installed version")

    parser.add_argument("--upgrade", "-u", dest="package", type=str,
                        help="Upgrade to latest version")

    options = parser.parse_args()

    ab = Afribuild()

    if options.version and options.package:
        if ab.versionExpand(options.version) < ab.versionExpand(ab.versionGet(options.package)):
            ab.upgrade(options.package)

    if options.list:
        ab.list()


if __name__ == '__main__':
    main()

