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 (scm/pypi/rubygems/git_and_tito/mock_scm) 28 29 Returns 30 ------- 31 BasePackageForm child 32 based on source_type_text input 33 """ 34 if source_type_text == 'scm': 35 return PackageFormScm 36 elif source_type_text == 'pypi': 37 return PackageFormPyPI 38 elif source_type_text == 'rubygems': 39 return PackageFormRubyGems 40 elif source_type_text == 'git_and_tito': 41 return PackageFormTito # deprecated 42 elif source_type_text == 'mock_scm': 43 return PackageFormMock # deprecated 44 else: 45 raise exceptions.UnknownSourceTypeException("Invalid source type")4649 widget = wtforms.widgets.ListWidget(prefix_label=False) 50 option_widget = wtforms.widgets.CheckboxInput()51547456 if not message: 57 message = ("A list of http[s] URLs separated by whitespace characters" 58 " is needed ('{0}' doesn't seem to be a valid URL).") 59 self.message = message6062 urls = field.data.split() 63 for u in urls: 64 if not self.is_url(u): 65 raise wtforms.ValidationError(self.message.format(u))6668 parsed = urlparse(url) 69 if not parsed.scheme.startswith("http"): 70 return False 71 if not parsed.netloc: 72 return False 73 return True77 """ Allows also `repo://` schema"""9379 parsed = urlparse(url) 80 if parsed.scheme not in ["http", "https", "copr"]: 81 return False 82 if not parsed.netloc: 83 return False 84 # copr://username/projectname 85 # ^^ schema ^^ netlock ^^ path 86 if parsed.scheme == "copr": 87 # check if projectname missed 88 path_split = parsed.path.split("/") 89 if len(path_split) < 2 or path_split[1] == "": 90 return False 91 92 return True10797 if not message: 98 message = ("URLs must end with .src.rpm, .nosrc.rpm, or .spec" 99 " ('{0}' doesn't seem to be a valid URL).") 100 super(UrlSrpmListValidator, self).__init__(message)101119111 if not message: 112 message = "You can upload only .src.rpm, .nosrc.rpm, and .spec files" 113 self.message = message114122145124 if not message: 125 if group is None: 126 message = "You already have project named '{}'." 127 else: 128 message = "Group {} ".format(group) + "already have project named '{}'." 129 self.message = message 130 if not user: 131 user = flask.g.user 132 self.user = user 133 self.group = group134136 if self.group: 137 existing = CoprsLogic.exists_for_group( 138 self.group, field.data).first() 139 else: 140 existing = CoprsLogic.exists_for_user( 141 self.user, field.data).first() 142 143 if existing and str(existing.id) != form.id.data: 144 raise wtforms.ValidationError(self.message.format(field.data))158149 if not message: 150 message = "Name must contain only letters, digits, underscores, dashes and dots." 151 self.message = message152170162 selected = set(field.data.split()) 163 enabled = set(self.chroots_list()) 164 165 if not (selected <= enabled): 166 raise wtforms.ValidationError("Such chroot is not enabled: {}".format(", ".join(selected - enabled)))167173182 199175 if not message: 176 message = "Project's name can not be just number." 177 self.message = message178202212204 if not value: 205 return '' 206 # Replace every whitespace string with one newline 207 # Formats ideally for html form filling, use replace('\n', ' ') 208 # to get space-separated values or split() to get list 209 result = value.strip() 210 regex = re.compile(r"\s+") 211 return regex.sub(lambda x: '\n', result)215220217 if value: 218 return helpers.PermissionEnum("request") 219 return helpers.PermissionEnum("nothing")223 224 @staticmethod294 295 def validate_mock_chroots_not_empty(self): 296 have_any = False 297 for c in self.chroots_list: 298 if getattr(self, c).data: 299 have_any = True 300 return have_any 301 302 F.chroots_list = list(map(lambda x: x.name, 303 models.MockChroot.query.filter( 304 models.MockChroot.is_active == True 305 ).all())) 306 F.chroots_list.sort() 307 # sets of chroots according to how we should print them in columns 308 F.chroots_sets = {} 309 for ch in F.chroots_list: 310 checkbox_default = False 311 if mock_chroots and ch in map(lambda x: x.name, 312 mock_chroots): 313 checkbox_default = True 314 315 setattr(F, ch, wtforms.BooleanField(ch, default=checkbox_default)) 316 if ch[0] in F.chroots_sets: 317 F.chroots_sets[ch[0]].append(ch) 318 else: 319 F.chroots_sets[ch[0]] = [ch] 320 321 return F 322226 class F(FlaskForm): 227 # also use id here, to be able to find out whether user 228 # is updating a copr if so, we don't want to shout 229 # that name already exists 230 id = wtforms.HiddenField() 231 group_id = wtforms.HiddenField() 232 233 name = wtforms.StringField( 234 "Name", 235 validators=[ 236 wtforms.validators.DataRequired(), 237 NameCharactersValidator(), 238 CoprUniqueNameValidator(user=user, group=group), 239 NameNotNumberValidator() 240 ]) 241 242 homepage = wtforms.StringField( 243 "Homepage", 244 validators=[ 245 wtforms.validators.Optional(), 246 wtforms.validators.URL()]) 247 248 contact = wtforms.StringField( 249 "Contact", 250 validators=[ 251 wtforms.validators.Optional(), 252 EmailOrURL()]) 253 254 description = wtforms.TextAreaField("Description") 255 256 instructions = wtforms.TextAreaField("Instructions") 257 258 repos = wtforms.TextAreaField( 259 "External Repositories", 260 validators=[UrlRepoListValidator()], 261 filters=[StringListFilter()]) 262 263 initial_pkgs = wtforms.TextAreaField( 264 "Initial packages to build", 265 validators=[ 266 UrlListValidator(), 267 UrlSrpmListValidator()], 268 filters=[StringListFilter()]) 269 270 disable_createrepo = wtforms.BooleanField(default=False) 271 build_enable_net = wtforms.BooleanField(default=False) 272 unlisted_on_hp = wtforms.BooleanField("Do not display this project on home page", default=False) 273 persistent = wtforms.BooleanField(default=False) 274 auto_prune = wtforms.BooleanField("If backend auto-prunning script should be run for this project", default=True) 275 use_bootstrap_container = wtforms.BooleanField("Enable use_bootstrap_container mock's feature (experimental)", default=False) 276 follow_fedora_branching = wtforms.BooleanField("If newly branched chroots should be automatically enabled and populated.", default=False) 277 278 @property 279 def selected_chroots(self): 280 selected = [] 281 for ch in self.chroots_list: 282 if getattr(self, ch).data: 283 selected.append(ch) 284 return selected285 286 def validate(self): 287 if not super(F, self).validate(): 288 return False 289 290 if not self.validate_mock_chroots_not_empty(): 291 self.errors["chroots"] = ["At least one chroot must be selected"] 292 return False 293 return True325 verify = wtforms.TextField( 326 "Confirm deleting by typing 'yes'", 327 validators=[ 328 wtforms.validators.Required(), 329 wtforms.validators.Regexp( 330 r"^yes$", 331 message="Type 'yes' - without the quotes, lowercase.") 332 ])333334 335 # @TODO jkadlcik - rewrite via BaseBuildFormFactory after fe-dev-cloud is back online 336 -class BuildFormRebuildFactory(object):337 @staticmethod365 366 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 367 F.chroots_list.sort() 368 F.chroots_sets = {} 369 for ch in F.chroots_list: 370 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 371 if ch[0] in F.chroots_sets: 372 F.chroots_sets[ch[0]].append(ch) 373 else: 374 F.chroots_sets[ch[0]] = [ch] 375 376 return F 377339 class F(FlaskForm): 340 @property 341 def selected_chroots(self): 342 selected = [] 343 for ch in self.chroots_list: 344 if getattr(self, ch).data: 345 selected.append(ch) 346 return selected347 348 memory_reqs = wtforms.IntegerField( 349 "Memory requirements", 350 validators=[ 351 wtforms.validators.NumberRange( 352 min=constants.MIN_BUILD_MEMORY, 353 max=constants.MAX_BUILD_MEMORY)], 354 default=constants.DEFAULT_BUILD_MEMORY) 355 356 timeout = wtforms.IntegerField( 357 "Timeout", 358 validators=[ 359 wtforms.validators.NumberRange( 360 min=constants.MIN_BUILD_TIMEOUT, 361 max=constants.MAX_BUILD_TIMEOUT)], 362 default=constants.DEFAULT_BUILD_TIMEOUT) 363 364 enable_net = wtforms.BooleanField()380 package_name = wtforms.StringField( 381 "Package name", 382 validators=[wtforms.validators.DataRequired()]) 383 webhook_rebuild = wtforms.BooleanField(default=False)384387 scm_type = wtforms.SelectField( 388 "Type", 389 choices=[("git", "Git"), ("svn", "SVN")]) 390 391 clone_url = wtforms.StringField( 392 "Clone url", 393 validators=[ 394 wtforms.validators.DataRequired(), 395 wtforms.validators.URL()]) 396 397 committish = wtforms.StringField( 398 "Committish", 399 validators=[ 400 wtforms.validators.Optional()]) 401 402 subdirectory = wtforms.StringField( 403 "Subdirectory", 404 validators=[ 405 wtforms.validators.Optional()]) 406 407 spec = wtforms.StringField( 408 "Spec File", 409 validators=[ 410 wtforms.validators.Optional(), 411 wtforms.validators.Regexp( 412 r"^.+\.spec$", 413 message="RPM spec file must end with .spec")]) 414 415 srpm_build_method = wtforms.StringField( 416 "SRPM build method", 417 validators=[ 418 wtforms.validators.DataRequired(), 419 wtforms.validators.AnyOf(["rpkg", "tito", "tito_test", "make_srpm"]) 420 ], 421 default='rpkg') 422 423 @property433425 return json.dumps({ 426 "type": self.scm_type.data, 427 "clone_url": self.clone_url.data, 428 "subdirectory": self.subdirectory.data, 429 "committish": self.committish.data, 430 "spec": self.spec.data, 431 "srpm_build_method": self.srpm_build_method.data, 432 })436 pypi_package_name = wtforms.StringField( 437 "PyPI package name", 438 validators=[wtforms.validators.DataRequired()]) 439 440 pypi_package_version = wtforms.StringField( 441 "PyPI package version", 442 validators=[ 443 wtforms.validators.Optional(), 444 ]) 445 446 python_versions = MultiCheckboxField( 447 'Build for Python', 448 choices=[ 449 ('3', 'python3'), 450 ('2', 'python2') 451 ], 452 default=['3', '2']) 453 454 @property461456 return json.dumps({ 457 "pypi_package_name": self.pypi_package_name.data, 458 "pypi_package_version": self.pypi_package_version.data, 459 "python_versions": self.python_versions.data 460 })464 gem_name = wtforms.StringField( 465 "Gem Name", 466 validators=[wtforms.validators.DataRequired()]) 467 468 @property473476 """ 477 @deprecated 478 """ 479 git_url = wtforms.StringField( 480 "Git URL", 481 validators=[ 482 wtforms.validators.DataRequired(), 483 wtforms.validators.URL()]) 484 485 git_directory = wtforms.StringField( 486 "Git Directory", 487 validators=[ 488 wtforms.validators.Optional()]) 489 490 git_branch = wtforms.StringField( 491 "Git Branch", 492 validators=[ 493 wtforms.validators.Optional()]) 494 495 tito_test = wtforms.BooleanField(default=False) 496 497 @property507499 return json.dumps({ 500 "type": 'git', 501 "clone_url": self.git_url.data, 502 "committish": self.git_branch.data, 503 "subdirectory": self.git_directory.data, 504 "spec": '', 505 "srpm_build_method": 'tito_test' if self.tito_test.data else 'tito', 506 })510 """ 511 @deprecated 512 """ 513 scm_type = wtforms.SelectField( 514 "SCM Type", 515 choices=[("git", "Git"), ("svn", "SVN")]) 516 517 scm_url = wtforms.StringField( 518 "SCM URL", 519 validators=[ 520 wtforms.validators.DataRequired(), 521 wtforms.validators.URL()]) 522 523 scm_branch = wtforms.StringField( 524 "Git Branch", 525 validators=[ 526 wtforms.validators.Optional()]) 527 528 scm_subdir = wtforms.StringField( 529 "Subdirectory", 530 validators=[ 531 wtforms.validators.Optional()]) 532 533 spec = wtforms.StringField( 534 "Spec File", 535 validators=[ 536 wtforms.validators.Optional(), 537 wtforms.validators.Regexp( 538 r"^.+\.spec$", 539 message="RPM spec file must end with .spec")]) 540 541 @property551543 return json.dumps({ 544 "type": self.scm_type.data, 545 "clone_url": self.scm_url.data, 546 "committish": self.scm_branch.data, 547 "subdirectory": self.scm_subdir.data, 548 "spec": self.spec.data, 549 "srpm_build_method": 'rpkg', 550 })554 """ 555 @deprecated 556 """ 557 clone_url = wtforms.StringField( 558 "Clone Url", 559 validators=[wtforms.validators.DataRequired()]) 560 561 branch = wtforms.StringField( 562 "Branch", 563 validators=[wtforms.validators.Optional()]) 564 565 @property575586579 form_cls = BaseBuildFormFactory(active_chroots, FlaskForm) 580 form_cls.packages = MultiCheckboxField( 581 "Packages", 582 choices=[(name, name) for name in package_names], 583 default=package_names, 584 validators=[wtforms.validators.DataRequired()]) 585 return form_cls598 599 F.memory_reqs = wtforms.IntegerField( 600 "Memory requirements", 601 validators=[ 602 wtforms.validators.Optional(), 603 wtforms.validators.NumberRange( 604 min=constants.MIN_BUILD_MEMORY, 605 max=constants.MAX_BUILD_MEMORY)], 606 default=constants.DEFAULT_BUILD_MEMORY) 607 608 F.timeout = wtforms.IntegerField( 609 "Timeout", 610 validators=[ 611 wtforms.validators.Optional(), 612 wtforms.validators.NumberRange( 613 min=constants.MIN_BUILD_TIMEOUT, 614 max=constants.MAX_BUILD_TIMEOUT)], 615 default=constants.DEFAULT_BUILD_TIMEOUT) 616 617 F.enable_net = wtforms.BooleanField() 618 F.background = wtforms.BooleanField(default=False) 619 620 # overrides BasePackageForm.package_name and is unused for building 621 F.package_name = wtforms.StringField() 622 623 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 624 F.chroots_list.sort() 625 F.chroots_sets = {} 626 for ch in F.chroots_list: 627 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 628 if ch[0] in F.chroots_sets: 629 F.chroots_sets[ch[0]].append(ch) 630 else: 631 F.chroots_sets[ch[0]] = [ch] 632 return F 633 638 646 654 659 664 669590 class F(form): 591 @property 592 def selected_chroots(self): 593 selected = [] 594 for ch in self.chroots_list: 595 if getattr(self, ch).data: 596 selected.append(ch) 597 return selected678673 form = BaseBuildFormFactory(active_chroots, FlaskForm) 674 form.pkgs = FileField('srpm', validators=[ 675 FileRequired(), 676 SrpmValidator()]) 677 return form691682 form = BaseBuildFormFactory(active_chroots, FlaskForm) 683 form.pkgs = wtforms.TextAreaField( 684 "Pkgs", 685 validators=[ 686 wtforms.validators.DataRequired(message="URLs to packages are required"), 687 UrlListValidator(), 688 UrlSrpmListValidator()], 689 filters=[StringListFilter()]) 690 return form694 modulemd = FileField("modulemd", validators=[ 695 FileRequired(), 696 # @TODO Validate modulemd.yaml file 697 ]) 698 699 create = wtforms.BooleanField("create", default=True) 700 build = wtforms.BooleanField("build", default=True)701704 modulemd = FileField("modulemd") 705 scmurl = wtforms.StringField() 706 branch = wtforms.StringField() 707 copr_owner = wtforms.StringField() 708 copr_project = wtforms.StringField()709712 713 """ 714 Validator for editing chroots in project 715 (adding packages to minimal chroot) 716 """ 717 718 buildroot_pkgs = wtforms.TextField( 719 "Packages") 720 721 repos = wtforms.TextAreaField('Repos', 722 validators=[UrlRepoListValidator(), 723 wtforms.validators.Optional()], 724 filters=[StringListFilter()]) 725 726 module_md = FileField("module_md") 727 728 comps = FileField("comps_xml")729732 comment = wtforms.TextAreaField("Comment")733736 737 @staticmethod 741 742 builder_default = False 743 admin_default = False 744 745 if permission: 746 if permission.copr_builder != helpers.PermissionEnum("nothing"): 747 builder_default = True 748 if permission.copr_admin != helpers.PermissionEnum("nothing"): 749 admin_default = True 750 751 setattr(F, "copr_builder", 752 wtforms.BooleanField( 753 default=builder_default, 754 filters=[ValueToPermissionNumberFilter()])) 755 756 setattr(F, "copr_admin", 757 wtforms.BooleanField( 758 default=admin_default, 759 filters=[ValueToPermissionNumberFilter()])) 760 761 return F762765 766 """Creates a dynamic form for given set of copr permissions""" 767 @staticmethod 771 772 for perm in permissions: 773 builder_choices = helpers.PermissionEnum.choices_list() 774 admin_choices = helpers.PermissionEnum.choices_list() 775 776 builder_default = perm.copr_builder 777 admin_default = perm.copr_admin 778 779 setattr(F, "copr_builder_{0}".format(perm.user.id), 780 wtforms.SelectField( 781 choices=builder_choices, 782 default=builder_default, 783 coerce=int)) 784 785 setattr(F, "copr_admin_{0}".format(perm.user.id), 786 wtforms.SelectField( 787 choices=admin_choices, 788 default=admin_default, 789 coerce=int)) 790 791 return F792795 description = wtforms.TextAreaField('Description', 796 validators=[wtforms.validators.Optional()]) 797 798 instructions = wtforms.TextAreaField('Instructions', 799 validators=[wtforms.validators.Optional()]) 800 801 chroots = wtforms.TextAreaField('Chroots', 802 validators=[wtforms.validators.Optional(), ChrootsValidator()]) 803 804 repos = wtforms.TextAreaField('Repos', 805 validators=[UrlRepoListValidator(), 806 wtforms.validators.Optional()], 807 filters=[StringListFilter()]) 808 809 disable_createrepo = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 810 unlisted_on_hp = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 811 build_enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 812 auto_prune = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 813 use_bootstrap_container = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 814 follow_fedora_branching = wtforms.BooleanField(validators=[wtforms.validators.Optional()])815818 @staticmethod840820 class F(FlaskForm): 821 source = wtforms.StringField( 822 "Source", 823 default=copr.full_name) 824 825 owner = wtforms.SelectField( 826 "Fork owner", 827 choices=[(user.name, user.name)] + [(g.at_name, g.at_name) for g in groups], 828 default=user.name, 829 validators=[wtforms.validators.DataRequired()]) 830 831 name = wtforms.StringField( 832 "Fork name", 833 default=copr.name, 834 validators=[wtforms.validators.DataRequired(), NameCharactersValidator()]) 835 836 confirm = wtforms.BooleanField( 837 "Confirm", 838 default=False)839 return F843 buildroot_pkgs = wtforms.TextField('Additional packages to be always present in minimal buildroot') 844 repos = wtforms.TextAreaField('Additional repos to be used for builds in chroot', 845 validators=[UrlRepoListValidator(), 846 wtforms.validators.Optional()], 847 filters=[StringListFilter()]) 848 upload_comps = FileField("Upload comps.xml") 849 delete_comps = wtforms.BooleanField("Delete comps.xml")850853 playground = wtforms.BooleanField("Playground")854857 project = wtforms.TextField("Project")858861870863 if not message: 864 message = "Group with the alias '{}' already exists." 865 self.message = message866868 if UsersLogic.group_alias_exists(field.data): 869 raise wtforms.ValidationError(self.message.format(field.data))873 874 name = wtforms.StringField( 875 validators=[ 876 wtforms.validators.Regexp( 877 re.compile(r"^[\w.-]+$"), 878 message="Name must contain only letters," 879 "digits, underscores, dashes and dots."), 880 GroupUniqueNameValidator() 881 ] 882 )883886 name = wtforms.StringField("Name") 887 stream = wtforms.StringField("Stream") 888 version = wtforms.IntegerField("Version") 889 builds = wtforms.FieldList(wtforms.StringField("Builds ID list")) 890 packages = wtforms.FieldList(wtforms.StringField("Packages list")) 891 filter = wtforms.FieldList(wtforms.StringField("Package Filter")) 892 api = wtforms.FieldList(wtforms.StringField("Module API")) 893 profile_names = wtforms.FieldList(wtforms.StringField("Install Profiles"), min_entries=2) 894 profile_pkgs = wtforms.FieldList(wtforms.FieldList(wtforms.StringField("Install Profiles")), min_entries=2) 895 899926901 if not FlaskForm.validate(self): 902 return False 903 904 module = ModulesLogic.get_by_nsv(self.copr, self.name.data, self.stream.data, self.version.data).first() 905 if module: 906 self.errors["nsv"] = [Markup("Module <a href='{}'>{}</a> already exists".format( 907 helpers.copr_url("coprs_ns.copr_module", module.copr, id=module.id), module.full_name))] 908 return False 909 910 # Profile names should be unique 911 names = filter(None, self.profile_names.data) 912 if len(set(names)) < len(names): 913 self.errors["profiles"] = ["Profile names must be unique"] 914 return False 915 916 # WORKAROUND 917 # profile_pkgs are somehow sorted so if I fill profile_name in the first box and 918 # profile_pkgs in seconds box, it is sorted and validated correctly 919 for i in range(0, len(self.profile_names.data)): 920 # If profile name is not set, then there should not be any packages in this profile 921 if not flask.request.form["profile_names-{}".format(i)]: 922 if [j for j in range(0, len(self.profile_names)) if "profile_pkgs-{}-{}".format(i, j) in flask.request.form]: 923 self.errors["profiles"] = ["Missing profile name"] 924 return False 925 return True929 owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()]) 930 copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()]) 931 name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()]) 932 stream = wtforms.StringField("Stream", validators=[wtforms.validators.DataRequired()]) 933 version = wtforms.IntegerField("Version", validators=[wtforms.validators.DataRequired()]) 934 arch = wtforms.StringField("Arch", validators=[wtforms.validators.DataRequired()])935
Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 | http://epydoc.sourceforge.net |