Ejemplo n.º 1
0
class LegalFlag(db.Model, helpers.Serializer):
    id = db.Column(db.Integer, primary_key=True)
    # message from user who raised the flag (what he thinks is wrong)
    raise_message = db.Column(db.Text)
    # time of raising the flag as returned by int(time.time())
    raised_on = db.Column(db.Integer)
    # time of resolving the flag by admin as returned by int(time.time())
    resolved_on = db.Column(db.Integer)

    # relations
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), nullable=True)
    # cascade="all" means that we want to keep these even if copr is deleted
    copr = db.relationship("Copr",
                           backref=db.backref("legal_flags", cascade="all"))
    # user who reported the problem
    reporter_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    reporter = db.relationship("User",
                               backref=db.backref("legal_flags_raised"),
                               foreign_keys=[reporter_id],
                               primaryjoin="LegalFlag.reporter_id==User.id")
    # admin who resolved the problem
    resolver_id = db.Column(db.Integer,
                            db.ForeignKey("user.id"),
                            nullable=True)
    resolver = db.relationship("User",
                               backref=db.backref("legal_flags_resolved"),
                               foreign_keys=[resolver_id],
                               primaryjoin="LegalFlag.resolver_id==User.id")
Ejemplo n.º 2
0
class CoprPermission(db.Model, helpers.Serializer):
    """
    Association class for Copr<->Permission relation
    """

    # see helpers.PermissionEnum for possible values of the fields below
    # can this user build in the copr?
    copr_builder = db.Column(db.SmallInteger, default=0)
    # can this user serve as an admin? (-> edit and approve permissions)
    copr_admin = db.Column(db.SmallInteger, default=0)

    # relations
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
    user = db.relationship("User", backref=db.backref("copr_permissions"))
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
    copr = db.relationship("Copr", backref=db.backref("copr_permissions"))
Ejemplo n.º 3
0
class CoprChroot(db.Model, helpers.Serializer):
    """
    Representation of Copr<->MockChroot relation
    """

    buildroot_pkgs = db.Column(db.Text)
    mock_chroot_id = db.Column(db.Integer,
                               db.ForeignKey("mock_chroot.id"),
                               primary_key=True)
    mock_chroot = db.relationship("MockChroot",
                                  backref=db.backref("copr_chroots"))
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
    copr = db.relationship("Copr",
                           backref=db.backref(
                               "copr_chroots",
                               single_parent=True,
                               cascade="all,delete,delete-orphan"))

    comps_zlib = db.Column(db.LargeBinary(), nullable=True)
    comps_name = db.Column(db.String(127), nullable=True)

    def update_comps(self, comps_xml):
        self.comps_zlib = zlib.compress(comps_xml.encode("utf-8"))

    @property
    def buildroot_pkgs_list(self):
        return self.buildroot_pkgs.split()

    @property
    def comps(self):
        if self.comps_zlib:
            return zlib.decompress(self.comps_zlib).decode("utf-8")

    @property
    def comps_len(self):
        if self.comps_zlib:
            return len(zlib.decompress(self.comps_zlib))
        else:
            return 0

    @property
    def name(self):
        return self.mock_chroot.name

    @property
    def is_active(self):
        return self.mock_chroot.is_active
Ejemplo n.º 4
0
class CoprChroot(db.Model, helpers.Serializer):
    """
    Representation of Copr<->MockChroot relation
    """

    buildroot_pkgs = db.Column(db.Text)
    mock_chroot_id = db.Column(db.Integer,
                               db.ForeignKey("mock_chroot.id"),
                               primary_key=True)
    mock_chroot = db.relationship("MockChroot",
                                  backref=db.backref("copr_chroots"))
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
    copr = db.relationship("Copr",
                           backref=db.backref(
                               "copr_chroots",
                               single_parent=True,
                               cascade="all,delete,delete-orphan"))
Ejemplo n.º 5
0
class BuildChroot(db.Model, helpers.Serializer):
    """
    Representation of Build<->MockChroot relation
    """

    mock_chroot_id = db.Column(db.Integer,
                               db.ForeignKey("mock_chroot.id"),
                               primary_key=True)
    mock_chroot = db.relationship("MockChroot", backref=db.backref("builds"))
    build_id = db.Column(db.Integer,
                         db.ForeignKey("build.id"),
                         primary_key=True)
    build = db.relationship("Build", backref=db.backref("build_chroots"))
    status = db.Column(db.Integer, default=helpers.StatusEnum("pending"))

    @property
    def name(self):
        """
        Textual representation of name of this chroot
        """

        return self.mock_chroot.name

    @property
    def state(self):
        """
        Return text representation of status of this build chroot
        """

        if self.status is not None:
            return helpers.StatusEnum(self.status)

        return "unknown"

    def __str__(self):
        return "<BuildChroot: {}>".format(self.to_dict())
