Package coprs :: Package views :: Package coprs_ns :: Module coprs_builds
[hide private]
[frames] | no frames]

Source Code for Module coprs.views.coprs_ns.coprs_builds

  1  import flask 
  2  from flask import request, render_template, stream_with_context 
  3   
  4  from copr_common.enums import StatusEnum 
  5  from coprs import app 
  6  from coprs import db 
  7  from coprs import forms 
  8  from coprs import helpers 
  9   
 10  from coprs.logic import builds_logic 
 11  from coprs.logic.builds_logic import BuildsLogic 
 12  from coprs.logic.complex_logic import ComplexLogic 
 13   
 14  from coprs.views.misc import (login_required, req_with_copr, 
 15          req_with_copr, send_build_icon) 
 16  from coprs.views.coprs_ns import coprs_ns 
 17   
 18  from coprs.exceptions import (ActionInProgressException, 
 19                                InsufficientRightsException, 
 20                                UnrepeatableBuildException) 
21 22 23 @coprs_ns.route("/build/<int:build_id>/") 24 -def copr_build_redirect(build_id):
25 build = ComplexLogic.get_build_safe(build_id) 26 copr = build.copr 27 return flask.redirect(helpers.copr_url("coprs_ns.copr_build", copr, build_id=build_id))
28
29 30 @coprs_ns.route("/build/<int:build_id>/status_image.png") 31 -def copr_build_icon(build_id):
32 return send_build_icon(BuildsLogic.get_by_id(int(build_id)).first())
33
34 35 ################################ Build detail ################################ 36 37 @coprs_ns.route("/<username>/<coprname>/build/<int:build_id>/") 38 @coprs_ns.route("/g/<group_name>/<coprname>/build/<int:build_id>/") 39 @req_with_copr 40 -def copr_build(copr, build_id):
41 return render_copr_build(build_id, copr)
42
43 44 -def render_copr_build(build_id, copr):
45 build = ComplexLogic.get_build_safe(build_id) 46 return render_template("coprs/detail/build.html", build=build, copr=copr)
47
48 49 ################################ Build table ################################ 50 51 @coprs_ns.route("/<username>/<coprname>/builds/") 52 @coprs_ns.route("/g/<group_name>/<coprname>/builds/") 53 @req_with_copr 54 -def copr_builds(copr):
55 flashes = flask.session.pop('_flashes', []) 56 dirname = flask.request.args.get('dirname') 57 builds_query = builds_logic.BuildsLogic.get_copr_builds_list(copr, dirname) 58 builds = builds_query.yield_per(1000) 59 response = flask.Response(stream_with_context(helpers.stream_template("coprs/detail/builds.html", 60 copr=copr, 61 builds=builds, 62 current_dirname=dirname, 63 flashes=flashes))) 64 65 flask.session.pop('_flashes', []) 66 return response
67
68 ################################ Url builds ################################ 69 70 @coprs_ns.route("/<username>/<coprname>/add_build/") 71 @coprs_ns.route("/g/<group_name>/<coprname>/add_build/") 72 @login_required 73 @req_with_copr 74 -def copr_add_build(copr, form=None):
75 return render_add_build( 76 copr, form, view='coprs_ns.copr_new_build')
77
78 79 -def render_add_build(copr, form, view):
80 if not form: 81 form = forms.BuildFormUrlFactory(copr.active_chroots)() 82 return flask.render_template("coprs/detail/add_build/url.html", 83 copr=copr, view=view, form=form)
84
85 86 @coprs_ns.route("/<username>/<coprname>/new_build/", methods=["POST"]) 87 @coprs_ns.route("/g/<group_name>/<coprname>/new_build/", methods=["POST"]) 88 @login_required 89 @req_with_copr 90 -def copr_new_build(copr):
91 return process_new_build_url( 92 copr, 93 "coprs_ns.copr_new_build", 94 url_on_success=helpers.copr_url("coprs_ns.copr_builds", copr))
95
96 97 -def process_new_build_url(copr, add_view, url_on_success):
98 def factory(**build_options): 99 pkgs = form.pkgs.data.split("\n") 100 for pkg in pkgs: 101 BuildsLogic.create_new_from_url( 102 flask.g.user, copr, pkg, 103 chroot_names=form.selected_chroots, 104 **build_options 105 ) 106 for pkg in pkgs: 107 flask.flash("New build has been created: {}".format(pkg), "success")
108 109 form = forms.BuildFormUrlFactory(copr.active_chroots)() 110 return process_new_build(copr, form, factory, render_add_build, 111 add_view, url_on_success, msg_on_success=False) 112
113 114 -def process_new_build(copr, form, create_new_build_factory, add_function, add_view, url_on_success, msg_on_success=True):
115 if form.validate_on_submit(): 116 build_options = { 117 "enable_net": form.enable_net.data, 118 "timeout": form.timeout.data, 119 } 120 121 try: 122 create_new_build_factory(**build_options) 123 db.session.commit() 124 except (ActionInProgressException, InsufficientRightsException, UnrepeatableBuildException) as e: 125 db.session.rollback() 126 flask.flash(str(e), "error") 127 else: 128 if msg_on_success: 129 flask.flash("New build has been created.", "success") 130 131 return flask.redirect(url_on_success) 132 else: 133 return add_function(copr, form, add_view)
134
135 136 ################################ SCM builds ######################################### 137 138 @coprs_ns.route("/<username>/<coprname>/add_build_scm/") 139 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_scm/") 140 @login_required 141 @req_with_copr 142 -def copr_add_build_scm(copr, form=None):
143 return render_add_build_scm( 144 copr, form, view='coprs_ns.copr_new_build_scm')
145
146 147 -def render_add_build_scm(copr, form, view, package=None):
148 if not form: 149 form = forms.BuildFormScmFactory(copr.active_chroots)() 150 return flask.render_template("coprs/detail/add_build/scm.html", 151 copr=copr, form=form, view=view, package=package)
152
153 154 @coprs_ns.route("/<username>/<coprname>/new_build_scm/", methods=["POST"]) 155 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_scm/", methods=["POST"]) 156 @login_required 157 @req_with_copr 158 -def copr_new_build_scm(copr):
159 view = 'coprs_ns.copr_new_build_scm' 160 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 161 return process_new_build_scm(copr, view, url_on_success)
162
163 164 -def process_new_build_scm(copr, add_view, url_on_success):
165 def factory(**build_options): 166 BuildsLogic.create_new_from_scm( 167 flask.g.user, 168 copr, 169 form.scm_type.data, 170 form.clone_url.data, 171 form.committish.data, 172 form.subdirectory.data, 173 form.spec.data, 174 form.srpm_build_method.data, 175 form.selected_chroots, 176 **build_options 177 )
178 form = forms.BuildFormScmFactory(copr.active_chroots)() 179 return process_new_build(copr, form, factory, render_add_build_scm, add_view, url_on_success) 180
181 182 ################################ PyPI builds ################################ 183 184 @coprs_ns.route("/<username>/<coprname>/add_build_pypi/") 185 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_pypi/") 186 @login_required 187 @req_with_copr 188 -def copr_add_build_pypi(copr, form=None):
189 return render_add_build_pypi( 190 copr, form, view='coprs_ns.copr_new_build_pypi')
191
192 193 -def render_add_build_pypi(copr, form, view, package=None):
194 if not form: 195 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 196 return flask.render_template("coprs/detail/add_build/pypi.html", 197 copr=copr, form=form, view=view, package=package)
198
199 200 @coprs_ns.route("/<username>/<coprname>/new_build_pypi/", methods=["POST"]) 201 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_pypi/", methods=["POST"]) 202 @login_required 203 @req_with_copr 204 -def copr_new_build_pypi(copr):
205 view = 'coprs_ns.copr_new_build_pypi' 206 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 207 return process_new_build_pypi(copr, view, url_on_success)
208
209 210 -def process_new_build_pypi(copr, add_view, url_on_success):
211 def factory(**build_options): 212 BuildsLogic.create_new_from_pypi( 213 flask.g.user, 214 copr, 215 form.pypi_package_name.data, 216 form.pypi_package_version.data, 217 form.spec_template.data, 218 form.python_versions.data, 219 form.selected_chroots, 220 **build_options 221 )
222 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 223 return process_new_build(copr, form, factory, render_add_build_pypi, add_view, url_on_success) 224
225 226 ############################### RubyGems builds ############################### 227 228 @coprs_ns.route("/<username>/<coprname>/add_build_rubygems/") 229 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_rubygems/") 230 @login_required 231 @req_with_copr 232 -def copr_add_build_rubygems(copr, form=None):
233 return render_add_build_rubygems( 234 copr, form, view='coprs_ns.copr_new_build_rubygems')
235
236 237 -def render_add_build_rubygems(copr, form, view, package=None):
238 if not form: 239 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 240 return flask.render_template("coprs/detail/add_build/rubygems.html", 241 copr=copr, form=form, view=view, package=package)
242
243 244 @coprs_ns.route("/<username>/<coprname>/new_build_rubygems/", methods=["POST"]) 245 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_rubygems/", methods=["POST"]) 246 @login_required 247 @req_with_copr 248 -def copr_new_build_rubygems(copr):
249 view = 'coprs_ns.copr_new_build_rubygems' 250 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 251 return process_new_build_rubygems(copr, view, url_on_success)
252
253 254 -def process_new_build_rubygems(copr, add_view, url_on_success):
255 def factory(**build_options): 256 BuildsLogic.create_new_from_rubygems( 257 flask.g.user, 258 copr, 259 form.gem_name.data, 260 form.selected_chroots, 261 **build_options 262 )
263 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 264 return process_new_build(copr, form, factory, render_add_build_rubygems, add_view, url_on_success) 265
266 ############################### Custom builds ############################### 267 268 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_custom/", methods=["POST"]) 269 @coprs_ns.route("/<username>/<coprname>/new_build_custom/", methods=["POST"]) 270 @login_required 271 @req_with_copr 272 -def copr_new_build_custom(copr):
273 """ Handle the build request and redirect back. """ 274 275 # TODO: parametric decorator for this view && url_on_success 276 view = 'coprs_ns.copr_new_build_custom' 277 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 278 279 def factory(**build_options): 280 BuildsLogic.create_new_from_custom( 281 flask.g.user, 282 copr, 283 form.script.data, 284 form.chroot.data, 285 form.builddeps.data, 286 form.resultdir.data, 287 chroot_names=form.selected_chroots, 288 **build_options 289 )
290 291 form = forms.BuildFormCustomFactory(copr.active_chroots)() 292 293 return process_new_build(copr, form, factory, render_add_build_custom, 294 view, url_on_success) 295
296 297 298 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_custom/") 299 @coprs_ns.route("/<username>/<coprname>/add_build_custom/") 300 @login_required 301 @req_with_copr 302 -def copr_add_build_custom(copr, form=None):
303 return render_add_build_custom(copr, form, 304 'coprs_ns.copr_new_build_custom')
305
306 -def render_add_build_custom(copr, form, view, package=None):
307 if not form: 308 form = forms.BuildFormCustomFactory(copr.active_chroots)() 309 return flask.render_template("coprs/detail/add_build/custom.html", 310 copr=copr, form=form, view=view)
311
312 313 ################################ Upload builds ################################ 314 315 @coprs_ns.route("/<username>/<coprname>/add_build_upload/") 316 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_upload/") 317 @login_required 318 @req_with_copr 319 -def copr_add_build_upload(copr, form=None):
320 return render_add_build_upload( 321 copr, form, view='coprs_ns.copr_new_build_upload')
322
323 324 -def render_add_build_upload(copr, form, view):
325 if not form: 326 form = forms.BuildFormUploadFactory(copr.active_chroots)() 327 return flask.render_template("coprs/detail/add_build/upload.html", 328 copr=copr, form=form, view=view)
329
330 331 @coprs_ns.route("/<username>/<coprname>/new_build_upload/", methods=["POST"]) 332 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_upload/", methods=["POST"]) 333 @login_required 334 @req_with_copr 335 -def copr_new_build_upload(copr):
336 view = 'coprs_ns.copr_new_build_upload' 337 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 338 return process_new_build_upload(copr, view, url_on_success)
339
340 341 -def process_new_build_upload(copr, add_view, url_on_success):
342 def factory(**build_options): 343 BuildsLogic.create_new_from_upload( 344 flask.g.user, copr, 345 f_uploader=lambda path: form.pkgs.data.save(path), 346 orig_filename=form.pkgs.data.filename, 347 chroot_names=form.selected_chroots, 348 **build_options 349 )
350 form = forms.BuildFormUploadFactory(copr.active_chroots)() 351 return process_new_build(copr, form, factory, render_add_build_upload, add_view, url_on_success) 352
353 354 ################################ Builds rebuilds ################################ 355 356 @coprs_ns.route("/<username>/<coprname>/new_build_rebuild/<int:build_id>/", methods=["POST"]) 357 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_rebuild/<int:build_id>/", methods=["POST"]) 358 @login_required 359 @req_with_copr 360 -def copr_new_build_rebuild(copr, build_id):
361 view='coprs_ns.copr_new_build' 362 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 363 return process_rebuild(copr, build_id, view=view, url_on_success=url_on_success)
364
365 366 -def process_rebuild(copr, build_id, view, url_on_success):
367 def factory(**build_options): 368 source_build = ComplexLogic.get_build_safe(build_id) 369 BuildsLogic.create_new_from_other_build( 370 flask.g.user, copr, source_build, 371 chroot_names=form.selected_chroots, 372 **build_options 373 )
374 form = forms.BuildFormRebuildFactory.create_form_cls(copr.active_chroots)() 375 return process_new_build(copr, form, factory, render_add_build, view, url_on_success) 376
377 378 ################################ Repeat ################################ 379 380 @coprs_ns.route("/<username>/<coprname>/repeat_build/<int:build_id>/", methods=["GET", "POST"]) 381 @coprs_ns.route("/g/<group_name>/<coprname>/repeat_build/<int:build_id>/", methods=["GET", "POST"]) 382 @login_required 383 @req_with_copr 384 -def copr_repeat_build(copr, build_id):
385 return process_copr_repeat_build(build_id, copr)
386
387 388 -def process_copr_repeat_build(build_id, copr):
389 build = ComplexLogic.get_build_safe(build_id) 390 if not flask.g.user.can_build_in(build.copr): 391 flask.flash("You are not allowed to repeat this build.") 392 393 if build.source_type == helpers.BuildSourceEnum('upload'): 394 # If the original build's source is 'upload', we will show only the 395 # original build's chroots and skip import. 396 available_chroots = build.chroots 397 398 else: 399 # For all other sources, we will show all chroots enabled in the project 400 # and proceed with import. 401 available_chroots = copr.active_chroots 402 403 form = forms.BuildFormRebuildFactory.create_form_cls(available_chroots)( 404 build_id=build_id, enable_net=build.enable_net) 405 406 # remove all checkboxes by default 407 for ch in available_chroots: 408 field = getattr(form, ch.name) 409 field.data = False 410 chroot_to_build = request.args.get("chroot") 411 app.logger.debug("got param chroot: {}".format(chroot_to_build)) 412 if chroot_to_build: 413 # set single checkbox if chroot query arg was provided 414 if hasattr(form, chroot_to_build): 415 getattr(form, chroot_to_build).data = True 416 else: 417 build_chroot_names = set(ch.name for ch in build.chroots) 418 build_failed_chroot_names = set(ch.name for ch in build.get_chroots_by_status([ 419 StatusEnum('failed'), StatusEnum('canceled'), 420 ])) 421 for ch in available_chroots: 422 # check checkbox on all the chroots that have not been (successfully) built before 423 if (ch.name not in build_chroot_names) or (ch.name in build_failed_chroot_names): 424 getattr(form, ch.name).data = True 425 return flask.render_template( 426 "coprs/detail/add_build/rebuild.html", 427 copr=copr, build=build, form=form)
428
429 430 ################################ Cancel ################################ 431 432 -def process_cancel_build(build):
433 try: 434 builds_logic.BuildsLogic.cancel_build(flask.g.user, build) 435 except InsufficientRightsException as e: 436 flask.flash(str(e), "error") 437 else: 438 db.session.commit() 439 flask.flash("Build {} has been canceled successfully.".format(build.id)) 440 return flask.redirect(helpers.url_for_copr_builds(build.copr))
441
442 443 @coprs_ns.route("/<username>/<coprname>/cancel_build/<int:build_id>/", methods=["POST"]) 444 @coprs_ns.route("/g/<group_name>/<coprname>/cancel_build/<int:build_id>/", methods=["POST"]) 445 @login_required 446 @req_with_copr 447 -def copr_cancel_build(copr, build_id):
448 # only the user who ran the build can cancel it 449 build = ComplexLogic.get_build_safe(build_id) 450 return process_cancel_build(build)
451 452 453 ################################ Delete ################################ 454 455 @coprs_ns.route("/<username>/<coprname>/delete_build/<int:build_id>/", 456 methods=["POST"])
457 @login_required 458 -def copr_delete_build(username, coprname, build_id):
459 build = ComplexLogic.get_build_safe(build_id) 460 461 try: 462 builds_logic.BuildsLogic.delete_build(flask.g.user, build) 463 except (InsufficientRightsException, ActionInProgressException) as e: 464 flask.flash(str(e), "error") 465 else: 466 db.session.commit() 467 flask.flash("Build has been deleted successfully.") 468 469 return flask.redirect(helpers.url_for_copr_builds(build.copr))
470
471 ################################ xhr batch delete ################################ 472 473 @coprs_ns.route("/<username>/<coprname>/delete_builds/", methods=["POST"]) 474 @coprs_ns.route("/g/<group_name>/<coprname>/delete_builds/", methods=["POST"]) 475 @login_required 476 @req_with_copr 477 -def copr_delete_builds(copr):
478 build_ids = flask.request.form.getlist("build_ids[]") 479 480 to_delete = [] 481 for build_id in build_ids: 482 build = ComplexLogic.get_build_safe(build_id) 483 to_delete.append(build) 484 485 builds_logic.BuildsLogic.delete_multiple_builds(flask.g.user, to_delete) 486 487 db.session.commit() 488 build_ids_str = ", ".join(build_ids).strip(", ") 489 flask.flash("Builds {} have been deleted successfully.".format(build_ids_str), "success") 490 return flask.jsonify({"msg": "success"})
491