Exemple #1
0
class ParticipantHandler(object):
    """Participant class as defined by the SkyNET API"""

    def __init__(self):
        self.obs = None
        self.oscrc = None
        self.validator = Validator()

    def handle_wi_control(self, ctrl):
        """Job control thread"""
        pass

    def handle_lifecycle_control(self, ctrl):
        """Handle messages for the participant itself, like start and stop."""
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """Setup the Buildservice instance

        :param namespace: Alias to the OBS apiurl.
        """
        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def _get_spec_file(self, prj, pkg, rev):

        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        specs = [ fil for fil in file_list if fil.endswith(".spec")]

        if len(specs) > 1:
             specs = [ fil for fil in specs if (fil == "%s.spec" % pkg or fil.endswith(":%s.spec" % pkg))]

        if not specs:
            return "No specfile in %s" % pkg, None

        elif len(specs) > 1:
             return "Couldn't determine which spec file to use for %s " % pkg, None

        print specs
        fil = specs[0]

        spec = self.obs.getFile(prj, pkg, fil, revision=rev)
        specob = None

        with NamedTemporaryFile() as specf:
            specf.write(spec)
            specf.flush()
            try:
                specob = parse_spec(specf.name)
            except ValueError, exobj:
                return "Could not parse spec in %s: %s" % (pkg, exobj), None

        return None, specob
class ParticipantHandler(object):

    """ Participant class as defined by the SkyNET API """

    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_changes_file(self, prj, pkg, rev=None):

        """ Get a package's changes file """

        changelog = ""
        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        for fil in file_list:
            if fil.endswith(".changes"):
                changelog = self.obs.getFile(prj, pkg, fil)
        return changelog

    def handle_wi(self, wid):
        """ actual job thread """
        wid.result = False

        missing = [name for name in ["project", "package"]
                if not getattr(wid.fields, name, None)]
        if missing:
            raise RuntimeError("Missing mandatory field(s): %s" %
                ", ".join(missing))

        self.setup_obs(wid.fields.ev.namespace)

        wid.fields.changelog = self.get_changes_file(
                wid.fields.project,
                wid.fields.package)

        wid.result = True
Exemple #3
0
class ParticipantHandler(object):
    """ Participant class as defined by the SkyNET API """
    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_changes_file(self, prj, pkg, rev=None):
        """ Get a package's changes file """

        changelog = ""
        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        for fil in file_list:
            if fil.endswith(".changes"):
                changelog = self.obs.getFile(prj, pkg, fil)
        return changelog

    def handle_wi(self, wid):
        """ actual job thread """
        wid.result = False

        missing = [
            name for name in ["project", "package"]
            if not getattr(wid.fields, name, None)
        ]
        if missing:
            raise RuntimeError("Missing mandatory field(s): %s" %
                               ", ".join(missing))

        self.setup_obs(wid.fields.ev.namespace)

        wid.fields.changelog = self.get_changes_file(wid.fields.project,
                                                     wid.fields.package)

        wid.result = True
class ParticipantHandler(object):
    """Participant class as defined by the SkyNET API"""

    def __init__(self):
        self.obs = None
        self.oscrc = None
        self.validator = Validator()

    def handle_wi_control(self, ctrl):
        """Job control thread"""
        pass

    def handle_lifecycle_control(self, ctrl):
        """Handle messages for the participant itself, like start and stop."""
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """Setup the Buildservice instance

        :param namespace: Alias to the OBS apiurl.
        """
        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def check_spec_version_match(self, version, prj, pkg, rev=None):
        """Check that spec version matches given version"""
        spec = ""
        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        for fil in file_list:
            if fil.endswith(".spec"):
                spec = self.obs.getFile(prj, pkg, fil, revision=rev)
                break
        if not spec:
            return False, "No specfile in %s" % pkg
        with NamedTemporaryFile() as specf:
            specf.write(spec)
            specf.flush()
            try:
                specob = parse_spec(specf.name)
            except ValueError, exobj:
                return False, "Could not parse spec in %s: %s" % (pkg, exobj)
        src_hdrs = [pkg for pkg in specob.packages if pkg.header.isSource()][0]
        spec_version = src_hdrs.header[rpm.RPMTAG_VERSION]
        if spec_version != version.split('-')[0]:
            return False, "Last changelog version %s does not match" \
                          " version %s in spec file." % (version, spec_version)
        return True, None