Ejemplo n.º 6
0
class Krb5Login(db.Model, helpers.Serializer):
    """
    Represents additional user information for kerberos authentication.
    """

    __tablename__ = "krb5_login"

    # FK to User table
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)

    # 'string' from 'copr.conf' from KRB5_LOGIN[string]
    config_name = db.Column(db.String(30), nullable=False, primary_key=True)

    # krb's primary, i.e. 'username' from '*****@*****.**'
    primary = db.Column(db.String(80), nullable=False, primary_key=True)

    user = db.relationship("User", backref=db.backref("krb5_logins"))
Ejemplo n.º 7
0
class Package(db.Model, helpers.Serializer):
    """
    Represents a single package in a project.
    """
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    # Source of the build: type identifier
    source_type = db.Column(db.Integer,
                            default=helpers.BuildSourceEnum("unset"))
    # Source of the build: description in json, example: git link, srpm url, etc.
    source_json = db.Column(db.Text)
    # True if the package is built automatically via webhooks
    webhook_rebuild = db.Column(db.Boolean, default=False)
    # enable networking during a build process
    enable_net = db.Column(db.Boolean,
                           default=False,
                           server_default="0",
                           nullable=False)

    # relations
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
    copr = db.relationship("Copr", backref=db.backref("packages"))

    @property
    def dist_git_repo(self):
        if self.copr.is_a_group_project:
            return "@{}/{}/{}".format(self.copr.group.name, self.copr.name,
                                      self.name)
        else:
            return "{}/{}/{}".format(self.copr.owner.name, self.copr.name,
                                     self.name)

    @property
    def source_json_dict(self):
        return json.loads(self.source_json)

    @property
    def source_type_text(self):
        return helpers.BuildSourceEnum(self.source_type)

    @property
    def dist_git_url(self):
        if app.config["DIST_GIT_URL"]:
            return "{}/{}.git".format(app.config["DIST_GIT_URL"],
                                      self.dist_git_repo)
        return None
Ejemplo n.º 8
0
class Build(db.Model, helpers.Serializer):
    """
    Representation of one build in one copr
    """

    id = db.Column(db.Integer, primary_key=True)
    # single url to the source rpm, should not contain " ", "\n", "\t"
    pkgs = db.Column(db.Text)
    # built packages
    built_packages = db.Column(db.Text)
    # version of the srpm package got by rpm
    pkg_version = db.Column(db.Text)
    # was this build canceled by user?
    canceled = db.Column(db.Boolean, default=False)
    # list of space separated additional repos
    repos = db.Column(db.Text)
    # the three below represent time of important events for this build
    # as returned by int(time.time())
    submitted_on = db.Column(db.Integer, nullable=False)
    started_on = db.Column(db.Integer)
    ended_on = db.Column(db.Integer)
    # url of the build results
    results = db.Column(db.Text)
    # memory requirements for backend builder
    memory_reqs = db.Column(db.Integer, default=constants.DEFAULT_BUILD_MEMORY)
    # maximum allowed time of build, build will fail if exceeded
    timeout = db.Column(db.Integer, default=constants.DEFAULT_BUILD_TIMEOUT)
    # enable networking during a build process
    enable_net = db.Column(db.Boolean,
                           default=False,
                           server_default="0",
                           nullable=False)

    # relations
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    user = db.relationship("User", backref=db.backref("builds"))
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
    copr = db.relationship("Copr", backref=db.backref("builds"))

    chroots = association_proxy("build_chroots", "mock_chroot")

    @property
    def chroot_states(self):
        return map(lambda chroot: chroot.status, self.build_chroots)

    def get_chroots_by_status(self, statuses=None):
        """
        Get build chroots with states which present in `states` list
        If states == None, function returns build_chroots
        """
        chroot_states_map = dict(zip(self.build_chroots, self.chroot_states))
        if statuses is not None:
            statuses = set(statuses)
        else:
            return self.build_chroots

        return [
            chroot for chroot, status in chroot_states_map.items()
            if status in statuses
        ]

    @property
    def has_pending_chroot(self):
        # FIXME bad name
        # used when checking if the repo is initialized and results can be set
        # i think this is the only purpose - check
        return helpers.StatusEnum("pending") in self.chroot_states or \
            helpers.StatusEnum("starting") in self.chroot_states

    @property
    def has_unfinished_chroot(self):
        return helpers.StatusEnum("pending") in self.chroot_states or \
            helpers.StatusEnum("starting") in self.chroot_states or \
            helpers.StatusEnum("running") in self.chroot_states

    @property
    def status(self):
        """
        Return build status according to build status of its chroots
        """

        if self.canceled:
            return helpers.StatusEnum("canceled")

        for state in [
                "failed", "running", "starting", "pending", "succeeded",
                "skipped"
        ]:
            if helpers.StatusEnum(state) in self.chroot_states:
                return helpers.StatusEnum(state)

    @property
    def state(self):
        """
        Return text representation of status of this build
        """

        if self.status is not None:
            return helpers.StatusEnum(self.status)

        return "unknown"

    @property
    def cancelable(self):
        """
        Find out if this build is cancelable.

        Build is cancelabel only when it's pending (not started)
        """

        return self.status == helpers.StatusEnum("pending")

    @property
    def repeatable(self):
        """
        Find out if this build is repeatable.

        Build is repeatable only if it's not pending, starting or running
        """

        return self.status not in [
            helpers.StatusEnum("pending"),
            helpers.StatusEnum("starting"),
            helpers.StatusEnum("running"),
        ]

    @property
    def deletable(self):
        """
        Find out if this build is deletable.

        Build is deletable only when it's finished. (also means cancelled)
        It is important to remember that "failed" state doesn't ultimately
        mean it's finished - so we need to check whether the "ended_on"
        property has been set.
        """

        if self.state == "failed" and self.ended_on is not None:
            return True

        return self.state in ["succeeded", "canceled", "skipped"]

    @property
    def src_pkg_name(self):
        """
        Extract source package name from URL
        """
        src_rpm_name = self.pkgs.split("/")[-1]
        if src_rpm_name.endswith(".src.rpm"):
            return src_rpm_name[:-8]
        else:
            return src_rpm_name
