Пример #1
0
    def commit(self) -> str:
        """
        This method provides an easy way of getting the commit hash of the requested commit. It
        also stores the latest commit hash between method invocations, if the source goes away and
        the hash is needed again.

        Returns:
            str:        commit hash
        """

        logger = KtrLogger(LOG_PREFIX)

        # if sources are not accessible (anymore), return None or last saved rev
        if not os.access(self.dest, os.R_OK):
            if self.saved_commit is None:
                logger.dbg("Sources need to be get before commit hash can be read.")
                return None
            else:
                return self.saved_commit

        cmd = ["git", "rev-parse", "HEAD"]

        prev_dir = os.getcwd()
        os.chdir(self.dest)

        logger.log_command(cmd, 1)
        rev = subprocess.check_output(cmd).decode().rstrip("\n")

        os.chdir(prev_dir)

        self.saved_commit = rev
        return rev
Пример #2
0
    def verify(self) -> bool:
        """
        This method runs several checks to ensure local copying can proceed. It is automatically
        executed at package initialisation. This includes:

        * checks if all expected keys are present in the configuration file

        Returns:
            bool:   verification success
        """

        logger = KtrLogger(LOG_PREFIX)

        success = True

        # check if the configuration file is valid
        expected_keys = ["keep", "orig"]

        for key in expected_keys:
            if key not in self.spkg.conf["local"]:
                logger.err("The [local] section in the package's .conf file doesn't set the '" +
                           key +
                           "' key.")
                success = False

        return success
Пример #3
0
def do_release_bump(path: str, comment: str=None):
    """
    This function calls `rpmdev-bumpspec` with the specified arguments to bump the release number
    and create a changelog entry with a given comment.

    Arguments:
        str comment:    comment to be added to the changelog entry
    """

    ktr = Kentauros()
    logger = KtrLogger(LOG_PREFIX)

    if not os.path.exists(path):
        raise FileNotFoundError()

    if comment is None:
        comment = "Automatic build by kentauros."

    # construct rpmdev-bumpspec command
    cmd = ["rpmdev-bumpspec"]

    # add --verbose or --quiet depending on settings
    if (ktr.verby == 0) or ktr.debug:
        cmd.append("--verbose")

    cmd.append(path)
    cmd.append('--comment="' + comment + '"')

    logger.log_command(cmd)
    subprocess.call(cmd)
Пример #4
0
    def verify(self) -> bool:
        """
        This method runs several checks to ensure copr uploads can proceed. It is automatically
        executed at package initialisation. This includes:

        * checks if all expected keys are present in the configuration file
        * checks if the `copr-cli` binary is installed and can be found on the system

        Returns:
            bool:   verification success
        """

        logger = KtrLogger(LOG_PREFIX)

        success = True

        # check if the configuration file is valid
        expected_keys = ["active", "dists", "keep", "repo", "wait"]

        for key in expected_keys:
            if key not in self.upkg.conf["copr"]:
                logger.err("The [copr] section in the package's .conf file doesn't set the '" +
                           key +
                           "' key.")
                success = False

        # check if copr is installed
        try:
            subprocess.check_output(["which", "copr-cli"])
        except subprocess.CalledProcessError:
            logger.log("Install copr-cli to use the specified builder.")
            success = False

        return success