class ParticipantHandler(object):

    """ Participant class as defined by the SkyNET API """

    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_changes_file(self, prj, pkg, rev=None):
        """ Get a package's changes file """

        changelog = ""
        try:
            file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
            for fil in file_list:
                if fil.endswith(".changes"):
                    changelog = self.obs.getFile(prj, pkg, fil, revision=rev)
        except HTTPError, e:
            if e.code == 404:
                pass

        return changelog
Exemple #6
0
class ParticipantHandler(object):
    """ Participant class as defined by the SkyNET API """
    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_changes_file(self, prj, pkg, rev=None):
        """ Get a package's changes file """

        changelog = ""
        try:
            file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
            for fil in file_list:
                if fil.endswith(".changes"):
                    changelog = self.obs.getFile(prj, pkg, fil, revision=rev)
        except HTTPError, e:
            if e.code == 404:
                pass

        return changelog
Exemple #7
0
class ParticipantHandler(object):
    """ Participant class as defined by the SkyNET API """
    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    @CheckActionProcessor("check_package_is_complete")
    def is_complete(self, action, wid):
        """ Package file completeness check """

        filelist = self.obs.getPackageFileList(action['sourceproject'],
                                               action['sourcepackage'],
                                               action['sourcerevision'])

        if "_service" in filelist:
            filelist.remove("_service")
        if "_ccache" in filelist:
            filelist.remove("_ccache")
        if "_src" in filelist:
            filelist.remove("_src")
        spec = self.has_spec_file(action, wid, filelist)[0]
        changes = self.has_changes_file(action, wid, filelist)[0]
        sources = spec and self.check_source_files(action, wid, filelist)[0]

        return (spec and changes and sources), ""

    def get_rpm_sources(self, action, filelist):
        """Extract source file list from package spec.

        :parma action: OBS request action dictionary
        :param filelist: List of package files
        :returns: List of source file names
        :raises SourceError: If something goes wrong
        """
        try:
            specs = [name for name in filelist if name.endswith(".spec")]
            if len(specs) > 1:
                specs = [
                    name for name in filelist
                    if name.endswith("%s.spec" % action['sourcepackage'])
                ]
            if len(specs) > 1:
                specs = [
                    name for name in filelist
                    if name.endswith(":%s.spec" % action['sourcepackage'])
                ]
            spec_name = specs[0]
        except IndexError:
            # raise SourceError("No spec file found")
            return []
        print spec_name
        try:
            spec = self.obs.getFile(action["sourceproject"],
                                    action["sourcepackage"], spec_name,
                                    action["sourcerevision"])
        except Exception, exobj:
            raise SourceError(
                "Failed to fetch spec file %s/%s/%s rev %s: %s" %
                (action["sourceproject"], action["sourcepackage"], spec_name,
                 action["sourcerevision"], exobj))
        import hashlib
        print "Spec file retrieved from", action["sourceproject"], action[
            "sourcepackage"], action["sourcerevision"], ": ", hashlib.md5(
                spec).hexdigest()
        try:
            tmp_spec = NamedTemporaryFile(mode="w", delete=False)
            tmp_spec.file.write(spec)
            tmp_spec.file.flush()
            print "Parsing spec file from", tmp_spec.name
            spec_obj = parse_spec(tmp_spec.name)
            sources = [
                os.path.basename(name) for name, _, _ in spec_obj.sources
            ]
            tmp_spec.close()
        except ValueError, exobj:
            raise SourceError("Failed to parse spec file: %s" % exobj)