Ejemplo n.º 9
0
class Copr(db.Model, helpers.Serializer):
    """
    Represents a single copr (private repo with builds, mock chroots, etc.).
    """

    id = db.Column(db.Integer, primary_key=True)
    # name of the copr, no fancy chars (checked by forms)
    name = db.Column(db.String(100), nullable=False)
    # string containing urls of additional repos (separated by space)
    # that this copr will pull dependencies from
    repos = db.Column(db.Text)
    # time of creation as returned by int(time.time())
    created_on = db.Column(db.Integer)
    # description and instructions given by copr owner
    description = db.Column(db.Text)
    instructions = db.Column(db.Text)
    deleted = db.Column(db.Boolean, default=False)
    playground = db.Column(db.Boolean, default=False)

    # should copr run `createrepo` each time when build packages are changed
    auto_createrepo = db.Column(db.Boolean, default=True)

    # relations
    owner_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    owner = db.relationship("User", backref=db.backref("coprs"))
    mock_chroots = association_proxy("copr_chroots", "mock_chroot")

    # enable networking for the builds by default
    build_enable_net = db.Column(db.Boolean,
                                 default=True,
                                 server_default="1",
                                 nullable=False)

    __mapper_args__ = {"order_by": created_on.desc()}

    @property
    def repos_list(self):
        """
        Return repos of this copr as a list of strings
        """
        return self.repos.split()

    @property
    def active_chroots(self):
        """
        Return list of active mock_chroots of this copr
        """

        return filter(lambda x: x.is_active, self.mock_chroots)

    @property
    def build_count(self):
        """
        Return number of builds in this copr
        """

        return len(self.builds)

    @property
    def disable_createrepo(self):

        return not self.auto_createrepo

    @disable_createrepo.setter
    def disable_createrepo(self, value):

        self.auto_createrepo = not bool(value)

    def check_copr_chroot(self, chroot):
        """
        Return object of chroot, if is related to our copr or None
        """

        result = None
        # there will be max ~10 chroots per build, iteration will be probably
        # faster than sql query
        for copr_chroot in self.copr_chroots:
            if copr_chroot.mock_chroot_id == chroot.id:
                result = copr_chroot
                break
        return result

    def buildroot_pkgs(self, chroot):
        """
        Return packages in minimal buildroot for given chroot.
        """

        result = ""
        # this is ugly as user can remove chroot after he submit build, but
        # lets call this feature
        copr_chroot = self.check_copr_chroot(chroot)
        if copr_chroot:
            result = copr_chroot.buildroot_pkgs
        return result

    @property
    def modified_chroots(self):
        """
        Return list of chroots which has been modified
        """
        modified_chroots = []
        for chroot in self.active_chroots:
            if self.buildroot_pkgs(chroot):
                modified_chroots.append(chroot)
        return modified_chroots