Пример #5
0
    def build(self):
        """
        This method executes the actual SRPM package assembly. It sets `$HOME` to the created
        temporary directory and executes `rpmbuild -bs` with the copy of the package spec file in
        `rpmbuild/SPECS`. After that, `$HOME` is reset to the old value.
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        old_home = os.environ['HOME']
        os.environ['HOME'] = self.tempdir

        # construct rpmbuild command
        cmd = ["rpmbuild"]

        # add --verbose or --quiet depending on settings
        if (ktr.verby == 2) and not ktr.debug:
            cmd.append("--quiet")
        if (ktr.verby == 0) or ktr.debug:
            cmd.append("--verbose")

        cmd.append("-bs")
        cmd.append(os.path.join(self.specdir, self.cpkg.get_name() + ".spec"))

        logger.log_command(cmd)

        try:
            subprocess.call(cmd)
        finally:
            os.environ['HOME'] = old_home
Пример #6
0
    def get(self) -> bool:
        """
        This method attempts to copy the specified source from the location specified in the package
        configuration file to the determined destination. If the destination file already exists,
        nothing will be done.

        Returns:
            bool:   *True* if source was copied successfully, *False* if not
        """

        logger = KtrLogger(LOG_PREFIX)

        # check if $KTR_BASE_DIR/sources/$PACKAGE exists and create if not
        if not os.access(self.sdir, os.W_OK):
            os.makedirs(self.sdir)

        # if source seems to already exist, return False
        if os.access(self.dest, os.R_OK):
            logger.log("Sources already present.", 1)
            return False

        # copy file from origin to destination
        shutil.copy2(self.get_orig(), self.dest)

        return True
Пример #7
0
    def rev(self) -> str:
        """
        This method determines which revision the bzr repository associated with this
        :py:class:`BzrSource` currently is at and returns it as a string. Once run, it saves the
        last processed revision number in `self.saved_rev`, in case the revision needs to be
        determined when bzr repository might not be accessible anymore (e.g. if `bzr.keep=False` is
        set in configuration, so the repository is not kept after export to tarball).

        Returns:
            str: either revision string from repo, last stored rev string or `""` when unsuccessful
        """

        # ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        # if sources are not accessible (anymore), return "" or last saved rev
        if not os.access(self.dest, os.R_OK):
            if self.saved_rev is None:
                logger.dbg("Sources need to be get before rev can be determined.")
                return ""
            else:
                return self.saved_rev

        cmd = ["bzr", "revno"]

        prev_dir = os.getcwd()
        os.chdir(self.dest)

        logger.log_command(cmd, 0)
        rev = subprocess.check_output(cmd).decode().rstrip("\n")

        os.chdir(prev_dir)

        self.saved_rev = rev
        return rev
Пример #8
0
    def verify(self) -> bool:
        """
        This method runs several checks to ensure bzr commands can proceed. It is automatically
        executed at package initialisation. This includes:

        * checks if all expected keys are present in the configuration file
        * checks if the `bzr` binary is installed and can be found on the system

        Returns:
            bool:   verification success
        """

        logger = KtrLogger(LOG_PREFIX)

        success = True

        # check if the configuration file is valid
        expected_keys = ["branch", "keep", "keep_repo", "orig", "revno"]

        for key in expected_keys:
            if key not in self.spkg.conf["bzr"]:
                logger.err("The [bzr] section in the package's .conf file doesn't set the '" +
                           key +
                           "' key.")
                success = False

        # check if bzr is installed
        try:
            subprocess.check_output(["which", "bzr"]).decode().rstrip("\n")
        except subprocess.CalledProcessError:
            logger.log("Install bzr to use the specified source.")
            success = False

        return success
Пример #9
0
    def _get_last_release(self, spec: RPMSpec):
        """
        This method tries to read the latest state from the state database - if that is not
        available, the .spec file is parsed as a fallback.

        Arguments:
            RPMSpec spec:   rpm spec object

        Returns:
            str:            last known release
        """

        assert isinstance(spec, RPMSpec)

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        saved_state = ktr.state_read(self.cpkg.get_conf_name())

        if saved_state is None:
            logger.dbg("Package " +
                       self.cpkg.get_conf_name() +
                       " not yet in state database.")
            logger.dbg("Falling back to legacy release detection.")
            old_release = spec.get_release()
        elif "rpm_last_release" not in saved_state:
            logger.dbg("Package " +
                       self.cpkg.get_conf_name() +
                       " has no release set in state database.")
            logger.dbg("Falling back to legacy release detection.")
            old_release = spec.get_release()
        else:
            old_release = saved_state["rpm_last_release"]

        return old_release
Пример #10
0
    def execute(self) -> bool:
        logger = KtrLogger(LOG_PREFIX)

        success = self.build()

        if not success:
            logger.log("Binary package building unsuccessful, aborting action.")
            return False

        success = self.export()

        if not success:
            logger.log("Binary package exporting unsuccessful, aborting action.")
            return False

        return success
Пример #11
0
    def export(self):
        """
        This method copies the assembled source packages from `rpmbuild/SRPMS` to the directory for
        built packages as specified in the kentauros configuration. If multiple SRPM packages are
        found, they all are copied.
        """

        logger = KtrLogger(LOG_PREFIX)

        srpms = glob.glob(os.path.join(self.srpmdir, "*.src.rpm"))

        os.makedirs(self.pdir, exist_ok=True)

        for srpm in srpms:
            shutil.copy2(srpm, self.pdir)
            logger.log("File copied: " + srpm, 0)
Пример #12
0
    def export(self) -> bool:
        """
        This method copies the build results (if any) from the mock result directory to the
        directory specified for binary package exports.

        Returns:
            bool:   *True* if successful, *False* if not
        """

        if not self.get_active():
            return True

        if not self.get_export():
            return True

        logger = KtrLogger(LOG_PREFIX)

        os.makedirs(self.edir, exist_ok=True)

        if not os.path.exists(self.edir):
            logger.err("Package exports directory could not be created.")
            return False

        if not os.access(self.edir, os.W_OK):
            logger.err("Package exports directory can not be written to.")
            return False

        mock_result_dirs = list()

        for dist in self.get_dists():
            path = get_dist_result_path(dist)
            if os.path.exists(path):
                mock_result_dirs.append(path)
            else:
                corrected_path = get_dist_result_path(get_dist_from_mock_config(dist))
                mock_result_dirs.append(corrected_path)

        file_results = list()

        for result_dir in mock_result_dirs:
            file_results += glob.glob(os.path.join(result_dir, "*.rpm"))

        for file in file_results:
            shutil.copy2(file, self.edir)

        return True
Пример #13
0
    def clean(self) -> bool:
        if not os.path.exists(self.pdir):
            return True

        logger = KtrLogger(LOG_PREFIX)

        try:
            assert Kentauros().conf.get_packdir() in self.pdir
            assert os.path.isabs(self.pdir)
            shutil.rmtree(self.pdir)
            return True
        except AssertionError:
            logger.err("The Package exports directory looks weird. Doing nothing.")
            return False
        except OSError:
            logger.err("The Package exports directory couldn't be removed.")
            return False
Пример #14
0
    def execute(self) -> bool:
        """
        This method executes the :py:meth:`Source.prepare()` method to execute source preparation.
        This includes downloading or copying to destination, updating if necessary, and exporting to
        tarball if necessary.

        Returns:
            bool:           *True* when successful, *False* if sub-action fails
        """

        logger = KtrLogger(LOGPREFIX)

        source = self.kpkg.get_module("source")

        if source is None:
            logger.log("This package doesn't define a source module. Aborting.")
            return True

        success = source.execute()

        self.update_status()

        if success:
            logger.log(self.kpkg.get_conf_name() + ": Success!")
        else:
            logger.log(self.kpkg.get_conf_name() + ": Not successful.")

        return success
Пример #15
0
def ktr_mkdirp(path: str) -> bool:
    """
    This function checks for directory existence and the ability to write to it. If the directory
    does not exist, it will be created.

    Arguments:
        str path:   path of directory to check and create

    Returns:
        bool:       success (or not)
    """

    logger = KtrLogger(LOG_PREFIX)

    if os.path.exists(path):
        if os.access(path, os.W_OK):
            return True
        else:
            logger.err(path + " can't be written to.")
            return False
    else:
        logger.log(path + " directory doesn't exist and will be created.")
        try:
            os.makedirs(path)
        except OSError:
            logger.err(path + " directory could not be created.")
            return False
        return True
Пример #16
0
    def init(self):
        """
        This method creates a temporary directory (which is then set to `$HOME` in the
        :py:meth:`SrpmConstructor.build()` method) and other necessary sub-directories (here:
        `SOURCES`, `SRPMS`, `SPECS`).
        """

        logger = KtrLogger(LOG_PREFIX)

        # make sure to finally call self.clean()!
        self.tempdir = tempfile.mkdtemp()

        logger.log("Temporary directory " + self.tempdir + " created.", 1)

        self.rpmbdir = os.path.join(self.tempdir, "rpmbuild")
        self.specdir = os.path.join(self.tempdir, "rpmbuild", "SPECS")
        self.srpmdir = os.path.join(self.tempdir, "rpmbuild", "SRPMS")
        self.srcsdir = os.path.join(self.tempdir, "rpmbuild", "SOURCES")

        # create $TEMPDIR/rpmbuild
        if not os.path.exists(self.rpmbdir):
            os.mkdir(self.rpmbdir)

        logger.log("Temporary rpmbuild directory created: " + self.tempdir, 1)

        # create $TEMPDIR/rpmbuild/{SPECS,SRPMS,SOURCES}
        for directory in [self.specdir, self.srpmdir, self.srcsdir]:
            if not os.path.exists(directory):
                os.mkdir(directory)

        logger.log("Temporary 'SOURCES', 'SPECS', 'SRPMS' directories created.", 1)
Пример #17
0
    def execute(self) -> bool:
        """
        This method executes the :py:meth:`Uploader.upload()` method to execute the source upload,
        if possible - this only has effect for packages with a valid uploader specified in the
        package configuration file.

        Returns:
            bool:           always *True*, future error checking still missing
        """

        logger = KtrLogger(LOGPREFIX)

        uploader = self.kpkg.get_module("uploader")

        if uploader is None:
            logger.log("This package doesn't define an uploader module. Aborting.")
            return True

        success = uploader.execute()

        self.update_status()

        if success:
            logger.log(self.kpkg.get_conf_name() + ": Success!")
        else:
            logger.log(self.kpkg.get_conf_name() + ": Not successful.")

        return success
Пример #18
0
    def execute(self) -> bool:
        """
        This method cleans up the sources of to the package specified at initialisation. It executes
        the :py:meth:`Source.clean()` method of the :py:class:`Source` instance in the specified
        package.

        Returns:
            bool:           always ``True`` at the moment
        """

        logger = KtrLogger(LOGPREFIX)

        success = True

        for module in self.kpkg.get_modules():
            cleanup = module.clean()

            if not cleanup:
                logger.log("Module '" + str(module) + "' did not clean up successfully.")

            success = success and cleanup

        if success:
            logger.log(self.kpkg.get_conf_name() + ": Success!")
        else:
            logger.log(self.kpkg.get_conf_name() + ": Not successful.")

        return success
Пример #19
0
    def __init__(self, conf_name: str):
        assert isinstance(conf_name, str)

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        self.file = os.path.join(ktr.conf.get_confdir(), conf_name + ".conf")
        self.conf = ConfigParser()
        self.conf_name = conf_name

        if not os.path.exists(self.file):
            raise FileNotFoundError("Package configuration file does not exist.")

        success = self.conf.read(self.file)
        if not success:
            logger.err("Package configuration could not be read.")
            logger.err("Path: " + self.file)
            raise PackageError("Package configuration could not be read.")

        if not self.verify():
            raise PackageError("Package configuration file is invalid.")

        self.name = self.conf.get("package", "name")

        modules_str = str(self.conf.get("package", "modules"))
        module_type_list = modules_str.split(",")

        if module_type_list == [""]:
            module_type_list = []

        self.modules = OrderedDict()

        for module_type in module_type_list:
            module_type_enum = PkgModuleType[module_type.upper()]
            module_implement = str(self.conf.get("modules", module_type)).upper()

            module = PKG_MODULE_DICT[module_type_enum][
                PKG_MODULE_TYPE_DICT[module_type_enum][module_implement]](self)

            self.modules[module_type] = module

        for module in self.modules.values():
            assert isinstance(module, PkgModule)
            module.verify()
Пример #20
0
    def upload(self) -> bool:
        """
        This method executes the upload of the newest SRPM package found in the package directory.
        The invocation of `copr-cli` also includes the chroot settings set in the package
        configuration file.

        Returns:
            bool:       returns *False* if anything goes wrong, *True* otherwise
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        package_dir = os.path.join(ktr.conf.get_packdir(), self.upkg.get_conf_name())

        # get all srpms in the package directory
        srpms = glob.glob(os.path.join(package_dir, self.upkg.get_name() + "*.src.rpm"))

        if not srpms:
            logger.log("No source packages were found. Construct them first.")
            return False

        # figure out which srpm to build
        srpms.sort(reverse=True)
        srpm = srpms[0]

        # construct copr-cli command
        cmd = ["copr-cli", "build", self.get_repo()]

        # append chroots (dists)
        for dist in self.get_dists():
            cmd.append("--chroot")
            cmd.append(dist)

        # append --nowait if wait=False
        if not self.get_wait():
            cmd.append("--nowait")

        # append package
        cmd.append(srpm)

        # check for connectivity to server
        if not is_connected(self.remote):
            logger.log("No connection to remote host detected. Cancelling upload.", 2)
            return False

        logger.log_command(cmd, 1)
        subprocess.call(cmd)

        # TODO: error handling

        # remove source package if keep=False is specified
        if not self.get_keep():
            os.remove(srpm)

        return True