class ParticipantHandler(object):

    """ Participant class as defined by the SkyNET API """

    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    @CheckActionProcessor("check_package_is_complete")
    def is_complete(self, action, wid):
        """ Package file completeness check """

        filelist = self.obs.getPackageFileList(
                action['sourceproject'],
                action['sourcepackage'],
                action['sourcerevision'])

        # Remove all files starting with _ which don't have a : in
        # them (_constraints, _service but not _service:filename)
        filelist = [f for f in filelist if not re.match(r"_[^:]*$", f)]
        spec = self.has_spec_file(action, wid, filelist)[0]
        changes = self.has_changes_file(action, wid, filelist)[0]
        sources = spec and self.check_source_files(action, wid, filelist)[0]

        return (spec and changes and sources), ""

    def get_rpm_sources(self, action, filelist):
        """Extract source file list from package spec.

        :parma action: OBS request action dictionary
        :param filelist: List of package files
        :returns: List of source file names
        :raises SourceError: If something goes wrong
        """
        try:
            specs = [name for name in filelist if name.endswith(".spec")]
            if len(specs) > 1:
                specs = [name for name in filelist if name.endswith("%s.spec" % action['sourcepackage'])]
            if len(specs) > 1:
                specs = [name for name in filelist if name.endswith(":%s.spec" % action['sourcepackage'])]
            spec_name = specs[0]
        except IndexError:
            # raise SourceError("No spec file found")
            return []
        print spec_name
        try:
            spec = self.obs.getFile(action["sourceproject"],
                    action["sourcepackage"], spec_name,
                    action["sourcerevision"])
        except Exception, exobj:
            raise SourceError("Failed to fetch spec file %s/%s/%s rev %s: %s" %
                    (action["sourceproject"], action["sourcepackage"],
                    spec_name, action["sourcerevision"], exobj))
        import hashlib
        print "Spec file retrieved from", action["sourceproject"], action["sourcepackage"], action["sourcerevision"], ": ", hashlib.md5(spec).hexdigest()
        try:
            tmp_spec = NamedTemporaryFile(mode="w", delete=False)
            tmp_spec.file.write(spec)
            tmp_spec.file.flush()
            print "Parsing spec file from", tmp_spec.name
            spec_obj = parse_spec(tmp_spec.name)
            sources = [os.path.basename(name) for name, _, _ in
                       spec_obj.sources]
            tmp_spec.close()
        except ValueError, exobj:
            raise SourceError("Failed to parse spec file: %s" % exobj)
class ParticipantHandler(object):
    """ Participant class as defined by the SkyNET API """
    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_spec_file(self, prj, pkg, rev=None):
        """ Get a package's spec file """

        spec = ""
        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        for fil in file_list:
            if fil.endswith(".spec"):
                spec = self.obs.getFile(prj, pkg, fil, revision=rev)
        return spec

    @CheckActionProcessor("check_spec")
    def spec_valid(self, action, _wid):
        """
          Get spec file and check for various indications of spec file validity
        """
        spec = self.get_spec_file(action['sourceproject'],
                                  action['sourcepackage'],
                                  action['sourcerevision'])

        if has_section_or_tag(spec, "%changelog"):
            return False, "Spec file should not contain the %%changelog tag, "\
                    "otherwise the changes file is ignored."

        return True, None

    def handle_wi(self, wid):
        """ actual job thread """

        wid.result = False
        if not wid.fields.msg:
            wid.fields.msg = []
        actions = wid.fields.ev.actions

        if not actions:
            raise RuntimeError("Mandatory field: actions does not exist.")

        self.setup_obs(wid.fields.ev.namespace)
        result = True

        for action in actions:
            # Assert validity of spec file
            valid, _ = self.spec_valid(action, wid)
            result = result and valid

        wid.result = result
