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 elif source_type_text == "custom": 45 return PackageFormCustom 46 else: 47 raise exceptions.UnknownSourceTypeException("Invalid source type")4851 widget = wtforms.widgets.ListWidget(prefix_label=False) 52 option_widget = wtforms.widgets.CheckboxInput()53567658 if not message: 59 message = ("A list of http[s] URLs separated by whitespace characters" 60 " is needed ('{0}' doesn't seem to be a valid URL).") 61 self.message = message6264 urls = field.data.split() 65 for u in urls: 66 if not self.is_url(u): 67 raise wtforms.ValidationError(self.message.format(u))6879 """ Allows also `repo://` schema"""9581 parsed = urlparse(url) 82 if parsed.scheme not in ["http", "https", "copr"]: 83 return False 84 if not parsed.netloc: 85 return False 86 # copr://username/projectname 87 # ^^ schema ^^ netlock ^^ path 88 if parsed.scheme == "copr": 89 # check if projectname missed 90 path_split = parsed.path.split("/") 91 if len(path_split) < 2 or path_split[1] == "": 92 return False 93 94 return True10999 if not message: 100 message = ("URLs must end with .src.rpm, .nosrc.rpm, or .spec" 101 " ('{0}' doesn't seem to be a valid URL).") 102 super(UrlSrpmListValidator, self).__init__(message)103121113 if not message: 114 message = "You can upload only .src.rpm, .nosrc.rpm, and .spec files" 115 self.message = message116124147126 if not message: 127 if group is None: 128 message = "You already have project named '{}'." 129 else: 130 message = "Group {} ".format(group) + "already have project named '{}'." 131 self.message = message 132 if not user: 133 user = flask.g.user 134 self.user = user 135 self.group = group136138 if self.group: 139 existing = CoprsLogic.exists_for_group( 140 self.group, field.data).first() 141 else: 142 existing = CoprsLogic.exists_for_user( 143 self.user, field.data).first() 144 145 if existing and str(existing.id) != form.id.data: 146 raise wtforms.ValidationError(self.message.format(field.data))160151 if not message: 152 message = "Name must contain only letters, digits, underscores, dashes and dots." 153 self.message = message154172164 selected = set(field.data.split()) 165 enabled = set(self.chroots_list()) 166 167 if not (selected <= enabled): 168 raise wtforms.ValidationError("Such chroot is not enabled: {}".format(", ".join(selected - enabled)))169175184 201177 if not message: 178 message = "Project's name can not be just number." 179 self.message = message180204214206 if not value: 207 return '' 208 # Replace every whitespace string with one newline 209 # Formats ideally for html form filling, use replace('\n', ' ') 210 # to get space-separated values or split() to get list 211 result = value.strip() 212 regex = re.compile(r"\s+") 213 return regex.sub(lambda x: '\n', result)217222219 if value: 220 return helpers.PermissionEnum("request") 221 return helpers.PermissionEnum("nothing")225 226 @staticmethod296 297 def validate_mock_chroots_not_empty(self): 298 have_any = False 299 for c in self.chroots_list: 300 if getattr(self, c).data: 301 have_any = True 302 return have_any 303 304 F.chroots_list = list(map(lambda x: x.name, 305 models.MockChroot.query.filter( 306 models.MockChroot.is_active == True 307 ).all())) 308 F.chroots_list.sort() 309 # sets of chroots according to how we should print them in columns 310 F.chroots_sets = {} 311 for ch in F.chroots_list: 312 checkbox_default = False 313 if mock_chroots and ch in map(lambda x: x.name, 314 mock_chroots): 315 checkbox_default = True 316 317 setattr(F, ch, wtforms.BooleanField(ch, default=checkbox_default)) 318 if ch[0] in F.chroots_sets: 319 F.chroots_sets[ch[0]].append(ch) 320 else: 321 F.chroots_sets[ch[0]] = [ch] 322 323 return F 324228 class F(FlaskForm): 229 # also use id here, to be able to find out whether user 230 # is updating a copr if so, we don't want to shout 231 # that name already exists 232 id = wtforms.HiddenField() 233 group_id = wtforms.HiddenField() 234 235 name = wtforms.StringField( 236 "Name", 237 validators=[ 238 wtforms.validators.DataRequired(), 239 NameCharactersValidator(), 240 CoprUniqueNameValidator(user=user, group=group), 241 NameNotNumberValidator() 242 ]) 243 244 homepage = wtforms.StringField( 245 "Homepage", 246 validators=[ 247 wtforms.validators.Optional(), 248 wtforms.validators.URL()]) 249 250 contact = wtforms.StringField( 251 "Contact", 252 validators=[ 253 wtforms.validators.Optional(), 254 EmailOrURL()]) 255 256 description = wtforms.TextAreaField("Description") 257 258 instructions = wtforms.TextAreaField("Instructions") 259 260 repos = wtforms.TextAreaField( 261 "External Repositories", 262 validators=[UrlRepoListValidator()], 263 filters=[StringListFilter()]) 264 265 initial_pkgs = wtforms.TextAreaField( 266 "Initial packages to build", 267 validators=[ 268 UrlListValidator(), 269 UrlSrpmListValidator()], 270 filters=[StringListFilter()]) 271 272 disable_createrepo = wtforms.BooleanField(default=False) 273 build_enable_net = wtforms.BooleanField(default=False) 274 unlisted_on_hp = wtforms.BooleanField("Do not display this project on home page", default=False) 275 persistent = wtforms.BooleanField(default=False) 276 auto_prune = wtforms.BooleanField("If backend auto-prunning script should be run for this project", default=True) 277 use_bootstrap_container = wtforms.BooleanField("Enable use_bootstrap_container mock's feature (experimental)", default=False) 278 follow_fedora_branching = wtforms.BooleanField("If newly branched chroots should be automatically enabled and populated.", default=False) 279 280 @property 281 def selected_chroots(self): 282 selected = [] 283 for ch in self.chroots_list: 284 if getattr(self, ch).data: 285 selected.append(ch) 286 return selected287 288 def validate(self): 289 if not super(F, self).validate(): 290 return False 291 292 if not self.validate_mock_chroots_not_empty(): 293 self.errors["chroots"] = ["At least one chroot must be selected"] 294 return False 295 return True327 verify = wtforms.TextField( 328 "Confirm deleting by typing 'yes'", 329 validators=[ 330 wtforms.validators.Required(), 331 wtforms.validators.Regexp( 332 r"^yes$", 333 message="Type 'yes' - without the quotes, lowercase.") 334 ])335336 337 # @TODO jkadlcik - rewrite via BaseBuildFormFactory after fe-dev-cloud is back online 338 -class BuildFormRebuildFactory(object):339 @staticmethod367 368 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 369 F.chroots_list.sort() 370 F.chroots_sets = {} 371 for ch in F.chroots_list: 372 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 373 if ch[0] in F.chroots_sets: 374 F.chroots_sets[ch[0]].append(ch) 375 else: 376 F.chroots_sets[ch[0]] = [ch] 377 378 return F 379341 class F(FlaskForm): 342 @property 343 def selected_chroots(self): 344 selected = [] 345 for ch in self.chroots_list: 346 if getattr(self, ch).data: 347 selected.append(ch) 348 return selected349 350 memory_reqs = wtforms.IntegerField( 351 "Memory requirements", 352 validators=[ 353 wtforms.validators.NumberRange( 354 min=constants.MIN_BUILD_MEMORY, 355 max=constants.MAX_BUILD_MEMORY)], 356 default=constants.DEFAULT_BUILD_MEMORY) 357 358 timeout = wtforms.IntegerField( 359 "Timeout", 360 validators=[ 361 wtforms.validators.NumberRange( 362 min=constants.MIN_BUILD_TIMEOUT, 363 max=constants.MAX_BUILD_TIMEOUT)], 364 default=constants.DEFAULT_BUILD_TIMEOUT) 365 366 enable_net = wtforms.BooleanField()382 package_name = wtforms.StringField( 383 "Package name", 384 validators=[wtforms.validators.DataRequired()]) 385 webhook_rebuild = wtforms.BooleanField(default=False)386389 scm_type = wtforms.SelectField( 390 "Type", 391 choices=[("git", "Git"), ("svn", "SVN")]) 392 393 clone_url = wtforms.StringField( 394 "Clone url", 395 validators=[ 396 wtforms.validators.DataRequired(), 397 wtforms.validators.URL()]) 398 399 committish = wtforms.StringField( 400 "Committish", 401 validators=[ 402 wtforms.validators.Optional()]) 403 404 subdirectory = wtforms.StringField( 405 "Subdirectory", 406 validators=[ 407 wtforms.validators.Optional()]) 408 409 spec = wtforms.StringField( 410 "Spec File", 411 validators=[ 412 wtforms.validators.Optional(), 413 wtforms.validators.Regexp( 414 r"^.+\.spec$", 415 message="RPM spec file must end with .spec")]) 416 417 srpm_build_method = wtforms.StringField( 418 "SRPM build method", 419 validators=[ 420 wtforms.validators.DataRequired(), 421 wtforms.validators.AnyOf(["rpkg", "tito", "tito_test", "make_srpm"]) 422 ], 423 default='rpkg') 424 425 @property435427 return json.dumps({ 428 "type": self.scm_type.data, 429 "clone_url": self.clone_url.data, 430 "subdirectory": self.subdirectory.data, 431 "committish": self.committish.data, 432 "spec": self.spec.data, 433 "srpm_build_method": self.srpm_build_method.data, 434 })438 pypi_package_name = wtforms.StringField( 439 "PyPI package name", 440 validators=[wtforms.validators.DataRequired()]) 441 442 pypi_package_version = wtforms.StringField( 443 "PyPI package version", 444 validators=[ 445 wtforms.validators.Optional(), 446 ]) 447 448 python_versions = MultiCheckboxField( 449 'Build for Python', 450 choices=[ 451 ('3', 'python3'), 452 ('2', 'python2') 453 ], 454 default=['3', '2']) 455 456 @property463458 return json.dumps({ 459 "pypi_package_name": self.pypi_package_name.data, 460 "pypi_package_version": self.pypi_package_version.data, 461 "python_versions": self.python_versions.data 462 })466 gem_name = wtforms.StringField( 467 "Gem Name", 468 validators=[wtforms.validators.DataRequired()]) 469 470 @property475478 """ 479 @deprecated 480 """ 481 git_url = wtforms.StringField( 482 "Git URL", 483 validators=[ 484 wtforms.validators.DataRequired(), 485 wtforms.validators.URL()]) 486 487 git_directory = wtforms.StringField( 488 "Git Directory", 489 validators=[ 490 wtforms.validators.Optional()]) 491 492 git_branch = wtforms.StringField( 493 "Git Branch", 494 validators=[ 495 wtforms.validators.Optional()]) 496 497 tito_test = wtforms.BooleanField(default=False) 498 499 @property509501 return json.dumps({ 502 "type": 'git', 503 "clone_url": self.git_url.data, 504 "committish": self.git_branch.data, 505 "subdirectory": self.git_directory.data, 506 "spec": '', 507 "srpm_build_method": 'tito_test' if self.tito_test.data else 'tito', 508 })512 """ 513 @deprecated 514 """ 515 scm_type = wtforms.SelectField( 516 "SCM Type", 517 choices=[("git", "Git"), ("svn", "SVN")]) 518 519 scm_url = wtforms.StringField( 520 "SCM URL", 521 validators=[ 522 wtforms.validators.DataRequired(), 523 wtforms.validators.URL()]) 524 525 scm_branch = wtforms.StringField( 526 "Git Branch", 527 validators=[ 528 wtforms.validators.Optional()]) 529 530 scm_subdir = wtforms.StringField( 531 "Subdirectory", 532 validators=[ 533 wtforms.validators.Optional()]) 534 535 spec = wtforms.StringField( 536 "Spec File", 537 validators=[ 538 wtforms.validators.Optional(), 539 wtforms.validators.Regexp( 540 r"^.+\.spec$", 541 message="RPM spec file must end with .spec")]) 542 543 @property553545 return json.dumps({ 546 "type": self.scm_type.data, 547 "clone_url": self.scm_url.data, 548 "committish": self.scm_branch.data, 549 "subdirectory": self.scm_subdir.data, 550 "spec": self.spec.data, 551 "srpm_build_method": 'rpkg', 552 })556 """ 557 @deprecated 558 """ 559 clone_url = wtforms.StringField( 560 "Clone Url", 561 validators=[wtforms.validators.DataRequired()]) 562 563 branch = wtforms.StringField( 564 "Branch", 565 validators=[wtforms.validators.Optional()]) 566 567 @property577580 script = wtforms.TextAreaField( 581 "Script", 582 validators=[ 583 wtforms.validators.DataRequired(), 584 wtforms.validators.Length( 585 max=4096, 586 message="Maximum script size is 4kB"), 587 ], 588 ) 589 590 builddeps = wtforms.StringField( 591 "Build dependencies", 592 validators=[wtforms.validators.Optional()]) 593 594 chroot = wtforms.SelectField( 595 'Mock chroot', 596 choices=[], 597 default='fedora-latest-x86_64', 598 ) 599 600 resultdir = wtforms.StringField( 601 "Result directory", 602 validators=[wtforms.validators.Optional()]) 603631605 super(PackageFormCustom, self).__init__(*args, **kwargs) 606 chroot_objects = models.MockChroot.query.filter(models.MockChroot.is_active).all() 607 608 chroots = [c.name for c in chroot_objects] 609 chroots.sort() 610 chroots = [(name, name) for name in chroots] 611 612 arches = set() 613 for ch in chroot_objects: 614 if ch.os_release == 'fedora': 615 arches.add(ch.arch) 616 617 self.chroot.choices = [] 618 if arches: 619 self.chroot.choices += [('fedora-latest-' + l, 'fedora-latest-' + l) for l in arches] 620 621 self.chroot.choices += chroots622 623 @property642635 form_cls = BaseBuildFormFactory(active_chroots, FlaskForm) 636 form_cls.packages = MultiCheckboxField( 637 "Packages", 638 choices=[(name, name) for name in package_names], 639 default=package_names, 640 validators=[wtforms.validators.DataRequired()]) 641 return form_cls654 655 F.memory_reqs = wtforms.IntegerField( 656 "Memory requirements", 657 validators=[ 658 wtforms.validators.Optional(), 659 wtforms.validators.NumberRange( 660 min=constants.MIN_BUILD_MEMORY, 661 max=constants.MAX_BUILD_MEMORY)], 662 default=constants.DEFAULT_BUILD_MEMORY) 663 664 F.timeout = wtforms.IntegerField( 665 "Timeout", 666 validators=[ 667 wtforms.validators.Optional(), 668 wtforms.validators.NumberRange( 669 min=constants.MIN_BUILD_TIMEOUT, 670 max=constants.MAX_BUILD_TIMEOUT)], 671 default=constants.DEFAULT_BUILD_TIMEOUT) 672 673 F.enable_net = wtforms.BooleanField() 674 F.background = wtforms.BooleanField(default=False) 675 676 # overrides BasePackageForm.package_name and is unused for building 677 F.package_name = wtforms.StringField() 678 679 F.chroots_list = list(map(lambda x: x.name, active_chroots)) 680 F.chroots_list.sort() 681 F.chroots_sets = {} 682 for ch in F.chroots_list: 683 setattr(F, ch, wtforms.BooleanField(ch, default=True)) 684 if ch[0] in F.chroots_sets: 685 F.chroots_sets[ch[0]].append(ch) 686 else: 687 F.chroots_sets[ch[0]] = [ch] 688 return F 689 694 702 710 715 720 725646 class F(form): 647 @property 648 def selected_chroots(self): 649 selected = [] 650 for ch in self.chroots_list: 651 if getattr(self, ch).data: 652 selected.append(ch) 653 return selected734 739729 form = BaseBuildFormFactory(active_chroots, FlaskForm) 730 form.pkgs = FileField('srpm', validators=[ 731 FileRequired(), 732 SrpmValidator()]) 733 return form752743 form = BaseBuildFormFactory(active_chroots, FlaskForm) 744 form.pkgs = wtforms.TextAreaField( 745 "Pkgs", 746 validators=[ 747 wtforms.validators.DataRequired(message="URLs to packages are required"), 748 UrlListValidator(), 749 UrlSrpmListValidator()], 750 filters=[StringListFilter()]) 751 return form755 modulemd = FileField("modulemd", validators=[ 756 FileRequired(), 757 # @TODO Validate modulemd.yaml file 758 ]) 759 760 create = wtforms.BooleanField("create", default=True) 761 build = wtforms.BooleanField("build", default=True)762765 modulemd = FileField("modulemd") 766 scmurl = wtforms.StringField() 767 branch = wtforms.StringField()768771 772 """ 773 Validator for editing chroots in project 774 (adding packages to minimal chroot) 775 """ 776 777 buildroot_pkgs = wtforms.TextField( 778 "Packages") 779 780 repos = wtforms.TextAreaField('Repos', 781 validators=[UrlRepoListValidator(), 782 wtforms.validators.Optional()], 783 filters=[StringListFilter()]) 784 785 module_md = FileField("module_md") 786 787 comps = FileField("comps_xml")788791 comment = wtforms.TextAreaField("Comment")792795 796 @staticmethod 800 801 builder_default = False 802 admin_default = False 803 804 if permission: 805 if permission.copr_builder != helpers.PermissionEnum("nothing"): 806 builder_default = True 807 if permission.copr_admin != helpers.PermissionEnum("nothing"): 808 admin_default = True 809 810 setattr(F, "copr_builder", 811 wtforms.BooleanField( 812 default=builder_default, 813 filters=[ValueToPermissionNumberFilter()])) 814 815 setattr(F, "copr_admin", 816 wtforms.BooleanField( 817 default=admin_default, 818 filters=[ValueToPermissionNumberFilter()])) 819 820 return F821824 825 """Creates a dynamic form for given set of copr permissions""" 826 @staticmethod 830 831 for perm in permissions: 832 builder_choices = helpers.PermissionEnum.choices_list() 833 admin_choices = helpers.PermissionEnum.choices_list() 834 835 builder_default = perm.copr_builder 836 admin_default = perm.copr_admin 837 838 setattr(F, "copr_builder_{0}".format(perm.user.id), 839 wtforms.SelectField( 840 choices=builder_choices, 841 default=builder_default, 842 coerce=int)) 843 844 setattr(F, "copr_admin_{0}".format(perm.user.id), 845 wtforms.SelectField( 846 choices=admin_choices, 847 default=admin_default, 848 coerce=int)) 849 850 return F851854 description = wtforms.TextAreaField('Description', 855 validators=[wtforms.validators.Optional()]) 856 857 instructions = wtforms.TextAreaField('Instructions', 858 validators=[wtforms.validators.Optional()]) 859 860 chroots = wtforms.TextAreaField('Chroots', 861 validators=[wtforms.validators.Optional(), ChrootsValidator()]) 862 863 repos = wtforms.TextAreaField('Repos', 864 validators=[UrlRepoListValidator(), 865 wtforms.validators.Optional()], 866 filters=[StringListFilter()]) 867 868 disable_createrepo = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 869 unlisted_on_hp = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 870 build_enable_net = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 871 auto_prune = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 872 use_bootstrap_container = wtforms.BooleanField(validators=[wtforms.validators.Optional()]) 873 follow_fedora_branching = wtforms.BooleanField(validators=[wtforms.validators.Optional()])874877 @staticmethod899879 class F(FlaskForm): 880 source = wtforms.StringField( 881 "Source", 882 default=copr.full_name) 883 884 owner = wtforms.SelectField( 885 "Fork owner", 886 choices=[(user.name, user.name)] + [(g.at_name, g.at_name) for g in groups], 887 default=user.name, 888 validators=[wtforms.validators.DataRequired()]) 889 890 name = wtforms.StringField( 891 "Fork name", 892 default=copr.name, 893 validators=[wtforms.validators.DataRequired(), NameCharactersValidator()]) 894 895 confirm = wtforms.BooleanField( 896 "Confirm", 897 default=False)898 return F902 buildroot_pkgs = wtforms.TextField('Additional packages to be always present in minimal buildroot') 903 repos = wtforms.TextAreaField('Additional repos to be used for builds in chroot', 904 validators=[UrlRepoListValidator(), 905 wtforms.validators.Optional()], 906 filters=[StringListFilter()]) 907 upload_comps = FileField("Upload comps.xml") 908 delete_comps = wtforms.BooleanField("Delete comps.xml")909912 playground = wtforms.BooleanField("Playground")913916 project = wtforms.TextField("Project")917920929922 if not message: 923 message = "Group with the alias '{}' already exists." 924 self.message = message925927 if UsersLogic.group_alias_exists(field.data): 928 raise wtforms.ValidationError(self.message.format(field.data))932 933 name = wtforms.StringField( 934 validators=[ 935 wtforms.validators.Regexp( 936 re.compile(r"^[\w.-]+$"), 937 message="Name must contain only letters," 938 "digits, underscores, dashes and dots."), 939 GroupUniqueNameValidator() 940 ] 941 )942945 builds = wtforms.FieldList(wtforms.StringField("Builds ID list")) 946 packages = wtforms.FieldList(wtforms.StringField("Packages list")) 947 filter = wtforms.FieldList(wtforms.StringField("Package Filter")) 948 api = wtforms.FieldList(wtforms.StringField("Module API")) 949 profile_names = wtforms.FieldList(wtforms.StringField("Install Profiles"), min_entries=2) 950 profile_pkgs = wtforms.FieldList(wtforms.FieldList(wtforms.StringField("Install Profiles")), min_entries=2) 951 955976957 if not FlaskForm.validate(self): 958 return False 959 960 # Profile names should be unique 961 names = [x for x in self.profile_names.data if x] 962 if len(set(names)) < len(names): 963 self.errors["profiles"] = ["Profile names must be unique"] 964 return False 965 966 # WORKAROUND 967 # profile_pkgs are somehow sorted so if I fill profile_name in the first box and 968 # profile_pkgs in seconds box, it is sorted and validated correctly 969 for i in range(0, len(self.profile_names.data)): 970 # If profile name is not set, then there should not be any packages in this profile 971 if not flask.request.form["profile_names-{}".format(i)]: 972 if [j for j in range(0, len(self.profile_names)) if "profile_pkgs-{}-{}".format(i, j) in flask.request.form]: 973 self.errors["profiles"] = ["Missing profile name"] 974 return False 975 return True979 owner = wtforms.StringField("Owner Name", validators=[wtforms.validators.DataRequired()]) 980 copr = wtforms.StringField("Copr Name", validators=[wtforms.validators.DataRequired()]) 981 name = wtforms.StringField("Name", validators=[wtforms.validators.DataRequired()]) 982 stream = wtforms.StringField("Stream", validators=[wtforms.validators.DataRequired()]) 983 version = wtforms.IntegerField("Version", validators=[wtforms.validators.DataRequired()]) 984 arch = wtforms.StringField("Arch", validators=[wtforms.validators.DataRequired()])985
Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 | http://epydoc.sourceforge.net |