Ejemplo n.º 10
0
class BuildChroot(db.Model, helpers.Serializer):
    """
    Representation of Build<->MockChroot relation
    """

    mock_chroot_id = db.Column(db.Integer,
                               db.ForeignKey("mock_chroot.id"),
                               primary_key=True)
    mock_chroot = db.relationship("MockChroot", backref=db.backref("builds"))
    build_id = db.Column(db.Integer,
                         db.ForeignKey("build.id"),
                         primary_key=True)
    build = db.relationship("Build", backref=db.backref("build_chroots"))
    git_hash = db.Column(db.String(40))
    status = db.Column(db.Integer, default=StatusEnum("importing"))

    started_on = db.Column(db.Integer)
    ended_on = db.Column(db.Integer)

    last_deferred = db.Column(db.Integer)

    @property
    def name(self):
        """
        Textual representation of name of this chroot
        """

        return self.mock_chroot.name

    @property
    def state(self):
        """
        Return text representation of status of this build chroot
        """

        if self.status is not None:
            return StatusEnum(self.status)

        return "unknown"

    @property
    def task_id(self):
        return "{}-{}".format(self.build_id, self.name)

    @property
    def import_task_id(self):
        return "{}-{}".format(self.build_id,
                              helpers.chroot_to_branch(self.name))

    @property
    def dist_git_url(self):
        if app.config["DIST_GIT_URL"]:
            return "{}/{}.git/commit/?id={}".format(
                app.config["DIST_GIT_URL"], self.build.package.dist_git_repo,
                self.git_hash)
        return None

    @property
    def import_log_url(self):
        if app.config["COPR_DIST_GIT_LOGS_URL"]:
            return "{}/{}.log".format(app.config["COPR_DIST_GIT_LOGS_URL"],
                                      self.import_task_id)
        return None

    @property
    def result_dir_url(self):
        return "/".join(
            [app.config["BACKEND_BASE_URL"], u"results", self.result_dir])

    @property
    def result_dir(self):
        # hide changes occurred after migration to dist-git
        # if build has defined dist-git, it means that new schema should be used
        # otherwise use older structure

        # old: results/valtri/ruby/fedora-rawhide-x86_64/rubygem-aws-sdk-resources-2.1.11-1.fc24/
        # new: results/asamalik/rh-perl520/epel-7-x86_64/00000187-rh-perl520/

        parts = [self.build.copr.owner_name]

        parts.extend([
            self.build.copr.name,
            self.name,
        ])
        if self.git_hash is not None and self.build.package:
            parts.append(self.build.result_dir_name)
        else:
            parts.append(self.build.src_pkg_name)

        return os.path.join(*parts)

    def __str__(self):
        return "<BuildChroot: {}>".format(self.to_dict())