Пример #21
0
    def update(self) -> bool:
        """
        This method executes a git repository update as specified in the package configuration file.
        If a specific commit has been set in the config file, this method will not attempt to
        execute an update.

        Returns:
            bool: *True* if update available and successful, *False* if not
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        # if specific commit is requested, do not pull updates (obviously)
        if self.get_commit() == "HEAD":
            return False

        # check for connectivity to server
        if not is_connected(self.get_orig()):
            logger.log("No connection to remote host detected. Cancelling source update.", 2)
            return False

        # construct git command
        cmd = ["git", "pull", "--rebase"]

        # add --verbose or --quiet depending on settings
        if (ktr.verby == 2) and not ktr.debug:
            cmd.append("--quiet")
        if (ktr.verby == 0) or ktr.debug:
            cmd.append("--verbose")

        # check if source directory exists before going there
        if not os.access(self.dest, os.W_OK):
            logger.err("Sources need to be get before an update can be run.")
            return False

        # get old commit ID
        rev_old = self.commit()

        # change to git repository directory
        prev_dir = os.getcwd()
        os.chdir(self.dest)

        # get updates
        logger.log_command(cmd, 1)
        subprocess.call(cmd)

        # go back to previous dir
        os.chdir(prev_dir)

        # get new commit ID
        rev_new = self.commit()
        self.date()

        # return True if update found, False if not
        return rev_new != rev_old
Пример #22
0
def get_mock_cmd() -> str:
    """
    This function tries to determine the correct mock binary path. If something is messing with the
    `$PATH` environment variable, it will try to account for that. If mock is not installed (or
    cannot be found within `$PATH`, this function will raise an Exception.

    Raises:
        subprocess.CalledProcessError

    Returns:
        str:    path to the mock binary
    """
    logger = KtrLogger(LOG_PREFIX)

    mock_cmd = subprocess.check_output(["which", "mock"]).decode().rstrip("\n")

    # check if the right binary is used or if something is messing up $PATH
    if mock_cmd == "/usr/sbin/mock":
        logger.log("Something is messing with your $PATH variable.", 2)
        mock_cmd = "/usr/bin/mock"

    return mock_cmd
Пример #23
0
    def clean(self) -> bool:
        """
        This method cleans up all of a package's sources - excluding other files in the packages's
        source directory, which may include patches or other, additional files - they are preserved.

        Returns:
            bool:   *True* if successful
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        if not os.path.exists(self.sdir):
            logger.log("Nothing here to be cleaned.", 0)
            return True

        # try to be careful with "rm -r"
        assert os.path.isabs(self.dest)
        assert ktr.conf.get_datadir() in self.dest

        # remove source destination first

        # if destination is a file (tarball):
        if os.path.isfile(self.dest):
            os.remove(self.dest)

        # if destination is a directory (VCS repo):
        elif os.path.isdir(self.dest):
            shutil.rmtree(self.dest)

        # if source directory is empty now (no patches, additional files, etc. left):
        # remove whole directory
        if not os.listdir(self.sdir):
            os.rmdir(self.sdir)

        return True
Пример #24
0
    def build(self):
        """
        This method starts the mock build (and waits for already running builds with the same
        chroot to finish before that).

        Returns:
            int:    return code of the subprocess call
        """

        logger = KtrLogger(LOG_PREFIX)

        dist_path = os.path.join("/var/lib/mock/", self.dist)
        lock_path = os.path.join(dist_path, "buildroot.lock")

        # wait 2 minutes for builds occupying the specified build chroot
        if os.path.isdir(dist_path):
            build_wait = True

            while build_wait:
                lock_file = open(lock_path, "a+")

                try:
                    fcntl.lockf(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
                except IOError:
                    logger.log("The specified build chroot is busy, waiting.", 2)
                    time.sleep(120)
                else:
                    build_wait = False
                finally:
                    lock_file.close()

        cmd = self.get_command()
        logger.log_command(cmd)

        ret = subprocess.call(cmd)
        return ret
Пример #25
0
    def execute(self) -> bool:
        """
        This method runs the "chain reaction" corresponding to the package specified at
        initialisation, with the configuration from the package configuration file.

        Returns:
            bool:   ``True`` if chain went all the way through, ``False`` if not
        """

        ktr = Kentauros()
        logger = KtrLogger(LOGPREFIX)
        force = ktr.cli.get_force()

        success = True

        for module in self.kpkg.get_modules():
            succeeded = module.execute()

            if not succeeded:
                logger.err("Execution of module '" + str(module) + "' wasn't successful.")

                if force:
                    logger.log("Execution is forced to continue.")
                    success = success and succeeded
                    continue
                else:
                    success = False
                    break

        self.update_status()

        if success:
            logger.log(self.kpkg.get_conf_name() + ": Success!")
        else:
            logger.log(self.kpkg.get_conf_name() + ": Not successful.")

        return success
Пример #26
0
    def get(self) -> bool:
        """
        This method executes the download of the file specified by the URL to the package source
        directory.

        Returns:
            bool:  *True* if successful, *False* if not or source already exists
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        # check if $KTR_BASE_DIR/sources/$PACKAGE exists and create if not
        if not os.access(self.sdir, os.W_OK):
            os.makedirs(self.sdir)

        # if source seems to already exist, return False
        if os.access(self.dest, os.R_OK):
            logger.log("Sources already downloaded.", 1)
            return False

        # check for connectivity to server
        if not is_connected(self.get_orig()):
            logger.log("No connection to remote host detected. Cancelling source download.", 2)
            return False

        # construct wget commands
        cmd = ["wget"]

        # add --verbose or --quiet depending on settings
        if (ktr.verby == 2) and not ktr.debug:
            cmd.append("--quiet")
        if (ktr.verby == 0) or ktr.debug:
            cmd.append("--verbose")

        # set origin and destination
        cmd.append(self.get_orig())
        cmd.append("-O")
        cmd.append(self.dest)

        # wget source from origin to destination
        logger.log_command(cmd, 1)
        subprocess.call(cmd)

        return True
Пример #27
0
    def execute(self) -> bool:
        logger = KtrLogger(LOGPREFIX)

        constructor = self.kpkg.get_module("constructor")

        if constructor is None:
            logger.log("This package doesn't define a constructor module. Aborting.")
            return True

        success = constructor.execute()

        self.update_status()

        if success:
            logger.log(self.kpkg.get_conf_name() + ": Success!")
        else:
            logger.log(self.kpkg.get_conf_name() + ": Not successful.")

        return success
Пример #28
0
    def verify(self) -> bool:
        """
        This method runs several checks to ensure git commands can proceed. It is automatically
        executed at package initialisation. This includes:

        * checks if all expected keys are present in the configuration file
        * checks that the configuration file is consistent (i.e. shallow clone and commit checkout
          are not compatible)
        * checks if the `git` binary is installed and can be found on the system

        Returns:
            bool:   verification success
        """

        logger = KtrLogger(LOG_PREFIX)

        success = True

        # check if the configuration file is valid
        expected_keys = ["branch", "commit", "keep", "keep_repo", "orig", "shallow"]

        for key in expected_keys:
            if key not in self.spkg.conf["git"]:
                logger.err("The [git] section in the package's .conf file doesn't set the '" +
                           key +
                           "' key.")
                success = False

        # shallow clones and checking out a specific commit is not supported
        if (self.get_commit() != "HEAD") and self.get_shallow():
            logger.err("Shallow clones are not compatible with specifying a specific commit.")
            success = False

        # check if git is installed
        try:
            subprocess.check_output(["which", "git"]).decode().rstrip("\n")
        except subprocess.CalledProcessError:
            logger.log("Install git to use the specified source.")
            success = False

        return success
Пример #29
0
    def verify(self) -> bool:
        """
        This method runs several checks to ensure srpm builds can proceed. It is automatically
        executed at package initialisation. This includes:

        * checks if all expected keys are present in the configuration file
        * checks if the `mock` binary is installed and can be found on the system
        * checks if the current user is allowed to run builds with mock
        * checks if the current user is root (building as root is strongly discouraged)
        * checks if the .spec file is present at the expected location

        Returns:
            bool:   verification success
        """

        logger = KtrLogger(LOG_PREFIX)

        success = True

        # check if the configuration file is valid
        expected_keys = []

        for key in expected_keys:
            if key not in self.cpkg.conf["srpm"]:
                logger.err("The [srpm] section in the package's .conf file doesn't set the '" +
                           key +
                           "' key.")
                success = False

        # check for .spec file presence
        if not os.path.exists(self.path):
            logger.err("Spec file has not been found at the expected location:")
            logger.err(self.path)
            success = False

        # check if rpmbuild and rpmdev-bumpspec are installed
        try:
            subprocess.check_output(["which", "rpmbuild"]).decode().rstrip("\n")
        except subprocess.CalledProcessError:
            logger.log("Install rpm-build to use the srpm constructor.")
            success = False

        try:
            subprocess.check_output(["which", "rpmdev-bumpspec"]).decode().rstrip("\n")
        except subprocess.CalledProcessError:
            logger.log("Install rpmdevtools to use the srpm constructor.")
            success = False

        return success
Пример #30
0
    def prepare(self) -> bool:
        """
        This method prepares all files necessary for source package assembly.

        This includes

        - copying every file (not directories) from package source directory to `rpmbuild/SOURCES`,
        - removing the latest tarball from the package source directory if it should not be kept,
        - copying the package configuration file to `rpmbuild/SOURCES`
        - preparing the `package.spec` file in `rpmbuild/SPECS` from the file in the spec directory,
        - defining macros for git and bzr version string additions,
        - setting `Version:` and `Release:` tags according to configuration,
        - appending a changelog entry automatically for every different build,
        - copying back the modified spec file to preserve added changelog entries.

        Returns:
            bool:           returns `True` if the preparation was successful.
        """

        ktr = Kentauros()
        logger = KtrLogger(LOG_PREFIX)

        spec = RPMSpec(self.path, self.cpkg.get_module("source"))

        if not os.path.exists(self.rpmbdir):
            warnings.warn("Make sure to call Constructor.init() before .prepare()!", Warning)
            self.init()

        # copy sources to rpmbuild/SOURCES
        for entry in os.listdir(self.cpkg.get_module("source").sdir):
            entry_path = os.path.join(self.cpkg.get_module("source").sdir, entry)
            if os.path.isfile(entry_path):
                shutil.copy2(entry_path, self.srcsdir)
                logger.log("File copied to SOURCES: " + entry_path, 1)

        # remove tarballs if they should not be kept
        if not self.cpkg.get_module("source").get_keep():

            # if source is a tarball (or similar) from the beginning:
            if os.path.isfile(self.cpkg.get_module("source").dest):
                os.remove(self.cpkg.get_module("source").dest)

            # otherwise it is in kentauros' standard .tar.gz format:
            else:
                tarballs = glob.glob(os.path.join(self.cpkg.get_module("source").sdir,
                                                  self.cpkg.get_name()) + "*.tar.gz")
                # remove only the newest one to be safe
                tarballs.sort(reverse=True)
                if os.path.isfile(tarballs[0]):
                    assert self.cpkg.get_module("source").sdir in tarballs[0]
                    os.remove(tarballs[0])
                    logger.log("Tarball removed: " + tarballs[0], 1)

        # copy package.conf to rpmbuild/SOURCES
        shutil.copy2(self.cpkg.file, self.srcsdir)
        logger.log("Package configuration copied to SOURCES: " + self.cpkg.file, 1)

        # construct preamble and new version string
        old_version = self._get_last_version(spec)
        old_release = self._get_last_release(spec)
        new_version = self.cpkg.get_version()

        # TODO: check if release resetting / incrementing logic works now

        spec.set_version()
        spec.set_source()

        # if old version and new version are different, force release reset to 0
        rel_reset = (new_version != old_version)

        # start constructing release string from old release string
        if rel_reset:
            spec.do_release_reset()

        # write preamble to new spec file
        preamble = spec.build_preamble_string()

        # calculate absolute path of new spec file and copy it over
        new_spec_path = os.path.join(self.specdir, self.cpkg.get_name() + ".spec")
        spec.export_to_file(new_spec_path)

        # use "rpmdev-bumpspec" to increment release number and create changelog entries
        force = ktr.cli.get_force()

        logger.dbg("Old Version: " + old_version)
        logger.dbg("New Version: " + new_version)
        logger.dbg("Old Release: " + old_release)

        # if major version has changed, put it into the changelog
        if (old_version != new_version) or (old_release[0] == "0"):
            do_release_bump(new_spec_path,
                            "Update to version " + self.cpkg.get_version() + ".")
            new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source"))

        # else if nothing changed but "force" was set (packaging changes)
        # old_version =!= new_version, rel_reset !=!= True
        elif force:
            message = ktr.cli.get_message()
            if message is None:
                do_release_bump(new_spec_path, "Update for packaging changes.")
            else:
                do_release_bump(new_spec_path, message)

            new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source"))

        # else if version has not changed, but snapshot has been updated:
        # old_version =!= new_version
        elif rel_reset:
            new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source"))
            new_rpm_spec.do_release_reset()
            do_release_bump(new_spec_path, "Update to latest snapshot.")
            new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source"))

        else:
            logger.err("Something went wrong.")
            return False

        self.last_release = new_rpm_spec.get_release()
        self.last_version = new_rpm_spec.get_version()

        # copy new spec file back to ktr/specdir to preserve version tracking,
        # release number and changelog consistency (keep old version once as backup)
        # BUT: remove preamble again, it would break things otherwise

        new_rpm_spec.contents = new_rpm_spec.contents.replace(preamble, "")
        shutil.copy2(self.path, self.path + ".old")
        new_rpm_spec.export_to_file(self.path)

        return True