Trees | Indices | Help |
---|
|
1 import re 2 from six.moves.urllib.parse import urlparse 3 4 import flask 5 import wtforms 6 import json 7 8 from flask_wtf.file import FileAllowed, FileRequired, FileField 9 10 from flask_wtf import Form as FlaskForm 11 from jinja2 import Markup 12 13 from coprs import constants 14 from coprs import helpers 15 from coprs import models 16 from coprs.logic.coprs_logic import CoprsLogic 17 from coprs.logic.users_logic import UsersLogic 18 from coprs.logic.modules_logic import ModulesLogic 19 from coprs.models import Package 20 from coprs import exceptions23 """ 24 Params 25 ------ 26 source_type_text : str 27 name of the source type (tito/mock/pypi/rubygems/upload) 28 29 Returns 30 ------- 31 BasePackageForm child 32 based on source_type_text input 33 """ 34 if source_type_text == 'git_and_tito': 35 return PackageFormTito 36 elif source_type_text == 'mock_scm': 37 return PackageFormMock 38 elif source_type_text == 'pypi': 39 return PackageFormPyPI 40 elif source_type_text == 'rubygems': 41 return PackageFormRubyGems 42 else: 43 raise exceptions.UnknownSourceTypeException("Invalid source type")4447 widget = wtforms.widgets.ListWidget(prefix_label=False) 48 option_widget = wtforms.widgets.CheckboxInput()49527254 if not message: 55 message = ("A list of http[s] URLs separated by whitespace characters" 56 " is needed ('{0}' doesn't seem to be a valid URL).") 57 self.message = message5860 urls = field.data.split() 61 for u in urls: 62 if not self.is_url(u): 63 raise wtforms.ValidationError(self.message.format(u))6466 parsed = urlparse(url) 67 if not parsed.scheme.startswith("http"): 68 return False 69 if not parsed.netloc: 70 return False 71 return True75 """ Allows also `repo://` schema"""9177 parsed = urlparse(url) 78 if parsed.scheme not in ["http", "https", "copr"]: 79 return False 80 if not parsed.netloc: 81 return False 82 # copr://username/projectname 83 # ^^ schema ^^ netlock ^^ path 84 if parsed.scheme == "copr": 85 # check if projectname missed 86 path_split = parsed.path.split("/") 87 if len(path_split) < 2 or path_split[1] == "": 88 return False 89 90 return True10595 if not message: 96 message = ("URLs must end with .src.rpm, .nosrc.rpm, or .spec" 97 " ('{0}' doesn't seem to be a valid URL).") 98 super(UrlSrpmListValidator, self).__init__(message)99117109 if not message: 110 message = "You can upload only .src.rpm, .nosrc.rpm, and .spec files" 111 self.message = message112120143122 if not message: 123 if group is None: 124 message = "You already have project named '{}'." 125 else: 126 message = "Group {} ".format(group) + "already have project named '{}'." 127 self.message = message 128 if not user: 129 user = flask.g.user 130 self.user = user 131 self.group = group132134 if self.group: 135 existing = CoprsLogic.exists_for_group( 136 self.group, field.data).first() 137 else: 138 existing = CoprsLogic.exists_for_user( 139 self.user, field.data).first() 140 141 if existing and str(existing.id) != form.id.data: 142 raise wtforms.ValidationError(self.message.format(field.data))156147 if not message: 148 message = "Name must contain only letters, digits, underscores, dashes and dots." 149 self.message = message150168160 selected = set(field.data.split()) 161 enabled = set(self.chroots_list()) 162 163 if not (selected <= enabled): 164 raise wtforms.ValidationError("Such chroot is not enabled: {}".format(", ".join(selected - enabled)))165171180 197173 if not message: 174 message = "Project's name can not be just number." 175 self.message = message176200210202 if not value: 203 return '' 204 # Replace every whitespace string with one newline 205 # Formats ideally for html form filling, use replace('\n', ' ') 206 # to get space-separated values or split() to get list 207 result = value.strip() 208 regex = re.compile(r"\s+") 209 return regex.sub(lambda x: '\n', result)213218215 if value: 216 return helpers.PermissionEnum("request") 217 return helpers.PermissionEnum("nothing")221 222 @staticmethod292 293 def validate_mock_chroots_not_empty(self): 294 have_any = False 295 for c in self.chroots_list: 296 if getattr(self, c).data: 297 have_any = True 298 return have_any 299 300 F.chroots_list = list(map(lambda x: x.name, 301 models.MockChroot.query.filter( 302 models.MockChroot.is_active == True 303 ).all())) 304 F.chroots_list.sort() 305 # sets of chroots according to how we should print them in columns 306 F.chroots_sets = {} 307 for ch in F.chroots_list: 308 checkbox_default = False 309 if mock_chroots and ch in map(lambda x: x.name, 310 mock_chroots): 311 checkbox_default = True 312 313 setattr(F, ch, wtforms.BooleanField(ch, default=checkbox_default)) 314 if ch[0] in F.chroots_sets: 315 F.chroots_sets[ch[0]].append(ch) 316 else: 317 F.chroots_sets[ch[0]] = [ch] 318 319 return F 320224 class F(FlaskForm): 225 # also use id here, to be able to find out whether user 226 # is updating a copr if so, we don't want to shout 227 # that name already exists 228 id = wtforms.HiddenField() 229 group_id = wtforms.HiddenField() 230 231 name = wtforms.StringField( 232 "Name", 233 validators=[ 234 wtforms.validators.DataRequired(), 235 NameCharactersValidator(), 236 CoprUniqueNameValidator(user=user, group=group), 237 NameNotNumberValidator() 238 ]) 239 240 homepage = wtforms.StringField( 241 "Homepage", 242 validators=[ 243 wtforms.validators.Optional(), 244 wtforms.validators.URL()]) 245 246 contact = wtforms.StringField( 247 "Contact", 248 validators=[ 249 wtforms.validators.Optional(), 250 EmailOrURL()]) 251 252 description = wtforms.TextAreaField("Description") 253 254 instructions = wtforms.TextAreaField("Instructions") 255 256 repos = wtforms.TextAreaField( 257 "External Repositories", 258 validators=[UrlRepoListValidator()], 259 filters=[StringListFilter()]) 260 261 initial_pkgs = wtforms.TextAreaField( 262 "Initial packages to build", 263 validators=[ 264 UrlListValidator(), 265 UrlSrpmListValidator()], 266 filters=[StringListFilter()]) 267 268 disable_createrepo = wtforms.BooleanField(default=False) 269 build_enable_net = wtforms.BooleanField(default=False) 270 unlisted_on_hp = wtforms.BooleanField("Do not display this project on home page", default=False) 271 persistent = wtforms.BooleanField(default=False) 272 auto_prune = wtforms.BooleanField("If backend auto-prunning script should be run for this project", default=True) 273 use_bootstrap_container = wtforms.BooleanField("Enable use_bootstrap_container mock's feature (experimental)", default=False) 274 follow_fedora_branching = wtforms.BooleanField("If newly branched chroots should be automatically enabled and populated.", default=False) 275 276 @property 277 def selected_chroots(self): 278 selected = [] 279 for ch in self.chroots_list: 280 if getattr(self, ch).data: 281 selected.append(ch) 282 return selected283 284 def validate(self): 285 if not super(F, self).validate(): 286 return False 287 288 if not self.validate_mock_chroots_not_empty(): 289 self.errors["chroots"] = ["At least one chroot must be selected"] 290 return False 291 return True323 verify = wtforms.TextField( 324 "Confirm deleting by typing 'yes'", 325 validators=[ 326 wtforms.validators.Required(), 327 wtforms.validators.Regexp( 328 r"^yes$", 329 message="Type 'yes' - without the quotes, lowercase.") 330 ])331332 333 # @TODO jkadlcik - rewrite via BaseBuildFormFactory after fe-dev-cloud is back online 334 -class BuildFormRebuildFactory(object):335 @staticmethod363 364 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 365 F.chroots_list.sort() 366 F.chroots_sets = {} 367 for ch in F.chroots_list: 368 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 369 if ch[0] in F.chroots_sets: 370 F.chroots_sets[ch[0]].append(ch) 371 else: 372 F.chroots_sets[ch[0]] = [ch] 373 374 return F 375337 class F(FlaskForm): 338 @property 339 def selected_chroots(self): 340 selected = [] 341 for ch in self.chroots_list: 342 if getattr(self, ch).data: 343 selected.append(ch) 344 return selected345 346 memory_reqs = wtforms.IntegerField( 347 "Memory requirements", 348 validators=[ 349 wtforms.validators.NumberRange( 350 min=constants.MIN_BUILD_MEMORY, 351 max=constants.MAX_BUILD_MEMORY)], 352 default=constants.DEFAULT_BUILD_MEMORY) 353 354 timeout = wtforms.IntegerField( 355 "Timeout", 356 validators=[ 357 wtforms.validators.NumberRange( 358 min=constants.MIN_BUILD_TIMEOUT, 359 max=constants.MAX_BUILD_TIMEOUT)], 360 default=constants.DEFAULT_BUILD_TIMEOUT) 361 362 enable_net = wtforms.BooleanField()378 package_name = wtforms.StringField( 379 "Package name", 380 validators=[wtforms.validators.DataRequired()]) 381 webhook_rebuild = wtforms.BooleanField(default=False)382385 git_url = wtforms.StringField( 386 "Git URL", 387 validators=[ 388 wtforms.validators.DataRequired(), 389 wtforms.validators.URL()]) 390 391 git_directory = wtforms.StringField( 392 "Git Directory", 393 validators=[ 394 wtforms.validators.Optional()]) 395 396 git_branch = wtforms.StringField( 397 "Git Branch", 398 validators=[ 399 wtforms.validators.Optional()]) 400 401 tito_test = wtforms.BooleanField(default=False) 402 403 @property411405 return json.dumps({ 406 "git_url": self.git_url.data, 407 "git_branch": self.git_branch.data, 408 "git_dir": self.git_directory.data, 409 "tito_test": self.tito_test.data 410 })414 scm_type = wtforms.SelectField( 415 "SCM Type", 416 choices=[("git", "Git"), ("svn", "SVN")]) 417 418 scm_url = wtforms.StringField( 419 "SCM URL", 420 validators=[ 421 wtforms.validators.DataRequired(), 422 wtforms.validators.URL()]) 423 424 scm_branch = wtforms.StringField( 425 "Git Branch", 426 validators=[ 427 wtforms.validators.Optional()]) 428 429 scm_subdir = wtforms.StringField( 430 "Subdirectory", 431 validators=[ 432 wtforms.validators.Optional()]) 433 434 spec = wtforms.StringField( 435 "Spec File", 436 validators=[ 437 wtforms.validators.Optional(), 438 wtforms.validators.Regexp( 439 r"^.+\.spec$", 440 message="RPM spec file must end with .spec")]) 441 442 @property451444 return json.dumps({ 445 "scm_type": self.scm_type.data, 446 "scm_url": self.scm_url.data, 447 "scm_subdir": self.scm_subdir.data, 448 "scm_branch": self.scm_branch.data, 449 "spec": self.spec.data 450 })454 pypi_package_name = wtforms.StringField( 455 "PyPI package name", 456 validators=[wtforms.validators.DataRequired()]) 457 458 pypi_package_version = wtforms.StringField( 459 "PyPI package version", 460 validators=[ 461 wtforms.validators.Optional(), 462 ]) 463 464 python_versions = MultiCheckboxField( 465 'Build for Python', 466 choices=[ 467 ('3', 'python3'), 468 ('2', 'python2') 469 ], 470 default=['3', '2']) 471 472 @property479474 return json.dumps({ 475 "pypi_package_name": self.pypi_package_name.data, 476 "pypi_package_version": self.pypi_package_version.data, 477 "python_versions": self.python_versions.data 478 })482 gem_name = wtforms.StringField( 483 "Gem Name", 484 validators=[wtforms.validators.DataRequired()]) 485 486 @property491494 clone_url = wtforms.StringField( 495 "Clone Url", 496 validators=[wtforms.validators.DataRequired()]) 497 498 branch = wtforms.StringField( 499 "Branch", 500 validators=[wtforms.validators.Optional()]) 501 502 @property508519512 form_cls = BaseBuildFormFactory(active_chroots, FlaskForm) 513 form_cls.packages = MultiCheckboxField( 514 "Packages", 515 choices=[(name, name) for name in package_names], 516 default=package_names, 517 validators=[wtforms.validators.DataRequired()]) 518 return form_cls531 532 F.memory_reqs = wtforms.IntegerField( 533 "Memory requirements", 534 validators=[ 535 wtforms.validators.Optional(), 536 wtforms.validators.NumberRange( 537 min=constants.MIN_BUILD_MEMORY, 538 max=constants.MAX_BUILD_MEMORY)], 539 default=constants.DEFAULT_BUILD_MEMORY) 540 541 F.timeout = wtforms.IntegerField( 542 "Timeout", 543 validators=[ 544 wtforms.validators.Optional(), 545 wtforms.validators.NumberRange( 546 min=constants.MIN_BUILD_TIMEOUT, 547 max=constants.MAX_BUILD_TIMEOUT)], 548 default=constants.DEFAULT_BUILD_TIMEOUT) 549 550 F.enable_net = wtforms.BooleanField() 551 F.background = wtforms.BooleanField(default=False) 552 553 # overrides BasePackageForm.package_name and is unused for building 554 F.package_name = wtforms.StringField() 555 556 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 557 F.chroots_list.sort() 558 F.chroots_sets = {} 559 for ch in F.chroots_list: 560 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 561 if ch[0] in F.chroots_sets: 562 F.chroots_sets[ch[0]].append(ch) 563 else: 564 F.chroots_sets[ch[0]] = [ch] 565 return F 566 571 576 581 586 591523 class F(form): 524 @property 525 def selected_chroots(self): 526 selected = [] 527 for ch in self.chroots_list: 528 if getattr(self, ch).data: 529 selected.append(ch) 530 return selected600595 form = BaseBuildFormFactory(active_chroots, FlaskForm) 596 form.pkgs = FileField('srpm', validators=[ 597 FileRequired(), 598 SrpmValidator()]) 599 return form613604 form = BaseBuildFormFactory(active_chroots, FlaskForm) 605 form.pkgs = wtforms.TextAreaField( 606 "Pkgs", 607 validators=[ 608 wtforms.validators.DataRequired(message="URLs to packages are required"), 609 UrlListValidator(), 610 UrlSrpmListValidator()], 611 filters=[StringListFilter()]) 612 return form616 modulemd = FileField("modulemd", validators=[ 617 FileRequired(), 618 # @TODO Validate modulemd.yaml file 619 ]) 620 621 create = wtforms.BooleanField("create", default=True) 622 build = wtforms.BooleanField("build", default=True)623626 modulemd = FileField("modulemd") 627 scmurl = wtforms.StringField() 628 branch = wtforms.StringField() 629 copr_owner = wtforms.StringField() 630 copr_project = wtforms.StringField()631634 635 """ 636 Validator for editing chroots in project 637 (adding packages to minimal chroot) 638 """ 639 640 buildroot_pkgs = wtforms.TextField( 641 "Packages") 642 643 repos = wtforms.TextAreaField('Repos', 644 validators=[UrlRepoListValidator(), 645 wtforms.validators.Optional()], 646 filters=[StringListFilter()]) 647 648 module_md = FileField("module_md") 649 650 comps = FileField("comps_xml")651654 comment = wtforms.TextAreaField("Comment")655658 659 @staticmethod 663 664 builder_default = False 665 admin_default = False 666 667 if permission: 668 if permission.copr_builder != helpers.PermissionEnum("nothing"): 669 builder_default = True 670 if permission.copr_admin != helpers.PermissionEnum("nothing"): 671 admin_default = True 672 673 setattr(F, "copr_builder", 674 wtforms.BooleanField( 675 default=builder_default, 676 filters=[ValueToPermissionNumberFilter()])) 677 678 setattr(F, "copr_admin", 679 wtforms.BooleanField( 680 default=admin_default, 681 filters=[ValueToPermissionNumberFilter()])) 682 683 return F684687 688 """Creates a dynamic form for given set of copr permissions""" 689 @staticmethod 693 694 for perm in permissions: 695 builder_choices = helpers.PermissionEnum.choices_list() 696 admin_choices = helpers.PermissionEnum.choices_list() 697 698 builder_default = perm.copr_builder 699 admin_default = perm.copr_admin 700 701 setattr(F, "copr_builder_{0}".format(perm.user.id), 702 wtforms.SelectField( 703 choices=builder_choices, 704 default=builder_default, 705 coerce=int)) 706 707 setattr(F, "copr_admin_{0}".format(perm.user.id), 708 wtforms.SelectField( 709 choices=admin_choices, 710 default=admin_default, 711 coerce=int)) 712 713 return F714717 description = wtforms.TextAreaField('Description', 718 validators=[wtforms.validators.Optional()]) 719 720 instructions = wtforms.TextAreaField('Instructions', 721 validators=[wtforms.validators.Optional()]) 722 723 chroots = wtforms.TextAreaField('Chroots', 724 validators=[wtforms.validators.Optional(), ChrootsValidator()]) 725 726 repos = wtforms.TextAreaField('Repos', 727 validators=[UrlRepoListValidator(), 728 wtforms.validators.Optional()], 729 filters=[StringListFilter()]) 730 731 disable_createrepo = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 732 unlisted_on_hp = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 733 build_enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 734 auto_prune = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 735 use_bootstrap_container = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 736 follow_fedora_branching = wtforms.BooleanField(validators=[wtforms.validators.Optional()])737740 @staticmethod762742 class F(FlaskForm): 743 source = wtforms.StringField( 744 "Source", 745 default=copr.full_name) 746 747 owner = wtforms.SelectField( 748 "Fork owner", 749 choices=[(user.name, user.name)] + [(g.at_name, g.at_name) for g in groups], 750 default=user.name, 751 validators=[wtforms.validators.DataRequired()]) 752 753 name = wtforms.StringField( 754 "Fork name", 755 default=copr.name, 756 validators=[wtforms.validators.DataRequired(), NameCharactersValidator()]) 757 758 confirm = wtforms.BooleanField( 759 "Confirm", 760 default=False)761 return F765 buildroot_pkgs = wtforms.TextField('Additional packages to be always present in minimal buildroot') 766 repos = wtforms.TextAreaField('Additional repos to be used for builds in chroot', 767 validators=[UrlRepoListValidator(), 768 wtforms.validators.Optional()], 769 filters=[StringListFilter()]) 770 upload_comps = FileField("Upload comps.xml") 771 delete_comps = wtforms.BooleanField("Delete comps.xml")772775 playground = wtforms.BooleanField("Playground")776779 project = wtforms.TextField("Project")780783792785 if not message: 786 message = "Group with the alias '{}' already exists." 787 self.message = message788790 if UsersLogic.group_alias_exists(field.data): 791 raise wtforms.ValidationError(self.message.format(field.data))795 796 name = wtforms.StringField( 797 validators=[ 798 wtforms.validators.Regexp( 799 re.compile(r"^[\w.-]+$"), 800 message="Name must contain only letters," 801 "digits, underscores, dashes and dots."), 802 GroupUniqueNameValidator() 803 ] 804 )805808 name = wtforms.StringField("Name") 809 stream = wtforms.StringField("Stream") 810 version = wtforms.IntegerField("Version") 811 builds = wtforms.FieldList(wtforms.StringField("Builds ID list")) 812 packages = wtforms.FieldList(wtforms.StringField("Packages list")) 813 filter = wtforms.FieldList(wtforms.StringField("Package Filter")) 814 api = wtforms.FieldList(wtforms.StringField("Module API")) 815 profile_names = wtforms.FieldList(wtforms.StringField("Install Profiles"), min_entries=2) 816 profile_pkgs = wtforms.FieldList(wtforms.FieldList(wtforms.StringField("Install Profiles")), min_entries=2) 817 821848823 if not FlaskForm.validate(self): 824 return False 825 826 module = ModulesLogic.get_by_nsv(self.copr, self.name.data, self.stream.data, self.version.data).first() 827 if module: 828 self.errors["nsv"] = [Markup("Module <a href='{}'>{}</a> already exists".format( 829 helpers.copr_url("coprs_ns.copr_module", module.copr, id=module.id), module.full_name))] 830 return False 831 832 # Profile names should be unique 833 names = filter(None, self.profile_names.data) 834 if len(set(names)) < len(names): 835 self.errors["profiles"] = ["Profile names must be unique"] 836 return False 837 838 # WORKAROUND 839 # profile_pkgs are somehow sorted so if I fill profile_name in the first box and 840 # profile_pkgs in seconds box, it is sorted and validated correctly 841 for i in range(0, len(self.profile_names.data)): 842 # If profile name is not set, then there should not be any packages in this profile 843 if not flask.request.form["profile_names-{}".format(i)]: 844 if [j for j in range(0, len(self.profile_names)) if "profile_pkgs-{}-{}".format(i, j) in flask.request.form]: 845 self.errors["profiles"] = ["Missing profile name"] 846 return False 847 return True851 owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()]) 852 copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()]) 853 name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()]) 854 stream = wtforms.StringField("Stream", validators=[wtforms.validators.DataRequired()]) 855 version = wtforms.IntegerField("Version", validators=[wtforms.validators.DataRequired()]) 856 arch = wtforms.StringField("Arch", validators=[wtforms.validators.DataRequired()])857
Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 | http://epydoc.sourceforge.net |