Ejemplo n.º 11
0
class Build(db.Model, helpers.Serializer):
    """
    Representation of one build in one copr
    """
    __table_args__ = (db.Index('build_canceled', "canceled"), )

    id = db.Column(db.Integer, primary_key=True)
    # single url to the source rpm, should not contain " ", "\n", "\t"
    pkgs = db.Column(db.Text)
    # built packages
    built_packages = db.Column(db.Text)
    # version of the srpm package got by rpm
    pkg_version = db.Column(db.Text)
    # was this build canceled by user?
    canceled = db.Column(db.Boolean, default=False)
    # list of space separated additional repos
    repos = db.Column(db.Text)
    # the three below represent time of important events for this build
    # as returned by int(time.time())
    submitted_on = db.Column(db.Integer, nullable=False)
    # url of the build results
    results = db.Column(db.Text)
    # memory requirements for backend builder
    memory_reqs = db.Column(db.Integer, default=constants.DEFAULT_BUILD_MEMORY)
    # maximum allowed time of build, build will fail if exceeded
    timeout = db.Column(db.Integer, default=constants.DEFAULT_BUILD_TIMEOUT)
    # enable networking during a build process
    enable_net = db.Column(db.Boolean,
                           default=False,
                           server_default="0",
                           nullable=False)
    # Source of the build: type identifier
    source_type = db.Column(db.Integer,
                            default=helpers.BuildSourceEnum("unset"))
    # Source of the build: description in json, example: git link, srpm url, etc.
    source_json = db.Column(db.Text)
    # Type of failure: type identifier
    fail_type = db.Column(db.Integer, default=helpers.FailTypeEnum("unset"))
    # background builds has lesser priority than regular builds.
    is_background = db.Column(db.Boolean,
                              default=False,
                              server_default="0",
                              nullable=False)

    # relations
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    user = db.relationship("User", backref=db.backref("builds"))
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
    copr = db.relationship("Copr", backref=db.backref("builds"))
    package_id = db.Column(db.Integer, db.ForeignKey("package.id"))
    package = db.relationship("Package")

    chroots = association_proxy("build_chroots", "mock_chroot")

    @property
    def user_name(self):
        return self.user.name

    @property
    def group_name(self):
        return self.copr.group.name

    @property
    def copr_name(self):
        return self.copr.name

    @property
    def fail_type_text(self):
        return helpers.FailTypeEnum(self.fail_type)

    @property
    def is_older_results_naming_used(self):
        # we have changed result directory naming together with transition to dist-git
        # that's why we use so strange criterion
        return self.build_chroots[0].git_hash is None

    @property
    def repos_list(self):
        if self.repos is None:
            return list()
        else:
            return self.repos.split()

    @property
    def result_dir_name(self):
        # We can remove this ugly condition after migrating Copr to new machines
        # It is throw-back from era before dist-git
        if self.is_older_results_naming_used:
            return self.src_pkg_name

        return "{:08d}-{}".format(self.id, self.package.name)

    @property
    def source_json_dict(self):
        if not self.source_json:
            return {}
        return json.loads(self.source_json)

    @property
    def started_on(self):
        return self.min_started_on

    @property
    def min_started_on(self):
        mb_list = [
            chroot.started_on for chroot in self.build_chroots
            if chroot.started_on
        ]
        if len(mb_list) > 0:
            return min(mb_list)
        else:
            return None

    @property
    def ended_on(self):
        return self.max_ended_on

    @property
    def max_ended_on(self):
        if not self.build_chroots:
            return None
        if any(chroot.ended_on is None for chroot in self.build_chroots):
            return None
        return max(chroot.ended_on for chroot in self.build_chroots)

    @property
    def chroots_started_on(self):
        return {
            chroot.name: chroot.started_on
            for chroot in self.build_chroots
        }

    @property
    def chroots_ended_on(self):
        return {chroot.name: chroot.ended_on for chroot in self.build_chroots}

    @property
    def source_type_text(self):
        return helpers.BuildSourceEnum(self.source_type)

    @property
    def source_metadata(self):
        if self.source_json is None:
            return None

        try:
            return json.loads(self.source_json)
        except (TypeError, ValueError):
            return None

    @property
    def chroot_states(self):
        return map(lambda chroot: chroot.status, self.build_chroots)

    def get_chroots_by_status(self, statuses=None):
        """
        Get build chroots with states which present in `states` list
        If states == None, function returns build_chroots
        """
        chroot_states_map = dict(zip(self.build_chroots, self.chroot_states))
        if statuses is not None:
            statuses = set(statuses)
        else:
            return self.build_chroots

        return [
            chroot for chroot, status in chroot_states_map.items()
            if status in statuses
        ]

    @property
    def chroots_dict_by_name(self):
        return {b.name: b for b in self.build_chroots}

    @property
    def has_pending_chroot(self):
        # FIXME bad name
        # used when checking if the repo is initialized and results can be set
        # i think this is the only purpose - check
        return StatusEnum("pending") in self.chroot_states or \
            StatusEnum("starting") in self.chroot_states

    @property
    def has_unfinished_chroot(self):
        return StatusEnum("pending") in self.chroot_states or \
            StatusEnum("starting") in self.chroot_states or \
            StatusEnum("running") in self.chroot_states

    @property
    def has_importing_chroot(self):
        return StatusEnum("importing") in self.chroot_states

    @property
    def status(self):
        """
        Return build status according to build status of its chroots
        """
        if self.canceled:
            return StatusEnum("canceled")

        for state in [
                "running", "starting", "importing", "pending", "failed",
                "succeeded", "skipped"
        ]:
            if StatusEnum(state) in self.chroot_states:
                return StatusEnum(state)

    @property
    def state(self):
        """
        Return text representation of status of this build
        """

        if self.status is not None:
            return StatusEnum(self.status)

        return "unknown"

    @property
    def cancelable(self):
        """
        Find out if this build is cancelable.

        Build is cancelabel only when it's pending (not started)
        """

        return self.status == StatusEnum("pending") or \
            self.status == StatusEnum("importing")

    @property
    def repeatable(self):
        """
        Find out if this build is repeatable.

        Build is repeatable only if it's not pending, starting or running
        """
        return self.status not in [
            StatusEnum("pending"),
            StatusEnum("starting"),
            StatusEnum("running"),
        ]

    @property
    def finished(self):
        """
        Find out if this build is in finished state.

        Build is finished only if all its build_chroots are in finished state.
        """
        return all([(chroot.state
                     in ["succeeded", "canceled", "skipped", "failed"])
                    for chroot in self.build_chroots])

    @property
    def persistent(self):
        """
        Find out if this build is persistent.

        This property is inherited from the project.
        """
        return self.copr.persistent

    @property
    def src_pkg_name(self):
        """
        Extract source package name from source name or url
        todo: obsolete
        """
        try:
            src_rpm_name = self.pkgs.split("/")[-1]
        except:
            return None
        if src_rpm_name.endswith(".src.rpm"):
            return src_rpm_name[:-8]
        else:
            return src_rpm_name

    @property
    def package_name(self):
        try:
            return self.package.name
        except:
            return None

    def to_dict(self, options=None, with_chroot_states=False):
        result = super(Build, self).to_dict(options)
        result["src_pkg"] = result["pkgs"]
        del result["pkgs"]
        del result["copr_id"]

        result['source_type'] = helpers.BuildSourceEnum(result['source_type'])
        result["state"] = self.state

        if with_chroot_states:
            result["chroots"] = {b.name: b.state for b in self.build_chroots}

        return result