class ParticipantHandler(object):

    """ Participant class as defined by the SkyNET API """

    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    @CheckActionProcessor("check_package_is_complete")
    def is_complete(self, action, wid):
        """ Package file completeness check """

        filelist = self.obs.getPackageFileList(
                action['sourceproject'],
                action['sourcepackage'],
                action['sourcerevision'])

        if "_service" in filelist:
            filelist.remove("_service")
        if "_ccache" in filelist:
            filelist.remove("_ccache")
        if "_src" in filelist:
            filelist.remove("_src")
        spec = self.has_spec_file(action, wid, filelist)[0]
        changes = self.has_changes_file(action, wid, filelist)[0]
        sources = spec and self.check_source_files(action, wid, filelist)[0]

        return (spec and changes and sources), ""

    def get_rpm_sources(self, action, filelist):
        """Extract source file list from package spec.

        :parma action: OBS request action dictionary
        :param filelist: List of package files
        :returns: List of source file names
        :raises SourceError: If something goes wrong
        """
        try:
            spec_name = [name for name in filelist if name.endswith(".spec")][0]
        except IndexError:
            # raise SourceError("No spec file found")
            return []
        try:
            spec = self.obs.getFile(action["sourceproject"],
                    action["sourcepackage"], spec_name,
                    action["sourcerevision"])
        except Exception, exobj:
            raise SourceError("Failed to fetch spec file %s/%s/%s rev %s: %s" %
                    (action["sourceproject"], action["sourcepackage"],
                    spec_name, action["sourcerevision"], exobj))
        try:
            tmp_spec = NamedTemporaryFile(mode="w")
            tmp_spec.file.write(spec)
            tmp_spec.file.flush()
            spec_obj = parse_spec(tmp_spec.name)
            sources = [os.path.basename(name) for name, _, _ in
                       spec_obj.sources]
            tmp_spec.close()
        except ValueError, exobj:
            raise SourceError("Failed to parse spec file: %s" % exobj)
class ParticipantHandler(object):
    """Participant class as defined by the SkyNET API."""

    def __init__(self):
        self.oscrc = None
        self.namespace = None
        self.obs = None
        self.spec_re = None

    def handle_lifecycle_control(self, ctrl):
        """Participant life cycle control."""
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")
            else:
                raise RuntimeError("Participant config missing "
                        "[obs] oscrc option")
            if ctrl.config.has_option("check_yaml", "spec_pattern"):
                pat = ctrl.config.get("check_yaml", "spec_pattern")
            else:
                pat = DEFAULT_SPEC_PATTERN
            self.spec_re = re.compile(pat)
            self.log.info("oscrc: %s" % self.oscrc)
            self.log.info("spec_pattern: %s" % pat)

    def handle_wi_control(self, ctrl):
        """Job control."""
        pass

    def setup_obs(self, namespace):
        """Set up OBS instance."""
        if not self.obs or self.namespace != namespace:
            self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)
            self.namespace = namespace

    def handle_wi(self, wid):
        """Job thread."""
        wid.result = False
        if not isinstance(wid.fields.msg, list):
            wid.fields.msg = []

        if not wid.fields.ev:
            raise RuntimeError("Missing mandatory field 'ev'")
        if not isinstance(wid.fields.ev.actions, list):
            raise RuntimeError("Mandatory field ev.actions not a list")
        if not isinstance(wid.fields.ev.namespace, basestring):
            raise RuntimeError("Mandatory field ev.namespace not a string")

        self.setup_obs(wid.fields.ev.namespace)

        result = True
        for action in wid.fields.ev.actions:
            pkg_result, _ = self.__handle_action(action, wid)
            result = result and pkg_result
        wid.result = result

    @CheckActionProcessor("check_yaml_matches_spec")
    def __handle_action(self, action, _wid):
        """Process single action from OBS event info.

        :param action: Single dictionary from OBS event actions list
        :returns: True if all good, False otherwise
        """
        project = action["sourceproject"]
        package = action["sourcepackage"]
        revision = action["sourcerevision"]
        files = self.obs.getPackageFileList(project, package, revision)

        with Lab(prefix="check_yaml_spec_") as lab:
            spec = None
            yaml = None
            for name in files:
                if name.endswith(".spec"):
                    lab.store(name, self.obs.getFile(project, package, name,
                        revision))
                    spec = name
                elif name.endswith(".yaml"):
                    lab.store(name, self.obs.getFile(project, package, name,
                        revision))
                    yaml = name

            if not (spec and self.spec_re.search(lab.open(spec).read())):
                # No spec file or spec not from spectacle, skip
                return True, None
            if not yaml:
                return False, "SPEC file generated with spectacle, " \
                              "but yaml not present"

            snapshot = lab.take_snapshot()
            # Download rest of the files
            files.remove(spec)
            files.remove(yaml)
            for name in files:
                lab.store(name, self.obs.getFile(project, package, name,
                        revision))

            # Run specify
            specify = subprocess.Popen(["specify", "-n", "-N",
                lab.real_path(yaml)], stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT, env={"ANSI_COLORS_DISABLED":"1"})
            rcode = specify.wait()
            if rcode != 0:
                return False, "Running specify failed:\n%s" \
                        % specify.stdout.read()
            # Get the diff
            diff = lab.get_diff(spec, snapshot)
            clean_diff = []
            for line in diff:
                # ignore the ? seperator lines
                if line[0] == "?":
                    continue
                # Remove diff markers and white space
                stripped = line[2:].strip()
                # skip empty lines
                if not stripped:
                    continue
                # skip comments
                if stripped[0] == "#":
                    continue
                # effective change
                clean_diff.append(line)
            if clean_diff:
                return False, "Spec file changed by specify:\n%s" \
                        % "".join(clean_diff)
        return True, None
