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