git » autoupdaters.git » main » tree

[main] / autoupdater_helpers / __init__.py

#!/usr/bin/env python3

def pkgbuild_ver():
    for line in open("PKGBUILD", "r"):
        if line.startswith("pkgver="):
            return line[7:].strip()

def pkgbuild_new_ver(ver, sha256sum=None, rel="1", sumtype="sha256", sum=None):
    import os
    sumpfx = sumtype + "sums=("
    if sha256sum:
        sum = sha256sum

    # Skip one line with a checksum
    skipsumln = False
    # Skip the whole rest of the checksum section
    skipsumlines = False
    with open("PKGBUILD.new", "w") as outf:
        for line in open("PKGBUILD"):
            if skipsumln:
                if ')' in line:
                    skipsumln = False
                elif "'" not in line:
                    continue
                else:
                    skipsumln = False
                    continue
            if skipsumlines:
                if ')' in line:
                    skipsumlines = False
                continue
            if line.startswith("pkgver="):
                outf.write("pkgver=" + ver + "\n")
            elif line.startswith("pkgrel="):
                outf.write(f"pkgrel={rel}\n")
            elif line.startswith(sumpfx):
                if sum:
                    outf.write(sumpfx + "'" + sum + "'\n")
                    if "'" not in line:
                        skipsumln = True
                else:
                    if ")" not in line:
                        skipsumlines = True
            else:
                outf.write(line)

    os.rename("PKGBUILD", "PKGBUILD.old")
    os.rename("PKGBUILD.new", "PKGBUILD")
    return

def ssl_ctx():
    import ssl
    cabundle = "/etc/pki/tls/certs/ca-bundle.crt"
    ctx = ssl.create_default_context(cafile=cabundle)
    return ctx

def _log(desc):
    with open("/sources/autoupdaters/results.log", "a") as f:
        f.seek(0,2)
        f.write(desc + "\n")


def mpkg(pkg, ver=None, carch=None):
    statepath = "/tmp/armlfs-evt"
    activepath = statepath + "/active"
    donepath = statepath + "/done"
    failpath = statepath + "/failed"
    from os import makedirs, chdir, getcwd, rename, environ
    from os.path import join
    from subprocess import run, CalledProcessError
    desc = f"{pkg} {ver}" if ver else pkg
    fn = desc.replace(" ","-")
    makedirs(activepath, exist_ok=True)
    fpath = join(activepath,fn)
    with open(fpath,"w") as f:
        f.write(desc + "\n")
    prev_path = getcwd()
    chdir("/sources/base-pkgbuilds")
    myenv = None
    if carch:
        myenv = dict(environ, CARCH=carch)
    try:
        run(["./mpkg.sh", pkg], env=myenv, check=True)
        chdir(prev_path)
        makedirs(donepath, exist_ok=True)
        rename(fpath, join(donepath,fn))
        _log(desc + " DONE")
    except CalledProcessError:
        chdir(prev_path)
        makedirs(failpath, exist_ok=True)
        rename(fpath, join(failpath,fn))
        _log(desc + " FAIL")
        raise

def parse_pkgbuild_ver_sum(fn):
    meta = {}
    sumnextln = False
    for line in open(fn):
        if sumnextln:
            if "'" in line:
                _,meta['sum'],_ = line.strip().split("'")
                sumnextln = False
            if ")" in line:
                sumnextln = False
            continue
        if line.startswith("pkgver=") and 'ver' not in meta:
            meta['ver'] = line[7:].strip()
        elif "sums=(" in line and 'sum' not in meta:
            type, sum = line.strip().split("sums=(",maxsplit=1)
            if type not in ("b2", "sha512", "sha384", "sha256", "sha224", "sha1", "md5", "ck"):
                continue
            if "'" not in sum:
                sumnextln = True
            else:
                _,meta['sum'],_ = sum.strip().split("'")
            meta['sumtype'] = type
        if 'ver' in meta and 'sum' in meta:
            break
    return meta

def get_arch_pkgbuild_ver_sum(pkg):
    from tempfile import TemporaryDirectory
    from subprocess import run
    url = f"https://gitlab.archlinux.org/archlinux/packaging/packages/{pkg}.git"
    with TemporaryDirectory(prefix=f"tmp-{pkg}-") as dir:
        cmd = ["git", "clone", "--depth=1", url, dir ]
        run(cmd, check=True)
        return parse_pkgbuild_ver_sum(dir + '/PKGBUILD')

def _months_ago(n):
    from datetime import date, timedelta
    # This allows float "months" <3
    d = date.today() - timedelta(days=int(n*30))
    return d.isoformat()


def arch_arm_pkgbuild_update(pkg,aarepo="extra"):
    """Update our PKGBUILD (and accompanying files) based on Arch-ARM PKGBUILDs repo"""
    from tempfile import TemporaryDirectory
    from subprocess import run, PIPE, STDOUT
    from os import path, getcwd, chdir, mkdir
    url = "https://github.com/archlinuxarm/PKGBUILDs"
    ourdir = f"/sources/base-pkgbuilds/{pkg}"
    upcommits = ourdir + "/autoupdate-commits"
    upcommit_fn = ourdir + "/.upstream_commit"
    if path.exists(upcommits):
        return "Previous update unfinished"
    cwd = getcwd()
    with TemporaryDirectory(prefix=f"tmp-{pkg}-") as dir:
        cmd = ["git", "clone", f"--shallow-since={_months_ago(3)}", url, dir ]
        run(cmd, check=True)
        chdir(dir)
        path = f"{aarepo}/{pkg}"
        with open(upcommit_fn) as f:
            upstream_commit = f.read().strip()

        cmd2 = [ "git", "rev-list", f"^{upstream_commit}", "HEAD", "--", path ]
        revlistp = run(cmd2, text=True, stdout=PIPE, stderr=STDOUT, check=True)
        rl = []
        for rev in revlistp.stdout.splitlines():
            r = rev.strip()
            if len(r):
                rl.append(r)
        if len(rl) < 1:
            chdir(cwd)
            return "No update necessary"
        mkdir(upcommits)
        commits = []
        # We're recording what we're about to try and apply, to help with manual recovery
        # when a patch inevitably fails :P
        with open(upcommits + "/order", 'w') as orderf:
            for index, rev in enumerate(reversed(rl),start=1):
                # Changes to .SRCINFO are 1) pointless and 2) ofter fail -> filter them out
                exclude_srcinfo = f":(exclude){path}/.SRCINFO"
                cmd3 = [ "git", "format-patch", "--start-number", str(index), "-o", upcommits, "-1", rev, '--', path, exclude_srcinfo ]
                patchp = run(cmd3, text=True, stdout=PIPE, stderr=STDOUT, check=True)
                patchfn = patchp.stdout.strip()
                t = f"{rev} {patchfn}\n"
                orderf.write(t)
                commits.append((rev,patchfn))
        chdir(ourdir)
    # Recording of the changes is complete, get rid of the repo (thus exit the with block ^^)
    for rev, patchfn in commits:
        cmd = [ "patch", "-Np3" ]
        with open(patchfn) as patchf:
            print(f"Applying {patchfn}...")
            pp = run(cmd, stdin=patchf)
        if pp.returncode:
            msg = f"Applying patch {patchfn} failed"
            _log(pkg + ": " + msg)
            return msg
        with open(upcommit_fn, 'w') as f:
            f.write(rev)
    print("Patches applied succesfully")
    # Patches applied succesfully, get rid of the patch dir
    run(["rm", "-r", upcommits])
    # None as in No problems, go ahead and build the new version
    chdir(cwd)
    return None