class ParticipantHandler(object):
    """Participant class as defined by the SkyNET API"""

    def __init__(self):
        self.obs = None
        self.oscrc = None
        self.validator = Validator()

    def handle_wi_control(self, ctrl):
        """Job control thread"""
        pass

    def handle_lifecycle_control(self, ctrl):
        """Handle messages for the participant itself, like start and stop."""
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """Setup the Buildservice instance

        :param namespace: Alias to the OBS apiurl.
        """
        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def _get_spec_file(self, prj, pkg, rev):

        file_list = []
        try:
            file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        except:
            pass

        specs = [ fil for fil in file_list if fil.endswith(".spec")]

        if len(specs) > 1:
             specs = [ fil for fil in specs if (fil == "%s.spec" % pkg or fil.endswith(":%s.spec" % pkg))]

        if not specs:
            return "No specfile in %s" % pkg, None

        elif len(specs) > 1:
             return "Couldn't determine which spec file to use for %s " % pkg, None

        print specs
        fil = specs[0]

        spec = self.obs.getFile(prj, pkg, fil, revision=rev)
        specob = None

        print fil
        print spec
        with NamedTemporaryFile() as specf:
            specf.write(spec)
            specf.flush()
            try:
                specob = parse_spec(specf.name)
            except ValueError, exobj:
                return "Could not parse spec in %s: %s" % (pkg, exobj), None

        return None, specob
class ParticipantHandler(object):

    """ Participant class as defined by the SkyNET API """

    def __init__(self):
        self.obs = None
        self.oscrc = None

    def handle_wi_control(self, ctrl):
        """ job control thread """
        pass

    def handle_lifecycle_control(self, ctrl):
        """ participant control thread """
        if ctrl.message == "start":
            if ctrl.config.has_option("obs", "oscrc"):
                self.oscrc = ctrl.config.get("obs", "oscrc")

    def setup_obs(self, namespace):
        """ setup the Buildservice instance using the namespace as an alias
            to the apiurl """

        self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)

    def get_spec_file(self, prj, pkg, rev=None):

        """ Get a package's spec file """

        spec = ""
        file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
        for fil in file_list:
            if fil.endswith(".spec"):
                spec = self.obs.getFile(prj, pkg, fil, revision=rev)
        return spec

    @CheckActionProcessor("check_spec")
    def spec_valid(self, action, _wid):
        """
          Get spec file and check for various indications of spec file validity
        """
        spec = self.get_spec_file(action["sourceproject"], action["sourcepackage"], action["sourcerevision"])

        if has_section_or_tag(spec, "%changelog"):
            return False, "Spec file should not contain the %%changelog tag, " "otherwise the changes file is ignored."

        return True, None

    def handle_wi(self, wid):
        """ actual job thread """

        wid.result = False
        if not wid.fields.msg:
            wid.fields.msg = []
        actions = wid.fields.ev.actions

        if not actions:
            raise RuntimeError("Mandatory field: actions does not exist.")

        self.setup_obs(wid.fields.ev.namespace)
        result = True

        for action in actions:
            # Assert validity of spec file
            valid, _ = self.spec_valid(action, wid)
            result = result and valid

        wid.result = result