Ejemplo n.º 12
0
class Package(db.Model, helpers.Serializer, CoprSearchRelatedData):
    """
    Represents a single package in a project.
    """
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    # Source of the build: type identifier
    source_type = db.Column(db.Integer,
                            default=helpers.BuildSourceEnum("unset"))
    # Source of the build: description in json, example: git link, srpm url, etc.
    source_json = db.Column(db.Text)
    # True if the package is built automatically via webhooks
    webhook_rebuild = db.Column(db.Boolean, default=False)
    # enable networking during a build process
    enable_net = db.Column(db.Boolean,
                           default=False,
                           server_default="0",
                           nullable=False)

    # @TODO Remove me few weeks after Copr migration
    # Contain status of the Package before migration
    # Normally the `status` is not stored in `Package`. It is computed from `status` variable of `BuildChroot`,
    # but `old_status` has to be stored here, because we migrate whole `package` table, but only succeeded builds.
    # Therefore if `old_status` was in `BuildChroot` we wouldn't be able to know old state of non-succeeded packages
    # even though it would be known before migration.
    old_status = db.Column(db.Integer)

    builds = db.relationship("Build", order_by="Build.id")

    # relations
    copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
    copr = db.relationship("Copr", backref=db.backref("packages"))

    @property
    def dist_git_repo(self):
        return "{}/{}".format(self.copr.full_name, self.name)

    @property
    def source_json_dict(self):
        if not self.source_json:
            return {}
        return json.loads(self.source_json)

    @property
    def source_type_text(self):
        return helpers.BuildSourceEnum(self.source_type)

    @property
    def has_source_type_set(self):
        """
        Package's source type (and source_json) is being derived from its first build, which works except
        for "srpm_link" and "srpm_upload" cases. Consider these being equivalent to source_type being unset.
        """
        return self.source_type and self.source_type_text != "srpm_link" and self.source_type_text != "srpm_upload"

    @property
    def dist_git_url(self):
        if app.config["DIST_GIT_URL"]:
            return "{}/{}.git".format(app.config["DIST_GIT_URL"],
                                      self.dist_git_repo)
        return None

    def last_build(self, successful=False):
        for build in reversed(self.builds):
            if not successful or build.state == "succeeded":
                return build
        return None

    def to_dict(self,
                with_latest_build=False,
                with_latest_succeeded_build=False,
                with_all_builds=False):
        package_dict = super(Package, self).to_dict()
        package_dict['source_type'] = helpers.BuildSourceEnum(
            package_dict['source_type'])

        if with_latest_build:
            build = self.last_build(successful=False)
            package_dict['latest_build'] = build.to_dict(
                with_chroot_states=True) if build else None
        if with_latest_succeeded_build:
            build = self.last_build(successful=True)
            package_dict['latest_succeeded_build'] = build.to_dict(
                with_chroot_states=True) if build else None
        if with_all_builds:
            package_dict['builds'] = [
                build.to_dict(with_chroot_states=True)
                for build in reversed(self.builds)
            ]

        return package_dict

    def get_search_related_copr_id(self):
        return self.copr.id
