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