| |
@@ -23,8 +23,14 @@
|
| |
from coprs import db
|
| |
from coprs import models
|
| |
from coprs import helpers
|
| |
- from coprs.exceptions import MalformedArgumentException, ActionInProgressException, InsufficientRightsException, \
|
| |
- UnrepeatableBuildException, RequestCannotBeExecuted, DuplicateException
|
| |
+ from coprs.exceptions import (
|
| |
+ ActionInProgressException,
|
| |
+ ConflictingRequest,
|
| |
+ DuplicateException,
|
| |
+ InsufficientRightsException,
|
| |
+ MalformedArgumentException,
|
| |
+ UnrepeatableBuildException,
|
| |
+ )
|
| |
|
| |
from coprs.logic import coprs_logic
|
| |
from coprs.logic import users_logic
|
| |
@@ -276,22 +282,31 @@
|
| |
|
| |
@classmethod
|
| |
def get_pending_build_tasks(cls, background=None):
|
| |
- query = (models.BuildChroot.query
|
| |
- .outerjoin(models.Build)
|
| |
- .outerjoin(models.CoprDir)
|
| |
- .outerjoin(models.Package, models.Package.id == models.Build.package_id)
|
| |
- .options(joinedload('build').joinedload('copr_dir'),
|
| |
- joinedload('build').joinedload('package'))
|
| |
- .filter(models.Build.canceled == false())
|
| |
- .filter(or_(
|
| |
- models.BuildChroot.status == StatusEnum("pending"),
|
| |
- and_(
|
| |
- models.BuildChroot.status == StatusEnum("running"),
|
| |
- models.BuildChroot.started_on < int(time.time() - 1.1 * app.config["MAX_BUILD_TIMEOUT"]),
|
| |
- models.BuildChroot.ended_on.is_(None)
|
| |
- )
|
| |
- ))
|
| |
- .order_by(models.Build.is_background.asc(), models.Build.id.asc()))
|
| |
+ """
|
| |
+ Get list of BuildChroot objects that are to be (re)processed.
|
| |
+ """
|
| |
+
|
| |
+ # Also add too-long running tasks, those are probably staled.
|
| |
+ # TODO: Is this still needed?
|
| |
+ restart_older = int(time.time() - 1.1 * app.config["MAX_BUILD_TIMEOUT"])
|
| |
+
|
| |
+ query = (
|
| |
+ models.BuildChroot.query
|
| |
+ .join(models.Build)
|
| |
+ .join(models.CoprDir)
|
| |
+ # TODO: BuildChroot objects should be self-standing. The thing is
|
| |
+ # that this is racy -- Package reference provides some build
|
| |
+ # configuration which can be changed in the middle of the
|
| |
+ # BuildChroot processing.
|
| |
+ .join(models.Package, models.Package.id == models.Build.package_id)
|
| |
+ .options(joinedload('build').joinedload('copr_dir'),
|
| |
+ joinedload('build').joinedload('package'))
|
| |
+ .filter(models.Build.canceled == false())
|
| |
+ .filter(or_(models.BuildChroot.status == StatusEnum("pending"),
|
| |
+ and_(models.BuildChroot.status == StatusEnum("running"),
|
| |
+ models.BuildChroot.started_on < restart_older,
|
| |
+ models.BuildChroot.ended_on.is_(None))))
|
| |
+ .order_by(models.Build.is_background.asc(), models.Build.id.asc()))
|
| |
if background is not None:
|
| |
query = query.filter(models.Build.is_background == (true() if background else false()))
|
| |
return query
|
| |
@@ -629,7 +644,7 @@
|
| |
git_hash = None
|
| |
if git_hashes:
|
| |
git_hash = git_hashes.get(chroot.name)
|
| |
- buildchroot = models.BuildChroot(
|
| |
+ buildchroot = BuildChrootsLogic.new(
|
| |
build=build,
|
| |
status=chroot_status,
|
| |
mock_chroot=chroot,
|
| |
@@ -674,7 +689,7 @@
|
| |
|
| |
status = StatusEnum("waiting")
|
| |
for chroot in package.chroots:
|
| |
- buildchroot = models.BuildChroot(
|
| |
+ buildchroot = BuildChrootsLogic.new(
|
| |
build=build,
|
| |
status=status,
|
| |
mock_chroot=chroot,
|
| |
@@ -777,7 +792,7 @@
|
| |
# create the BuildChroots from Package setting, if not
|
| |
# already set explicitly for concrete build
|
| |
for chroot in build.package.chroots:
|
| |
- buildchroot = models.BuildChroot(
|
| |
+ buildchroot = BuildChrootsLogic.new(
|
| |
build=build,
|
| |
status=chroot_status,
|
| |
mock_chroot=chroot,
|
| |
@@ -903,7 +918,7 @@
|
| |
err_msg = "Cannot cancel build {} in state 'starting'".format(build.id)
|
| |
else:
|
| |
err_msg = "Cannot cancel build {}".format(build.id)
|
| |
- raise RequestCannotBeExecuted(err_msg)
|
| |
+ raise ConflictingRequest(err_msg)
|
| |
|
| |
if build.status == StatusEnum("running"): # otherwise the build is just in frontend
|
| |
ActionsLogic.send_cancel_build(build)
|
| |
@@ -1069,6 +1084,25 @@
|
| |
|
| |
class BuildChrootsLogic(object):
|
| |
@classmethod
|
| |
+ def new(cls, build, mock_chroot, **kwargs):
|
| |
+ """
|
| |
+ Create new instance of BuildChroot
|
| |
+ (which is not assigned to any session)
|
| |
+
|
| |
+ Each freshly created instance of BuildChroot has to be assigned to
|
| |
+ pre-existing Build and MockChroot, hence the mandatory arguments.
|
| |
+ """
|
| |
+ copr_chroot = coprs_logic.CoprChrootsLogic.get_by_mock_chroot_id(
|
| |
+ build.copr, mock_chroot.id
|
| |
+ ).one()
|
| |
+ return models.BuildChroot(
|
| |
+ mock_chroot=mock_chroot,
|
| |
+ copr_chroot=copr_chroot,
|
| |
+ build=build,
|
| |
+ **kwargs,
|
| |
+ )
|
| |
+
|
| |
+ @classmethod
|
| |
def get_by_build_id_and_name(cls, build_id, name):
|
| |
mc = MockChrootsLogic.get_from_name(name).one()
|
| |
|
| |
@@ -1110,6 +1144,27 @@
|
| |
def filter_by_group_name(cls, query, group_name):
|
| |
return query.filter(models.Group.name == group_name)
|
| |
|
| |
+ @classmethod
|
| |
+ def filter_by_copr_and_mock_chroot(cls, query, copr, mock_chroot):
|
| |
+ """
|
| |
+ Filter BuildChroot query so it returns only instances related to
|
| |
+ particular Copr and MockChroot.
|
| |
+ """
|
| |
+ return (
|
| |
+ query.join(models.BuildChroot.build)
|
| |
+ .filter(models.BuildChroot.mock_chroot_id == mock_chroot.id)
|
| |
+ .filter(models.Build.copr_id == copr.id)
|
| |
+ )
|
| |
+
|
| |
+ @classmethod
|
| |
+ def by_copr_and_mock_chroot(cls, copr, mock_chroot):
|
| |
+ """
|
| |
+ Given Copr and MockChroot instances, return query object which provides
|
| |
+ a list of related BuildChroots.
|
| |
+ """
|
| |
+ return cls.filter_by_copr_and_mock_chroot(BuildChroot.query, copr,
|
| |
+ mock_chroot)
|
| |
+
|
| |
|
| |
class BuildsMonitorLogic(object):
|
| |
@classmethod
|
| |
Do we want to start type-hinting our new python3-only functions now? I think it is not a bad idea.