Package coprs :: Package logic :: Module builds_logic
[hide private]
[frames] | no frames]

Source Code for Module coprs.logic.builds_logic

  1  import time 
  2  from sqlalchemy import or_ 
  3  from sqlalchemy import and_ 
  4   
  5  from coprs import db 
  6  from coprs import exceptions 
  7  from coprs import models 
  8  from coprs import helpers 
  9  from coprs import signals 
 10   
 11  from coprs.logic import coprs_logic 
 12  from coprs.logic import users_logic 
13 14 15 -class BuildsLogic(object):
16 17 @classmethod
18 - def get(cls, build_id):
19 return models.Build.query.filter(models.Build.id == build_id)
20 21 @classmethod
22 - def get_build_tasks(cls, status):
23 return models.BuildChroot.query.filter(models.BuildChroot.status == status)\ 24 .order_by(models.BuildChroot.build_id.desc())
25 26 @classmethod
27 - def get_recent_tasks(cls, user=None, limit=None):
28 if not limit: 29 limit = 100 30 31 query = models.Build.query \ 32 .filter(models.Build.ended_on != None) 33 34 if user is not None: 35 query = query.filter(models.Build.user_id == user.id) 36 37 query = query \ 38 .order_by(models.Build.id.desc()) \ 39 .limit(limit) 40 41 return query
42 43 44 @classmethod
45 - def get_build_task_queue(cls):
46 """ 47 Returns BuildChroots which are - waiting to be built or 48 - older than 2 hours and unfinished 49 """ 50 query = models.BuildChroot.query.join(models.Build).filter(or_( 51 models.BuildChroot.status == helpers.StatusEnum("pending"), 52 models.BuildChroot.status == helpers.StatusEnum("starting"), 53 and_( 54 models.BuildChroot.status == helpers.StatusEnum("running"), 55 models.Build.started_on < int(time.time() - 7200), 56 models.Build.ended_on == None 57 ) 58 )) 59 query = query.order_by(models.BuildChroot.build_id.asc()) 60 return query
61 62 @classmethod
63 - def get_multiple(cls, user, **kwargs):
64 copr = kwargs.get("copr", None) 65 username = kwargs.get("username", None) 66 coprname = kwargs.get("coprname", None) 67 68 query = models.Build.query.order_by(models.Build.id.desc()) 69 70 # if we get copr, query by its id 71 if copr: 72 query = query.filter(models.Build.copr == copr) 73 elif username and coprname: 74 query = (query.join(models.Build.copr) 75 .options(db.contains_eager(models.Build.copr)) 76 .join(models.Copr.owner) 77 .filter(models.Copr.name == coprname) 78 .filter(models.User.openid_name == 79 models.User.openidize_name(username)) 80 .order_by(models.Build.submitted_on.desc())) 81 else: 82 raise exceptions.ArgumentMissingException( 83 "Must pass either copr or both coprname and username") 84 85 return query
86 87 @classmethod
88 - def get_waiting(cls):
89 """ 90 Return builds that aren't both started and finished 91 (if build start submission fails, we still want to mark 92 the build as non-waiting, if it ended) 93 this has very different goal then get_multiple, so implement it alone 94 """ 95 96 query = (models.Build.query.join(models.Build.copr) 97 .join(models.User) 98 .options(db.contains_eager(models.Build.copr)) 99 .options(db.contains_eager("copr.owner")) 100 .filter((models.Build.started_on == None) 101 | (models.Build.started_on < int(time.time() - 7200))) 102 .filter(models.Build.ended_on == None) 103 .filter(models.Build.canceled != True) 104 .order_by(models.Build.submitted_on.asc())) 105 return query
106 107 @classmethod
108 - def get_by_ids(cls, ids):
109 return models.Build.query.filter(models.Build.id.in_(ids))
110 111 @classmethod
112 - def get_by_id(cls, build_id):
113 return models.Build.query.get(build_id)
114 115 @classmethod
116 - def add(cls, user, pkgs, copr, 117 repos=None, memory_reqs=None, timeout=None, chroots=None):
118 if chroots is None: 119 chroots = [] 120 coprs_logic.CoprsLogic.raise_if_unfinished_blocking_action( 121 user, copr, 122 "Can't build while there is an operation in progress: {action}") 123 users_logic.UsersLogic.raise_if_cant_build_in_copr( 124 user, copr, 125 "You don't have permissions to build in this copr.") 126 127 if not repos: 128 repos = copr.repos 129 130 build = models.Build( 131 user=user, 132 pkgs=pkgs, 133 copr=copr, 134 repos=repos, 135 submitted_on=int(time.time())) 136 137 if memory_reqs: 138 build.memory_reqs = memory_reqs 139 140 if timeout: 141 build.timeout = timeout 142 143 db.session.add(build) 144 145 # add BuildChroot object for each active (or selected) chroot 146 # this copr is assigned to 147 if not chroots: 148 chroots = copr.active_chroots 149 150 for chroot in chroots: 151 buildchroot = models.BuildChroot( 152 build=build, 153 mock_chroot=chroot) 154 155 db.session.add(buildchroot) 156 157 return build
158 159 @classmethod
160 - def update_state_from_dict(cls, build, upd_dict):
161 if "chroot" in upd_dict: 162 # update respective chroot status 163 for build_chroot in build.build_chroots: 164 if build_chroot.name == upd_dict["chroot"]: 165 if "status" in upd_dict: 166 build_chroot.status = upd_dict["status"] 167 168 db.session.add(build_chroot) 169 170 for attr in ["results", "started_on", "ended_on", "pkg_version", "built_packages"]: 171 value = upd_dict.get(attr, None) 172 if value: 173 # only update started_on once 174 if attr == "started_on" and build.started_on: 175 continue 176 177 # update ended_on when everything really ends 178 # update results when there is repo initialized for every chroot 179 if (attr == "ended_on" and build.has_unfinished_chroot) or \ 180 (attr == "results" and build.has_pending_chroot): 181 continue 182 183 if attr == "ended_on": 184 signals.build_finished.send(cls, build=build) 185 186 setattr(build, attr, value) 187 188 db.session.add(build)
189 190 @classmethod
191 - def cancel_build(cls, user, build):
192 if not user.can_build_in(build.copr): 193 raise exceptions.InsufficientRightsException( 194 "You are not allowed to cancel this build.") 195 build.canceled = True 196 for chroot in build.build_chroots: 197 chroot.status = 2 #canceled
198 199 @classmethod
200 - def delete_build(cls, user, build):
201 if not user.can_build_in(build.copr): 202 raise exceptions.InsufficientRightsException( 203 "You are not allowed to delete this build.") 204 205 if not build.deletable: 206 raise exceptions.ActionInProgressException( 207 "You can not delete build which is not finished.", 208 "Unfinished build") 209 210 # Only failed (and finished), succeeded, skipped and cancelled get here. 211 if build.state != "cancelled": #has nothing in backend to delete 212 object_type = "build-{0}".format(build.state) 213 action = models.Action(action_type=helpers.ActionTypeEnum("delete"), 214 object_type=object_type, 215 object_id=build.id, 216 old_value="{0}/{1}".format(build.copr.owner.name, 217 build.copr.name), 218 data=build.pkgs, 219 created_on=int(time.time())) 220 db.session.add(action) 221 222 for build_chroot in build.build_chroots: 223 db.session.delete(build_chroot) 224 db.session.delete(build)
225 226 @classmethod
227 - def last_modified(cls, copr):
228 """ Get build datetime (as epoch) of last successfull build 229 230 :arg copr: object of copr 231 """ 232 builds = cls.get_multiple(None, copr=copr) 233 234 last_build = (builds 235 .join(models.BuildChroot) 236 .filter((models.BuildChroot.status == helpers.StatusEnum("succeeded")) 237 | (models.BuildChroot.status == helpers.StatusEnum("skipped"))) 238 .filter(models.Build.ended_on != None) 239 .order_by(models.Build.ended_on.desc()) 240 ).first() 241 if last_build: 242 return last_build.ended_on 243 else: 244 return None
245