Ejemplo n.º 13
0
class Copr(db.Model, helpers.Serializer, CoprSearchRelatedData):
    """
    Represents a single copr (private repo with builds, mock chroots, etc.).
    """

    id = db.Column(db.Integer, primary_key=True)
    # name of the copr, no fancy chars (checked by forms)
    name = db.Column(db.String(100), nullable=False)
    homepage = db.Column(db.Text)
    contact = db.Column(db.Text)
    # string containing urls of additional repos (separated by space)
    # that this copr will pull dependencies from
    repos = db.Column(db.Text)
    # time of creation as returned by int(time.time())
    created_on = db.Column(db.Integer)
    # description and instructions given by copr owner
    description = db.Column(db.Text)
    instructions = db.Column(db.Text)
    deleted = db.Column(db.Boolean, default=False)
    playground = db.Column(db.Boolean, default=False)

    # should copr run `createrepo` each time when build packages are changed
    auto_createrepo = db.Column(db.Boolean, default=True)

    # relations
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    user = db.relationship("User", backref=db.backref("coprs"))
    group_id = db.Column(db.Integer, db.ForeignKey("group.id"))
    group = db.relationship("Group", backref=db.backref("groups"))
    mock_chroots = association_proxy("copr_chroots", "mock_chroot")
    forked_from_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
    forked_from = db.relationship("Copr",
                                  remote_side=id,
                                  backref=db.backref("forks"))

    # a secret to be used for webhooks authentication
    webhook_secret = db.Column(db.String(100))

    # enable networking for the builds by default
    build_enable_net = db.Column(db.Boolean,
                                 default=True,
                                 server_default="1",
                                 nullable=False)

    unlisted_on_hp = db.Column(db.Boolean, default=False, nullable=False)

    # information for search index updating
    latest_indexed_data_update = db.Column(db.Integer)

    # builds and the project are immune against deletion
    persistent = db.Column(db.Boolean,
                           default=False,
                           nullable=False,
                           server_default="0")

    __mapper_args__ = {"order_by": created_on.desc()}

    @property
    def is_a_group_project(self):
        """
        Return True if copr belongs to a group
        """
        return self.group_id is not None

    @property
    def owner(self):
        """
        Return owner (user or group) of this copr
        """
        return self.group if self.is_a_group_project else self.user

    @property
    def owner_name(self):
        """
        Return @group.name for a copr owned by a group and user.name otherwise
        """
        return self.group.at_name if self.is_a_group_project else self.user.name

    @property
    def repos_list(self):
        """
        Return repos of this copr as a list of strings
        """
        return self.repos.split()

    @property
    def active_chroots(self):
        """
        Return list of active mock_chroots of this copr
        """

        return filter(lambda x: x.is_active, self.mock_chroots)

    @property
    def active_copr_chroots(self):
        """
        :rtype: list of CoprChroot
        """
        return [c for c in self.copr_chroots if c.is_active]

    @property
    def active_chroots_sorted(self):
        """
        Return list of active mock_chroots of this copr
        """

        return sorted(self.active_chroots, key=lambda ch: ch.name)

    @property
    def active_chroots_grouped(self):
        """
        Return list of active mock_chroots of this copr
        """

        chroots = [("{} {}".format(c.os_release, c.os_version), c.arch)
                   for c in self.active_chroots_sorted]
        output = []
        for os, chs in itertools.groupby(chroots, operator.itemgetter(0)):
            output.append((os, [ch[1] for ch in chs]))

        return output

    @property
    def build_count(self):
        """
        Return number of builds in this copr
        """

        return len(self.builds)

    @property
    def disable_createrepo(self):

        return not self.auto_createrepo

    @disable_createrepo.setter
    def disable_createrepo(self, value):

        self.auto_createrepo = not bool(value)

    @property
    def modified_chroots(self):
        """
        Return list of chroots which has been modified
        """
        modified_chroots = []
        for chroot in self.copr_chroots:
            if chroot.buildroot_pkgs and chroot.is_active:
                modified_chroots.append(chroot)
        return modified_chroots

    def is_release_arch_modified(self, name_release, arch):
        if "{}-{}".format(name_release, arch) in \
                [chroot.name for chroot in self.modified_chroots]:
            return True
        return False

    @property
    def full_name(self):
        return "{}/{}".format(self.owner_name, self.name)

    @property
    def repo_name(self):
        return "{}-{}".format(self.owner_name, self.name)

    @property
    def repo_url(self):
        return "/".join(
            [app.config["BACKEND_BASE_URL"], u"results", self.full_name])

    @property
    def modules_url(self):
        return "/".join([self.repo_url, "modules"])

    @property
    def repo_id(self):
        if self.is_a_group_project:
            return "group_{}-{}".format(self.group.name, self.name)
        else:
            return "{}-{}".format(self.user.name, self.name)

    def to_dict(self, private=False, show_builds=True, show_chroots=True):
        result = {}
        for key in ["id", "name", "description", "instructions"]:
            result[key] = str(copy.copy(getattr(self, key)))
        result["owner"] = self.owner_name
        return result

    @property
    def still_forking(self):
        return bool(
            Action.query.filter(
                Action.result == helpers.BackendResultEnum("waiting")).filter(
                    Action.action_type == helpers.ActionTypeEnum("fork")).
            filter(Action.new_value == self.full_name).all())

    def get_search_related_copr_id(self):
        return self.id
