src/buildservice/misc.py \
src/buildservice/packages.py \
src/buildservice/ratelimiter.py \
+ src/buildservice/releases.py \
src/buildservice/releasemonitoring.py \
src/buildservice/repository.py \
src/buildservice/sessions.py \
-#!/usr/bin/python
+###############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2025 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
-import datetime
import logging
import sqlalchemy
from sqlalchemy import Column, Computed, ForeignKey
-from sqlalchemy import ARRAY, Boolean, DateTime, Integer, Text
+from sqlalchemy import ARRAY, DateTime, Integer, Text
from . import base
from . import database
from . import misc
+from . import releases
from . import repository
from . import sources
-from .decorators import *
# Setup logging
log = logging.getLogger("pbs.distros")
-class Release(database.Base, database.BackendMixin, database.SoftDeleteMixin):
- __tablename__ = "releases"
-
- def __str__(self):
- return self.name
-
- def has_perm(self, *args, **kwargs):
- # Inherit all permissions from the distribution
- return self.distro.has_perm(*args, **kwargs)
-
- # ID
-
- id = Column(Integer, primary_key=True)
-
- # Distro
-
- distro_id = Column(Integer, ForeignKey("distributions.id"), nullable=False)
-
- distro = sqlalchemy.orm.relationship("Distro", back_populates="releases", lazy="selectin")
-
- # Name
-
- name = Column(Text, nullable=False)
-
- # Slug
-
- slug = Column(Text, unique=True, nullable=False)
-
- # Created At
-
- created_at = Column(
- DateTime(timezone=False), nullable=False, server_default=sqlalchemy.func.current_timestamp(),
- )
-
- # Created By ID
-
- created_by_id = Column(Integer, ForeignKey("users.id"), nullable=False)
-
- # Created By
-
- created_by = sqlalchemy.orm.relationship(
- "User", foreign_keys=[created_by_id], lazy="selectin",
- )
-
- # Deleted By ID
-
- deleted_by_id = Column(Integer, ForeignKey("users.id"))
-
- # Deleted By
-
- deleted_by = sqlalchemy.orm.relationship(
- "User", foreign_keys=[deleted_by_id], lazy="selectin",
- )
-
- # Stable?
-
- stable = Column(Boolean, nullable=False)
-
- # Announcement
-
- announcement = Column(Text, nullable=False)
-
- # URL
-
- @property
- def url(self):
- return "/distros/%s/releases/%s" % (self.distro.slug, self.slug)
-
- # Publish
-
- def is_published(self):
- if self.published_at and self.published_at <= datetime.datetime.utcnow():
- return True
-
- return False
-
- # Published At
-
- published_at = Column(DateTime)
-
- async def publish(self, when=None):
- """
- Called to publish the release
- """
- self.published_at = when or sqlalchemy.func.current_timestamp()
-
- # XXX TODO
-
- # Delete
-
- async def delete(self, user=None):
- """
- Deletes this release
- """
- self._set_attribute_now("deleted_at")
- if user:
- self._set_attribute("deleted_by", user)
-
- # XXX TODO delete images
-
- # Images
-
- #images = sqlalchemy.orm.relationship("Image", back_populates="release")
-
- @lazy_property
- def XXXimages(self):
- images = self.backend.distros.releases.images._get_images("""
- SELECT
- *
- FROM
- release_images
- WHERE
- release_id = %s
- AND
- deleted_at IS NULL
- """, self.id,
-
- # Populate cache
- release=self,
- )
-
- # Return grouped by architecture
- return misc.group(images, lambda image: image.arch)
-
-
class Distributions(base.Object):
def __aiter__(self):
stmt = (
stmt = (
sqlalchemy
.select(
- Release,
+ releases.Release,
)
.where(
- Release.deleted_at == None,
- Release.distro == self,
- Release.published_at <= sqlalchemy.func.current_timestamp(),
+ releases.Release.deleted_at == None,
+ releases.Release.distro == self,
+ releases.Release.published_at <= sqlalchemy.func.current_timestamp(),
)
.order_by(
- Release.published_at.desc(),
+ releases.Release.published_at.desc(),
)
.limit(1)
)
# Create a new Release
release = await self.db.insert(
- Release,
+ releases.Release,
distro = self,
name = name,
slug = slug,
from . import distribution as distros
from . import jobs
from . import mirrors
+from . import releases
from . import releasemonitoring as monitorings
from . import repository as repos
TYPE("release-created"),
# Timestamp
- TIMESTAMP(distros.Release.created_at),
+ TIMESTAMP(releases.Release.created_at),
# Priority
PRIORITY(1),
# Release ID
- distros.Release.id.label("release_id"),
+ releases.Release.id.label("release_id"),
# By User ID
- distros.Release.created_by_id.label("by_user_id"),
+ releases.Release.created_by_id.label("by_user_id"),
)
- .select_from(distros.Release)
+ .select_from(releases.Release)
))
# Releases Deleted
TYPE("release-deleted"),
# Timestamp
- TIMESTAMP(distros.Release.deleted_at),
+ TIMESTAMP(releases.Release.deleted_at),
# Priority
PRIORITY(1),
# Release ID
- distros.Release.id.label("release_id"),
+ releases.Release.id.label("release_id"),
# By User ID
- distros.Release.deleted_by_id.label("by_user_id"),
+ releases.Release.deleted_by_id.label("by_user_id"),
)
- .select_from(distros.Release)
+ .select_from(releases.Release)
.where(
- distros.Release.deleted_at != None,
+ releases.Release.deleted_at != None,
)
))
TYPE("release-published"),
# Timestamp
- TIMESTAMP(distros.Release.published_at),
+ TIMESTAMP(releases.Release.published_at),
# Priority
PRIORITY(5),
# Release ID
- distros.Release.id.label("release_id"),
+ releases.Release.id.label("release_id"),
)
- .select_from(distros.Release)
+ .select_from(releases.Release)
.where(
- distros.Release.published_at != None,
- distros.Release.published_at <= sqlalchemy.func.current_timestamp(),
+ releases.Release.published_at != None,
+ releases.Release.published_at <= sqlalchemy.func.current_timestamp(),
)
))
--- /dev/null
+###############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2025 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+import datetime
+import logging
+
+import sqlalchemy
+from sqlalchemy import Column, Computed, ForeignKey
+from sqlalchemy import ARRAY, Boolean, DateTime, Integer, Text
+
+from . import database
+
+# Setup logging
+log = logging.getLogger("pbs.releases")
+
+class Release(database.Base, database.BackendMixin, database.SoftDeleteMixin):
+ __tablename__ = "releases"
+
+ def __str__(self):
+ return self.name
+
+ def has_perm(self, *args, **kwargs):
+ # Inherit all permissions from the distribution
+ return self.distro.has_perm(*args, **kwargs)
+
+ # ID
+
+ id = Column(Integer, primary_key=True)
+
+ # Distro ID
+
+ distro_id = Column(Integer, ForeignKey("distributions.id"), nullable=False)
+
+ # Distro
+
+ distro = sqlalchemy.orm.relationship("Distro", back_populates="releases", lazy="selectin")
+
+ # Name
+
+ name = Column(Text, nullable=False)
+
+ # Slug
+
+ slug = Column(Text, unique=True, nullable=False)
+
+ # Created At
+
+ created_at = Column(DateTime(timezone=False), nullable=False,
+ server_default=sqlalchemy.func.current_timestamp())
+
+ # Created By ID
+
+ created_by_id = Column(Integer, ForeignKey("users.id"), nullable=False)
+
+ # Created By
+
+ created_by = sqlalchemy.orm.relationship(
+ "User", foreign_keys=[created_by_id], lazy="selectin",
+ )
+
+ # Deleted By ID
+
+ deleted_by_id = Column(Integer, ForeignKey("users.id"))
+
+ # Deleted By
+
+ deleted_by = sqlalchemy.orm.relationship(
+ "User", foreign_keys=[deleted_by_id], lazy="selectin",
+ )
+
+ # Stable?
+
+ stable = Column(Boolean, nullable=False)
+
+ # Announcement
+
+ announcement = Column(Text, nullable=False)
+
+ # URL
+
+ @property
+ def url(self):
+ return "/distros/%s/releases/%s" % (self.distro.slug, self.slug)
+
+ # Publish
+
+ def is_published(self):
+ if self.published_at and self.published_at <= datetime.datetime.utcnow():
+ return True
+
+ return False
+
+ # Published At
+
+ published_at = Column(DateTime)
+
+ async def publish(self, when=None):
+ """
+ Called to publish the release
+ """
+ self.published_at = when or sqlalchemy.func.current_timestamp()
+
+ # XXX TODO
+
+ # Delete
+
+ async def delete(self, user=None):
+ """
+ Deletes this release
+ """
+ self._set_attribute_now("deleted_at")
+ if user:
+ self._set_attribute("deleted_by", user)
+
+ # XXX TODO delete images
+
+ # Images
+
+ #images = sqlalchemy.orm.relationship("Image", back_populates="release")
+
+ @property
+ def XXXimages(self):
+ images = self.backend.distros.releases.images._get_images("""
+ SELECT
+ *
+ FROM
+ release_images
+ WHERE
+ release_id = %s
+ AND
+ deleted_at IS NULL
+ """, self.id,
+
+ # Populate cache
+ release=self,
+ )
+
+ # Return grouped by architecture
+ return misc.group(images, lambda image: image.arch)