import configparser
import contextlib
import datetime
+import functools
import io
import logging
import os.path
return await self.db.fetch_one(stmt)
- async def get_total_builds(self):
+ @functools.cached_property
+ def builds(self):
"""
- Return the total number of builds in this repository
+ Returns a CTE with all builds in this repository
"""
- stmt = (
+ return (
sqlalchemy
.select(
- sqlalchemy.func.count().label("total_builds"),
+ builds.Build,
+ )
+ .select_from(
+ RepoBuild,
)
- .select_from(RepoBuild)
.join(
builds.Build,
builds.Build.id == RepoBuild.build_id,
)
.where(
+ # Builds should not be deleted
builds.Build.deleted_at == None,
+ # Builds must be in this repository
RepoBuild.repo == self,
RepoBuild.removed_at == None,
)
+ .cte("_builds")
+ )
+
+ @functools.cached_property
+ def packages(self):
+ """
+ Returns a CTE with all packages in this repository
+ """
+ # Source packages
+ source_packages = (
+ sqlalchemy
+ .select(
+ packages.Package,
+ )
+ .select_from(
+ self.builds,
+ )
+ .join(
+ packages.Package,
+ packages.Package.id == self.builds.c.pkg_id,
+ )
+ .where(
+ packages.Package.deleted_at == None,
+ )
+ )
+
+ # Binary Packages
+ binary_packages = (
+ sqlalchemy
+ .select(
+ packages.Package,
+ )
+ .select_from(
+ self.builds,
+ )
+ .join(
+ jobs.Job,
+ jobs.Job.build_id == self.builds.c.id,
+ )
+ .join(
+ jobs.JobPackage,
+ jobs.JobPackage.c.job_id == jobs.Job.id,
+ )
+ .join(
+ packages.Package,
+ packages.Package.id == jobs.JobPackage.c.pkg_id,
+ )
+ .where(
+ packages.Package.deleted_at == None,
+ jobs.Job.deleted_at == None,
+ )
+ )
+
+ return sqlalchemy.union_all(source_packages, binary_packages).cte("_packages")
+
+ async def get_total_builds(self):
+ """
+ Return the total number of builds in this repository
+ """
+ stmt = (
+ sqlalchemy
+ .select(
+ sqlalchemy.func.count().label("total_builds"),
+ )
+ .select_from(self.builds)
)
return await self.db.select_one(stmt, "total_builds")
- async def get_packages(self, arch):
- if arch == "src":
- packages = await self.backend.packages._get_packages("""
- SELECT
- packages.*
- FROM
- repository_builds
- LEFT JOIN
- builds ON repository_builds.build_id = builds.id
- LEFT JOIN
- packages ON builds.pkg_id = packages.id
- WHERE
- builds.deleted_at IS NULL
- AND
- packages.deleted_at IS NULL
- AND
- repository_builds.repo_id = %s
- AND
- repository_builds.removed_at IS NULL
- """, self.id,
+ def get_packages(self, arch):
+ """
+ Returns an iterator over all packages that match the given arch
+ """
+ arches = [arch]
+
+ # Include noarch packages unless we are looking for source packages only
+ if not arch == "src":
+ arches.append("noarch")
+
+ # Alias the CTE
+ all_packages = sqlalchemy.orm.aliased(packages.Package, self.packages)
+
+ # Fetch all packages that match the architecture
+ stmt = (
+ sqlalchemy
+ .select(
+ all_packages,
)
- else:
- packages = await self.backend.packages._get_packages("""
- SELECT
- packages.*
- FROM
- repository_builds
- LEFT JOIN
- builds ON repository_builds.build_id = builds.id
- LEFT JOIN
- jobs ON builds.id = jobs.build_id
- LEFT JOIN
- job_packages ON jobs.id = job_packages.job_id
- LEFT JOIN
- packages ON job_packages.pkg_id = packages.id
- WHERE
- builds.deleted_at IS NULL
- AND
- jobs.deleted_at IS NULL
- AND
- packages.deleted_at IS NULL
- AND
- repository_builds.repo_id = %s
- AND
- repository_builds.removed_at IS NULL
- AND
- packages.arch = ANY(%s)
- """,
- self.id, [arch, "noarch"],
+ .where(
+ all_packages.arch.in_(arches),
)
+ )
- return list(packages)
+ return self.db.fetch(stmt)
@property
async def pending_jobs(self):
# Stats
- @lazy_property
- async def size(self):
- res = await self.db.query("""
- SELECT
- packages.arch AS arch,
- SUM(packages.filesize) AS size
- FROM
- repository_builds
- LEFT JOIN
- builds ON repository_builds.build_id = builds.id
- LEFT JOIN
- jobs ON builds.id = jobs.build_id
- LEFT JOIN
- job_packages ON jobs.id = job_packages.job_id
- LEFT JOIN
- packages ON job_packages.pkg_id = packages.id
- WHERE
- builds.deleted_at IS NULL
- AND
- jobs.deleted_at IS NULL
- AND
- packages.deleted_at IS NULL
- AND
- repository_builds.repo_id = %s
- AND
- repository_builds.removed_at IS NULL
- GROUP BY
- packages.arch
- """, self.id,
- )
-
- return { row.arch : row.size for row in res if row.arch in self.distro.arches }
-
async def get_total_size(self):
"""
Returns the total size of the repository
"""
- source_packages = (
- sqlalchemy
- .select(
- packages.Package.filesize.label("size")
- )
- .select_from(RepoBuild)
- .join(
- builds.Build,
- builds.Build.id == RepoBuild.build_id,
- )
- .join(
- packages.Package,
- packages.Package.id == builds.Build.pkg_id,
- )
- .where(
- packages.Package.deleted_at == None,
- builds.Build.deleted_at == None,
- RepoBuild.removed_at == None,
- RepoBuild.repo == self,
- )
- )
-
- binary_packages = (
- sqlalchemy
- .select(
- packages.Package.filesize.label("size")
- )
- .select_from(RepoBuild)
- .join(
- builds.Build,
- builds.Build.id == RepoBuild.build_id,
- )
- .join(
- jobs.Job,
- jobs.Job.build_id == builds.Build.id,
- )
- .join(
- packages.Package,
- packages.Package.id == builds.Build.pkg_id,
- )
- .where(
- packages.Package.deleted_at == None,
- builds.Build.deleted_at == None,
- RepoBuild.removed_at == None,
- RepoBuild.repo == self,
- )
- )
-
- all_packages = (
- sqlalchemy
- .union_all(
- source_packages,
- binary_packages,
- )
- .cte("all_packages")
- )
-
stmt = (
sqlalchemy
.select(
sqlalchemy.func.sum(
- all_packages.c.size,
+ self.packages.c.size,
).label("total_size"),
)
.select_from(
- all_packages,
+ self.packages,
)
)
- return await self.db.select_one(stmt, "total_size")
+ return await self.db.select_one(stmt, "total_size") or 0
# Pakfire
# Make filelist (if they exist)
files = [
- p.path for p in packages \
+ p.path async for p in packages \
if p.path and await self.backend.exists(p.path)
]