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, req_with_copr 
 22  from coprs.views.coprs_ns import coprs_ns 
 23   
 24  from coprs.exceptions import (ActionInProgressException, 
 25                                InsufficientRightsException, 
 26                                UnrepeatableBuildException) 
27 28 29 @coprs_ns.route("/build/<int:build_id>/") 30 -def copr_build_redirect(build_id):
31 build = ComplexLogic.get_build_safe(build_id) 32 copr = build.copr 33 return flask.redirect(helpers.copr_url("coprs_ns.copr_build", copr, build_id=build_id))
34
35 36 ################################ Build detail ################################ 37 38 @coprs_ns.route("/<username>/<coprname>/build/<int:build_id>/") 39 @coprs_ns.route("/g/<group_name>/<coprname>/build/<int:build_id>/") 40 @req_with_copr 41 -def copr_build(copr, build_id):
42 return render_copr_build(build_id, copr)
43
44 45 -def render_copr_build(build_id, copr):
46 build = ComplexLogic.get_build_safe(build_id) 47 return render_template("coprs/detail/build.html", build=build, copr=copr)
48
49 50 ################################ Build table ################################ 51 52 @coprs_ns.route("/<username>/<coprname>/builds/") 53 @coprs_ns.route("/g/<group_name>/<coprname>/builds/") 54 @req_with_copr 55 -def copr_builds(copr):
56 return render_copr_builds(copr)
57
58 59 -def render_copr_builds(copr):
60 builds_query = builds_logic.BuildsLogic.get_copr_builds_list(copr=copr) 61 return flask.Response(stream_with_context(helpers.stream_template("coprs/detail/builds.html", 62 copr=copr, 63 builds=list(builds_query))))
64
65 66 ################################ Url builds ################################ 67 68 @coprs_ns.route("/<username>/<coprname>/add_build/") 69 @coprs_ns.route("/g/<group_name>/<coprname>/add_build/") 70 @login_required 71 @req_with_copr 72 -def copr_add_build(copr, form=None):
73 return render_add_build( 74 copr, form, view='coprs_ns.copr_new_build')
75
76 77 -def render_add_build(copr, form, view):
78 if not form: 79 form = forms.BuildFormUrlFactory(copr.active_chroots)() 80 return flask.render_template("coprs/detail/add_build/url.html", 81 copr=copr, view=view, form=form)
82
83 84 @coprs_ns.route("/<username>/<coprname>/new_build/", methods=["POST"]) 85 @coprs_ns.route("/g/<group_name>/<coprname>/new_build/", methods=["POST"]) 86 @login_required 87 @req_with_copr 88 -def copr_new_build(copr):
89 return process_new_build_url( 90 copr, 91 "coprs_ns.copr_new_build", 92 url_on_success=helpers.copr_url("coprs_ns.copr_builds", copr))
93
94 95 -def process_new_build_url(copr, add_view, url_on_success):
96 def factory(**build_options): 97 pkgs = form.pkgs.data.split("\n") 98 for pkg in pkgs: 99 BuildsLogic.create_new_from_url( 100 flask.g.user, copr, pkg, 101 chroot_names=form.selected_chroots, 102 **build_options 103 ) 104 for pkg in pkgs: 105 flask.flash("New build has been created: {}".format(pkg), "success")
106 107 form = forms.BuildFormUrlFactory(copr.active_chroots)() 108 return process_new_build(copr, form, factory, render_add_build, 109 add_view, url_on_success, msg_on_success=False) 110
111 112 -def process_new_build(copr, form, create_new_build_factory, add_function, add_view, url_on_success, msg_on_success=True):
113 if form.validate_on_submit(): 114 build_options = { 115 "enable_net": form.enable_net.data, 116 "timeout": form.timeout.data, 117 } 118 119 try: 120 create_new_build_factory(**build_options) 121 db.session.commit() 122 except (ActionInProgressException, InsufficientRightsException, UnrepeatableBuildException) as e: 123 db.session.rollback() 124 flask.flash(str(e), "error") 125 else: 126 if msg_on_success: 127 flask.flash("New build has been created.", "success") 128 129 return flask.redirect(url_on_success) 130 else: 131 return add_function(copr, form, add_view)
132
133 134 ################################ SCM builds ######################################### 135 136 @coprs_ns.route("/<username>/<coprname>/add_build_scm/") 137 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_scm/") 138 @login_required 139 @req_with_copr 140 -def copr_add_build_scm(copr, form=None):
141 return render_add_build_scm( 142 copr, form, view='coprs_ns.copr_new_build_scm')
143
144 145 -def render_add_build_scm(copr, form, view, package=None):
146 if not form: 147 form = forms.BuildFormScmFactory(copr.active_chroots)() 148 return flask.render_template("coprs/detail/add_build/scm.html", 149 copr=copr, form=form, view=view, package=package)
150
151 152 @coprs_ns.route("/<username>/<coprname>/new_build_scm/", methods=["POST"]) 153 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_scm/", methods=["POST"]) 154 @login_required 155 @req_with_copr 156 -def copr_new_build_scm(copr):
157 view = 'coprs_ns.copr_new_build_scm' 158 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 159 return process_new_build_scm(copr, view, url_on_success)
160
161 162 -def process_new_build_scm(copr, add_view, url_on_success):
163 def factory(**build_options): 164 BuildsLogic.create_new_from_scm( 165 flask.g.user, 166 copr, 167 form.scm_type.data, 168 form.clone_url.data, 169 form.committish.data, 170 form.subdirectory.data, 171 form.spec.data, 172 form.srpm_build_method.data, 173 form.selected_chroots, 174 **build_options 175 )
176 form = forms.BuildFormScmFactory(copr.active_chroots)() 177 return process_new_build(copr, form, factory, render_add_build_scm, add_view, url_on_success) 178
179 180 ################################ PyPI builds ################################ 181 182 @coprs_ns.route("/<username>/<coprname>/add_build_pypi/") 183 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_pypi/") 184 @login_required 185 @req_with_copr 186 -def copr_add_build_pypi(copr, form=None):
187 return render_add_build_pypi( 188 copr, form, view='coprs_ns.copr_new_build_pypi')
189
190 191 -def render_add_build_pypi(copr, form, view, package=None):
192 if not form: 193 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 194 return flask.render_template("coprs/detail/add_build/pypi.html", 195 copr=copr, form=form, view=view, package=package)
196
197 198 @coprs_ns.route("/<username>/<coprname>/new_build_pypi/", methods=["POST"]) 199 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_pypi/", methods=["POST"]) 200 @login_required 201 @req_with_copr 202 -def copr_new_build_pypi(copr):
203 view = 'coprs_ns.copr_new_build_pypi' 204 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 205 return process_new_build_pypi(copr, view, url_on_success)
206
207 208 -def process_new_build_pypi(copr, add_view, url_on_success):
209 def factory(**build_options): 210 BuildsLogic.create_new_from_pypi( 211 flask.g.user, 212 copr, 213 form.pypi_package_name.data, 214 form.pypi_package_version.data, 215 form.python_versions.data, 216 form.selected_chroots, 217 **build_options 218 )
219 form = forms.BuildFormPyPIFactory(copr.active_chroots)() 220 return process_new_build(copr, form, factory, render_add_build_pypi, add_view, url_on_success) 221
222 223 ############################### RubyGems builds ############################### 224 225 @coprs_ns.route("/<username>/<coprname>/add_build_rubygems/") 226 @coprs_ns.route("/g/<group_name>/<coprname>/add_build_rubygems/") 227 @login_required 228 @req_with_copr 229 -def copr_add_build_rubygems(copr, form=None):
230 return render_add_build_rubygems( 231 copr, form, view='coprs_ns.copr_new_build_rubygems')
232
233 234 -def render_add_build_rubygems(copr, form, view, package=None):
235 if not form: 236 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 237 return flask.render_template("coprs/detail/add_build/rubygems.html", 238 copr=copr, form=form, view=view, package=package)
239
240 241 @coprs_ns.route("/<username>/<coprname>/new_build_rubygems/", methods=["POST"]) 242 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_rubygems/", methods=["POST"]) 243 @login_required 244 @req_with_copr 245 -def copr_new_build_rubygems(copr):
246 view = 'coprs_ns.copr_new_build_rubygems' 247 url_on_success = helpers.copr_url("coprs_ns.copr_builds", copr) 248 return process_new_build_rubygems(copr, view, url_on_success)
249
250 251 -def process_new_build_rubygems(copr, add_view, url_on_success):
252 def factory(**build_options): 253 BuildsLogic.create_new_from_rubygems( 254 flask.g.user, 255 copr, 256 form.gem_name.data, 257 form.selected_chroots, 258 **build_options 259 )
260 form = forms.BuildFormRubyGemsFactory(copr.active_chroots)() 261 return process_new_build(copr, form, factory, render_add_build_rubygems, add_view, url_on_success) 262
263 ############################### Custom builds ############################### 264 265 @coprs_ns.route("/g/<group_name>/<coprname>/new_build_custom/", methods=["POST"]) 266 @coprs_ns.route("/<username>/<coprname>/new_build_custom/", methods=["POST"]) 267 @login_required 268 @req_with_copr 269 -def copr_new_build_custom(copr):
270 """ Handle the build request and redirect back. """ 271 272 # TODO: parametric decorator for this view && url_on_success 273 view = 'coprs_ns.copr_new_build_custom' 274 url_on_success = helpers.copr_url('coprs_ns.copr_add_build_custom', copr) 275 276 def factory(**build_options): 277 def cleanup_script(string): 278 # Keep this function in @copr_ns only, to not touch the contents of 279 # script specified through api or copr-cli. But from web-ui form, 280 # the script usually has unintentional '\r\n' EOLs, so drop them to 281 # not have broken shebang. 282 string = string.replace('\r\n', '\n') 283 284 # And append newline to have a valid unix file. 285 if not string.endswith('\n'): 286 string += '\n' 287 288 return string
289 290 BuildsLogic.create_new_from_custom( 291 flask.g.user, 292 copr, 293 cleanup_script(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_build", copr, build_id=build_id) 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), "success") 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.", "success") 478 479 return flask.redirect(helpers.url_for_copr_builds(build.copr))
480