Ejemplo n.º 14
0
class Copr(db.Model, helpers.Serializer):
    """
    Represents a single copr (private repo with builds, mock chroots, etc.).
    """

    id = db.Column(db.Integer, primary_key=True)
    # name of the copr, no fancy chars (checked by forms)
    name = db.Column(db.String(100), nullable=False)
    homepage = db.Column(db.Text)
    contact = db.Column(db.Text)
    # string containing urls of additional repos (separated by space)
    # that this copr will pull dependencies from
    repos = db.Column(db.Text)
    # time of creation as returned by int(time.time())
    created_on = db.Column(db.Integer)
    # description and instructions given by copr owner
    description = db.Column(db.Text)
    instructions = db.Column(db.Text)
    deleted = db.Column(db.Boolean, default=False)
    playground = db.Column(db.Boolean, default=False)

    # should copr run `createrepo` each time when build packages are changed
    auto_createrepo = db.Column(db.Boolean, default=True)

    # relations
    owner_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    owner = db.relationship("User", backref=db.backref("coprs"))
    group_id = db.Column(db.Integer, db.ForeignKey("group.id"))
    group = db.relationship("Group", backref=db.backref("groups"))
    mock_chroots = association_proxy("copr_chroots", "mock_chroot")

    # a secret to be used for webhooks authentication
    webhook_secret = db.Column(db.String(100))

    # enable networking for the builds by default
    build_enable_net = db.Column(db.Boolean,
                                 default=True,
                                 server_default="1",
                                 nullable=False)

    __mapper_args__ = {"order_by": created_on.desc()}

    @property
    def is_a_group_project(self):
        return self.group_id is not None

    @property
    def owner_name(self):
        return self.owner.name

    @property
    def group_name(self):
        return self.group.name

    @property
    def repos_list(self):
        """
        Return repos of this copr as a list of strings
        """
        return self.repos.split()

    @property
    def active_chroots(self):
        """
        Return list of active mock_chroots of this copr
        """

        return filter(lambda x: x.is_active, self.mock_chroots)

    @property
    def active_copr_chroots(self):
        """
        :rtype: list of CoprChroot
        """
        return [c for c in self.copr_chroots if c.is_active]

    @property
    def active_chroots_sorted(self):
        """
        Return list of active mock_chroots of this copr
        """

        return sorted(self.active_chroots, key=lambda ch: ch.name)

    @property
    def active_chroots_grouped(self):
        """
        Return list of active mock_chroots of this copr
        """

        chroots = [("{} {}".format(c.os_release, c.os_version), c.arch)
                   for c in self.active_chroots_sorted]
        output = []
        for os, chs in itertools.groupby(chroots, operator.itemgetter(0)):
            output.append((os, [ch[1] for ch in chs]))

        return output

    @property
    def build_count(self):
        """
        Return number of builds in this copr
        """

        return len(self.builds)

    @property
    def disable_createrepo(self):

        return not self.auto_createrepo

    @disable_createrepo.setter
    def disable_createrepo(self, value):

        self.auto_createrepo = not bool(value)

    @property
    def modified_chroots(self):
        """
        Return list of chroots which has been modified
        """
        modified_chroots = []
        for chroot in self.copr_chroots:
            if chroot.buildroot_pkgs and chroot.is_active:
                modified_chroots.append(chroot)
        return modified_chroots

    def is_release_arch_modified(self, name_release, arch):
        if "{}-{}".format(name_release, arch) in \
                [chroot.name for chroot in self.modified_chroots]:
            return True
        return False

    @property
    def full_name(self):
        if self.is_a_group_project:
            return "@{}/{}".format(self.group.name, self.name)
        else:
            return "{}/{}".format(self.owner.username, self.name)

    @property
    def repo_name(self):
        if self.is_a_group_project:
            return "@{}-{}".format(self.group.name, self.name)
        else:
            return "{}-{}".format(self.owner.username, self.name)

    @property
    def repo_id(self):
        if self.is_a_group_project:
            return "group_{}-{}".format(self.group.name, self.name)
        else:
            return "{}-{}".format(self.owner.username, self.name)

    def to_dict(self, private=False, show_builds=True, show_chroots=True):
        result = {}
        for key in ["id", "name", "description", "instructions"]:
            result[key] = str(copy.copy(getattr(self, key)))
        result["owner"] = self.owner.name
        return result