tdawson / centos / centpkg

Forked from centos/centpkg 3 years ago
Clone
Blob Blame History Raw
# pylint: disable=line-too-long,abstract-class-not-used

"""
    Top level function library for centpkg
"""

# Author(s):
#            Jesse Keating <jkeating@redhat.com>
#            Pat Riehecky <riehecky@fnal.gov>
#            Brian Stinson <bstinson@ksu.edu>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.


import re
import warnings

import git
from pyrpkg import Commands, rpkgError
from pyrpkg.utils import cached_property

# doc/centpkg_man_page.py uses the 'cli' import
from . import cli  # noqa
from .lookaside import StreamLookasideCache, SIGLookasideCache, CLLookasideCache


_DEFAULT_VERSION = "9"


class DistGitDirectory(object):

    signame = None
    centosversion = _DEFAULT_VERSION
    projectname = None
    releasename = None
    distrobranch = False
    sigbranch = False
    repo = None
    git_origin_substr = "git@gitlab.com/redhat/centos-stream"

    def __init__(self, branchtext, repo_path=None):
        if repo_path:
            # self.repo = git.cmd.Git(repo_path)
            self.repo = git.repo.Repo(repo_path)
        rhelbranchre = r"rhel-(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<appstream>\d+))?"
        sigtobranchre = r"c(?P<centosversion>\d+[s]?)-sig-(?P<signame>\w+)-?(?P<projectname>\w+)?-?(?P<releasename>\w+)?"
        distrobranchre = r"c(?P<centosversion>\d+)-?(?P<projectname>\w+)?"
        javabranchre = r"openjdk-portable-centos-(?P<centosversion>\d+)"
        oldbranchre = r"(?P<signame>\w+)(?P<centosversion>\d)"
        rhelmatch = re.search(rhelbranchre, branchtext)
        sigmatch = re.match(sigtobranchre, branchtext)
        distromatch = re.match(distrobranchre, branchtext)
        javamatch = re.match(javabranchre, branchtext)
        oldbranchmatch = re.match(oldbranchre, branchtext)
        if rhelmatch:
            gd = rhelmatch.groupdict()
            self.distrobranch = True
            self.signame = "centos"
            self.centosversion = gd["major"]
        elif sigmatch:
            gd = sigmatch.groupdict()
            self.sigbranch = True
            self.signame = gd["signame"]
            self.centosversion = gd["centosversion"]

            # Users have the option to specify (or not specify) common in their
            # git repos. Ww need to handle these cases because common is not a
            # project nor is it a release.
            if gd["projectname"] != "common":
                self.projectname = gd["projectname"]
            if gd["releasename"] != "common":
                self.releasename = gd["releasename"]
        elif distromatch:
            gd = distromatch.groupdict()
            self.distrobranch = True
            self.signame = "centos"
            self.centosversion = gd["centosversion"]

            if gd["projectname"] != "common":
                self.projectname = gd["projectname"]
        elif javamatch:
            gd = javamatch.groupdict()
            self.distrobranch = True
            self.signame = "centos"
            self.centosversion = gd["centosversion"]
        elif oldbranchmatch:
            warnings.warn(
                "This branch is deprecated and will be removed soon", DeprecationWarning
            )
        else:
            if not self.is_fork():
                warnings.warn(
                    "Unable to determine if this is a fork or not. Proceeding, but you should double check."
                )
            else:
                self.distrobranch = True
                self.signame = "centos"
                self.projectname = self.get_origin().split("_")[-1].replace(".git", "")

                warnings.warn(
                    'Remote "origin" was detected as a fork, ignoring branch name checking'
                )

    def get_origin(self):
        if self.repo is None:
            return ""
        if "origin" not in self.repo.remotes:
            return ""
        urls = [u for u in self.repo.remotes["origin"].urls]
        if len(urls) == 0:
            return ""
        return urls[0]

    def is_fork(self):
        """
        Check if origin remote repository is using a fork url.

        Returns
        bool
            A boolean flag indicating if origin remote url is using
            a forked repository url.
        """
        # git+ssh://git@gitlab.com/redhat/centos-stream/rpms/binutils.git
        if self.repo is None:
            return False
        return self.git_origin_substr not in self.get_origin()

    @property
    def target(self):
        projectorcommon = self.projectname
        releaseorcommon = self.releasename

        if self.distrobranch:
            if self.centosversion not in ("6", "7"):
                return "c{}s-candidate".format(self.centosversion)
            else:
                return "-".join(
                    filter(None, ["c" + self.centosversion, projectorcommon])
                )

        if not releaseorcommon:
            if not projectorcommon or projectorcommon == "common":
                projectorcommon = "common"
            else:
                releaseorcommon = "common"

        return "-".join(
            filter(
                None,
                [self.signame + self.centosversion, projectorcommon, releaseorcommon],
            )
        ) + "-el{0}".format(self.centosversion)


class Commands(Commands):
    """
    For the pyrpkg commands with centpkg behavior
    """

    def __init__(self, *args, **kwargs):
        """
        Init the object and some configuration details.
        """
        super(Commands, self).__init__(*args, **kwargs)
        # For MD5 we want to use the old format of source files, the BSD format
        # should only be used when configured for SHA512
        self.source_entry_type = "bsd" if self.lookasidehash != "md5" else "old"
        self.branchre = "c\d{1,}(s)?(tream)?|master"

    @property
    def distgitdir(self):
        return DistGitDirectory(self.branch_merge, repo_path=self.path)

    @cached_property
    def lookasidecache(self):
        if self.layout.sources_file_template == "sources":
            return StreamLookasideCache(
                self.lookasidehash,
                self.lookaside,
                self.lookaside_cgi,
            )
        else:
            if self.distgitdir.sigbranch:
                return SIGLookasideCache(
                    self.lookasidehash,
                    self.lookaside,
                    self.lookaside_cgi,
                    self.repo_name,
                    self.branch_merge,
                )
            else:
                return CLLookasideCache(
                    self.lookasidehash,
                    self.lookaside,
                    self.lookaside_cgi,
                    self.repo_name,
                    self.branch_merge,
                )

    # redefined loaders
    def load_rpmdefines(self):
        """
        Populate rpmdefines based on branch data
        """

        if not self.distgitdir.centosversion:
            raise rpkgError(
                "Could not get the OS version from the branch:{0}".format(
                    self.branch_merge
                )
            )

        self._distvar = self.distgitdir.centosversion
        self._distval = self._distvar.replace(".", "_")

        self._distunset = 'fedora'
        self._disttag = "el%s" % self._distval
        self._rpmdefines = [
            "--define",
            "_sourcedir %s" % self.layout.sourcedir,
            "--define",
            "_specdir %s" % self.layout.specdir,
            "--define",
            "_builddir %s" % self.layout.builddir,
            "--define",
            "_srcrpmdir %s" % self.layout.srcrpmdir,
            "--define",
            "_rpmdir %s" % self.layout.rpmdir,
            "--define",
            "dist .%s" % self._disttag,
            # int and float this to remove the decimal
            "--define",
            "%s 1" % self._disttag,
            # This is so the rhel macro is set for spec files
            "--define",
            "rhel %s" % self._distval.split("_")[0],
            # This is so the centos macro is set for spec files
            "--define",
            "centos %s" % self._distval.split("_")[0],
            # This is so the fedora macro is unset for spec files
            "--eval",
            "%%undefine %s" % self._distunset,
        ]
        self.log.debug("RPMDefines: %s" % self._rpmdefines)

    def construct_build_url(self, *args, **kwargs):
        """Override build URL for CentOS/Fedora Koji build

        In CentOS/Fedora Koji, anonymous URL should have prefix "git+https://"
        """
        url = super(Commands, self).construct_build_url(*args, **kwargs)
        return "git+{0}".format(url)

    def load_target(self):
        """This sets the target attribute (used for mock and koji)"""

        self._target = self.distgitdir.target