Package coprs :: Package logic :: Module coprs_logic
[hide private]
[frames] | no frames]

Source Code for Module coprs.logic.coprs_logic

  1  import os 
  2  import time 
  3   
  4  from sqlalchemy import and_ 
  5  from sqlalchemy.sql import func 
  6  from sqlalchemy import asc 
  7  from sqlalchemy.event import listen 
  8  from sqlalchemy.orm.attributes import NEVER_SET 
  9  from sqlalchemy.orm.exc import NoResultFound 
 10  from sqlalchemy.orm.attributes import get_history 
 11   
 12  from coprs import db 
 13  from coprs import exceptions 
 14  from coprs import helpers 
 15  from coprs import models 
 16  from coprs.exceptions import MalformedArgumentException 
 17  from coprs.logic import users_logic 
 18  from coprs.whoosheers import CoprWhoosheer 
 19  from coprs.helpers import fix_protocol_for_backend 
 20   
 21  from coprs.logic.actions_logic import ActionsLogic 
 22  from coprs.logic.users_logic import UsersLogic 
23 24 25 -class CoprsLogic(object):
26 """ 27 Used for manipulating Coprs. 28 29 All methods accept user object as a first argument, 30 as this may be needed in future. 31 """ 32 33 @classmethod
34 - def get_all(cls):
35 """ Return all coprs without those which are deleted. """ 36 query = (db.session.query(models.Copr) 37 .join(models.Copr.user) 38 .options(db.contains_eager(models.Copr.user)) 39 .filter(models.Copr.deleted == False)) 40 return query
41 42 @classmethod
43 - def get_by_id(cls, copr_id):
44 return cls.get_all().filter(models.Copr.id == copr_id)
45 46 @classmethod
47 - def attach_build(cls, query):
48 query = (query.outerjoin(models.Copr.builds) 49 .options(db.contains_eager(models.Copr.builds)) 50 .order_by(models.Build.submitted_on.desc())) 51 return query
52 53 @classmethod
54 - def attach_mock_chroots(cls, query):
55 query = (query.outerjoin(*models.Copr.mock_chroots.attr) 56 .options(db.contains_eager(*models.Copr.mock_chroots.attr)) 57 .order_by(models.MockChroot.os_release.asc()) 58 .order_by(models.MockChroot.os_version.asc()) 59 .order_by(models.MockChroot.arch.asc())) 60 return query
61 62 @classmethod
63 - def get_multiple_by_username(cls, username, **kwargs):
64 with_builds = kwargs.get("with_builds", False) 65 with_mock_chroots = kwargs.get("with_mock_chroots", False) 66 67 query = ( 68 cls.get_all() 69 .filter(models.User.username == username) 70 ) 71 72 if with_builds: 73 query = cls.attach_build(query) 74 75 if with_mock_chroots: 76 query = cls.attach_mock_chroots(query) 77 78 return query
79 80 @classmethod
81 - def get_multiple_by_group_id(cls, group_id, **kwargs):
82 with_builds = kwargs.get("with_builds", False) 83 with_mock_chroots = kwargs.get("with_mock_chroots", False) 84 85 query = ( 86 cls.get_all() 87 .filter(models.Copr.group_id == group_id) 88 ) 89 90 if with_builds: 91 query = cls.attach_build(query) 92 93 if with_mock_chroots: 94 query = cls.attach_mock_chroots(query) 95 96 return query
97 98 @classmethod
99 - def get(cls, username, coprname, **kwargs):
100 query = cls.get_multiple_by_username(username, **kwargs) 101 query = query.filter(models.Copr.name == coprname) 102 return query
103 104 @classmethod
105 - def get_by_group_id(cls, group_id, coprname, **kwargs):
106 query = cls.get_multiple_by_group_id(group_id, **kwargs) 107 query = query.filter(models.Copr.name == coprname) 108 return query
109 110 @classmethod
111 - def get_multiple(cls, include_deleted=False, include_unlisted_on_hp=True):
112 query = ( 113 db.session.query(models.Copr) 114 .join(models.Copr.user) 115 .outerjoin(models.Group) 116 .options(db.contains_eager(models.Copr.user)) 117 ) 118 119 if not include_deleted: 120 query = query.filter(models.Copr.deleted.is_(False)) 121 122 if not include_unlisted_on_hp: 123 query = query.filter(models.Copr.unlisted_on_hp.is_(False)) 124 125 return query
126 127 @classmethod
128 - def set_query_order(cls, query, desc=False):
129 if desc: 130 query = query.order_by(models.Copr.id.desc()) 131 else: 132 query = query.order_by(models.Copr.id.asc()) 133 return query
134 135 # user_relation="owned", username=username, with_mock_chroots=False 136 @classmethod
137 - def get_multiple_owned_by_username(cls, username):
138 query = cls.get_multiple() 139 return query.filter(models.User.username == username)
140 141 @classmethod
142 - def filter_by_name(cls, query, name):
143 return query.filter(models.Copr.name == name)
144 145 @classmethod
146 - def filter_by_user_name(cls, query, username):
147 # should be already joined with the User table 148 return query.filter(models.User.username == username)
149 150 @classmethod
151 - def filter_by_group_name(cls, query, group_name):
152 # should be already joined with the Group table 153 return query.filter(models.Group.name == group_name)
154 155 @classmethod
156 - def filter_without_group_projects(cls, query):
157 return query.filter(models.Copr.group_id.is_(None))
158 159 @classmethod
160 - def join_builds(cls, query):
161 return (query.outerjoin(models.Copr.builds) 162 .options(db.contains_eager(models.Copr.builds)) 163 .order_by(models.Build.submitted_on.desc()))
164 165 @classmethod
166 - def join_mock_chroots(cls, query):
167 return (query.outerjoin(*models.Copr.mock_chroots.attr) 168 .options(db.contains_eager(*models.Copr.mock_chroots.attr)) 169 .order_by(models.MockChroot.os_release.asc()) 170 .order_by(models.MockChroot.os_version.asc()) 171 .order_by(models.MockChroot.arch.asc()))
172 173 @classmethod
174 - def get_playground(cls):
175 return cls.get_all().filter(models.Copr.playground == True)
176 177 @classmethod
178 - def set_playground(cls, user, copr):
179 if user.admin: 180 db.session.add(copr) 181 pass 182 else: 183 raise exceptions.InsufficientRightsException( 184 "User is not a system admin")
185 186 @classmethod
187 - def get_multiple_fulltext(cls, search_string):
188 query = (models.Copr.query.join(models.User) 189 .filter(models.Copr.deleted == False)) 190 if "/" in search_string: # copr search by its full name 191 if search_string[0] == '@': # searching for @group/project 192 group_name = "%{}%".format(search_string.split("/")[0][1:]) 193 project = "%{}%".format(search_string.split("/")[1]) 194 query = query.filter(and_(models.Group.name.ilike(group_name), 195 models.Copr.name.ilike(project), 196 models.Group.id == models.Copr.group_id)) 197 query = query.order_by(asc(func.length(models.Group.name)+func.length(models.Copr.name))) 198 else: # searching for user/project 199 user_name = "%{}%".format(search_string.split("/")[0]) 200 project = "%{}%".format(search_string.split("/")[1]) 201 query = query.filter(and_(models.User.username.ilike(user_name), 202 models.Copr.name.ilike(project), 203 models.User.id == models.Copr.user_id)) 204 query = query.order_by(asc(func.length(models.User.username)+func.length(models.Copr.name))) 205 else: # fulltext search 206 query = query.whooshee_search(search_string, whoosheer=CoprWhoosheer) 207 return query
208 209 @classmethod
210 - def add(cls, user, name, selected_chroots, repos=None, description=None, 211 instructions=None, check_for_duplicates=False, group=None, persistent=False, 212 auto_prune=True, use_bootstrap_container=False, follow_fedora_branching=False, **kwargs):
213 214 if not user.admin and persistent: 215 raise exceptions.NonAdminCannotCreatePersistentProject() 216 217 if not user.admin and not auto_prune: 218 raise exceptions.NonAdminCannotDisableAutoPrunning() 219 220 # form validation checks for duplicates 221 cls.new(user, name, group, check_for_duplicates=check_for_duplicates) 222 223 copr = models.Copr(name=name, 224 repos=repos or u"", 225 user=user, 226 description=description or u"", 227 instructions=instructions or u"", 228 created_on=int(time.time()), 229 persistent=persistent, 230 auto_prune=auto_prune, 231 use_bootstrap_container=use_bootstrap_container, 232 follow_fedora_branching=follow_fedora_branching, 233 **kwargs) 234 235 236 if group is not None: 237 UsersLogic.raise_if_not_in_group(user, group) 238 copr.group = group 239 240 copr_dir = models.CoprDir( 241 main=True, 242 name=name, 243 copr=copr) 244 245 db.session.add(copr_dir) 246 db.session.add(copr) 247 248 CoprChrootsLogic.new_from_names( 249 copr, selected_chroots) 250 251 db.session.flush() 252 ActionsLogic.send_create_gpg_key(copr) 253 254 return copr
255 256 @classmethod
257 - def new(cls, user, copr_name, group=None, check_for_duplicates=True):
258 if check_for_duplicates: 259 if group is None and cls.exists_for_user(user, copr_name).all(): 260 raise exceptions.DuplicateException( 261 "Copr: '{0}/{1}' already exists".format(user.name, copr_name)) 262 elif group: 263 if cls.exists_for_group(group, copr_name).all(): 264 db.session.rollback() 265 raise exceptions.DuplicateException( 266 "Copr: '@{0}/{1}' already exists".format(group.name, copr_name))
267 268 @classmethod
269 - def update(cls, user, copr):
270 # we should call get_history before other requests, otherwise 271 # the changes would be forgotten 272 if get_history(copr, "name").has_changes(): 273 raise MalformedArgumentException("Change name of the project is forbidden") 274 275 users_logic.UsersLogic.raise_if_cant_update_copr( 276 user, copr, "Only owners and admins may update their projects.") 277 278 if not user.admin and not copr.auto_prune: 279 raise exceptions.NonAdminCannotDisableAutoPrunning() 280 281 db.session.add(copr)
282 283 @classmethod
284 - def delete_unsafe(cls, user, copr):
285 """ 286 Deletes copr without termination of ongoing builds. 287 """ 288 cls.raise_if_cant_delete(user, copr) 289 # TODO: do we want to dump the information somewhere, so that we can 290 # search it in future? 291 cls.raise_if_unfinished_blocking_action( 292 copr, "Can't delete this project," 293 " another operation is in progress: {action}") 294 295 ActionsLogic.send_delete_copr(copr) 296 CoprDirsLogic.delete_all_by_copr(copr) 297 298 copr.deleted = True 299 return copr
300 301 @classmethod
302 - def exists_for_user(cls, user, coprname, incl_deleted=False):
303 existing = (models.Copr.query 304 .filter(models.Copr.name == coprname) 305 .filter(models.Copr.user_id == user.id)) 306 307 if not incl_deleted: 308 existing = existing.filter(models.Copr.deleted == False) 309 310 return cls.filter_without_group_projects(existing)
311 312 @classmethod
313 - def exists_for_group(cls, group, coprname, incl_deleted=False):
314 existing = (models.Copr.query 315 .filter(models.Copr.name == coprname) 316 .filter(models.Copr.group_id == group.id)) 317 318 if not incl_deleted: 319 existing = existing.filter(models.Copr.deleted == False) 320 321 return existing
322 323 @classmethod
324 - def unfinished_blocking_actions_for(cls, copr):
325 blocking_actions = [helpers.ActionTypeEnum("delete")] 326 327 actions = (models.Action.query 328 .filter(models.Action.object_type == "copr") 329 .filter(models.Action.object_id == copr.id) 330 .filter(models.Action.result == 331 helpers.BackendResultEnum("waiting")) 332 .filter(models.Action.action_type.in_(blocking_actions))) 333 334 return actions
335 336 @classmethod
337 - def get_yum_repos(cls, copr, empty=False):
338 repos = {} 339 release_tmpl = "{chroot.os_release}-{chroot.os_version}-{chroot.arch}" 340 build = models.Build.query.filter(models.Build.copr_id == copr.id).first() 341 if build or empty: 342 for chroot in copr.active_chroots: 343 release = release_tmpl.format(chroot=chroot) 344 repos[release] = fix_protocol_for_backend( 345 os.path.join(copr.repo_url, release + '/')) 346 return repos
347 348 @classmethod
349 - def raise_if_unfinished_blocking_action(cls, copr, message):
350 """ 351 Raise ActionInProgressException if given copr has an unfinished 352 action. Return None otherwise. 353 """ 354 355 unfinished_actions = cls.unfinished_blocking_actions_for(copr).all() 356 if unfinished_actions: 357 raise exceptions.ActionInProgressException( 358 message, unfinished_actions[0])
359 360 @classmethod
361 - def raise_if_cant_delete(cls, user, copr):
362 """ 363 Raise InsufficientRightsException if given copr cant be deleted 364 by given user. Return None otherwise. 365 """ 366 367 if not user.admin and user != copr.user: 368 raise exceptions.InsufficientRightsException( 369 "Only owners may delete their projects.")
370
371 372 -class CoprPermissionsLogic(object):
373 @classmethod
374 - def get(cls, copr, searched_user):
375 query = (models.CoprPermission.query 376 .filter(models.CoprPermission.copr == copr) 377 .filter(models.CoprPermission.user == searched_user)) 378 379 return query
380 381 @classmethod
382 - def get_for_copr(cls, copr):
383 query = models.CoprPermission.query.filter( 384 models.CoprPermission.copr == copr) 385 386 return query
387 388 @classmethod
389 - def new(cls, copr_permission):
390 db.session.add(copr_permission)
391 392 @classmethod
393 - def update_permissions(cls, user, copr, copr_permission, 394 new_builder, new_admin):
395 396 users_logic.UsersLogic.raise_if_cant_update_copr( 397 user, copr, "Only owners and admins may update" 398 " their projects permissions.") 399 400 (models.CoprPermission.query 401 .filter(models.CoprPermission.copr_id == copr.id) 402 .filter(models.CoprPermission.user_id == copr_permission.user_id) 403 .update({"copr_builder": new_builder, 404 "copr_admin": new_admin}))
405 406 @classmethod
407 - def update_permissions_by_applier(cls, user, copr, copr_permission, new_builder, new_admin):
408 if copr_permission: 409 # preserve approved permissions if set 410 if (not new_builder or 411 copr_permission.copr_builder != helpers.PermissionEnum("approved")): 412 413 copr_permission.copr_builder = new_builder 414 415 if (not new_admin or 416 copr_permission.copr_admin != helpers.PermissionEnum("approved")): 417 418 copr_permission.copr_admin = new_admin 419 else: 420 perm = models.CoprPermission( 421 user=user, 422 copr=copr, 423 copr_builder=new_builder, 424 copr_admin=new_admin) 425 426 cls.new(perm)
427 428 @classmethod
429 - def delete(cls, copr_permission):
430 db.session.delete(copr_permission)
431
432 433 -class CoprDirsLogic(object):
434 @classmethod
435 - def get_or_create(cls, copr, dirname, main=False):
436 copr_dir = cls.get_by_copr(copr, dirname).first() 437 438 if copr_dir: 439 return copr_dir 440 441 copr_dir = models.CoprDir( 442 name=dirname, copr=copr, main=main) 443 444 db.session.add(copr_dir) 445 return copr_dir
446 447 @classmethod
448 - def get_by_copr(cls, copr, dirname):
449 return (db.session.query(models.CoprDir) 450 .join(models.Copr) 451 .filter(models.Copr.id==copr.id) 452 .filter(models.CoprDir.name==dirname))
453 454 @classmethod
455 - def get_by_ownername(cls, ownername, dirname):
456 return (db.session.query(models.CoprDir) 457 .filter(models.CoprDir.name==dirname) 458 .filter(models.CoprDir.ownername==ownername))
459 460 @classmethod
461 - def delete(cls, copr_dir):
462 db.session.delete(copr_dir)
463 464 @classmethod
465 - def delete_all_by_copr(cls, copr):
466 for copr_dir in copr.dirs: 467 db.session.delete(copr_dir)
468
469 470 -def on_auto_createrepo_change(target_copr, value_acr, old_value_acr, initiator):
471 """ Emit createrepo action when auto_createrepo re-enabled""" 472 if old_value_acr == NEVER_SET: 473 # created new copr, not interesting 474 return 475 if not old_value_acr and value_acr: 476 # re-enabled 477 ActionsLogic.send_createrepo(target_copr)
478 479 480 listen(models.Copr.auto_createrepo, 'set', on_auto_createrepo_change, 481 active_history=True, retval=False)
482 483 484 -class BranchesLogic(object):
485 @classmethod
486 - def get_or_create(cls, name, session=db.session):
487 item = session.query(models.DistGitBranch).filter_by(name=name).first() 488 if item: 489 return item 490 491 branch = models.DistGitBranch() 492 branch.name = name 493 session.add(branch) 494 return branch
495
496 497 -class CoprChrootsLogic(object):
498 @classmethod
499 - def mock_chroots_from_names(cls, names):
500 501 db_chroots = models.MockChroot.query.all() 502 mock_chroots = [] 503 for ch in db_chroots: 504 if ch.name in names: 505 mock_chroots.append(ch) 506 507 return mock_chroots
508 509 @classmethod
510 - def get_by_name(cls, copr, chroot_name):
511 mc = MockChrootsLogic.get_from_name(chroot_name, active_only=True).one() 512 query = ( 513 models.CoprChroot.query.join(models.MockChroot) 514 .filter(models.CoprChroot.copr_id == copr.id) 515 .filter(models.MockChroot.id == mc.id) 516 ) 517 return query
518 519 @classmethod
520 - def get_by_name_safe(cls, copr, chroot_name):
521 """ 522 :rtype: models.CoprChroot 523 """ 524 try: 525 return cls.get_by_name(copr, chroot_name).one() 526 except NoResultFound: 527 return None
528 529 @classmethod
530 - def new(cls, mock_chroot):
531 db.session.add(mock_chroot)
532 533 @classmethod
534 - def new_from_names(cls, copr, names):
538 539 @classmethod
540 - def create_chroot(cls, user, copr, mock_chroot, 541 buildroot_pkgs=None, repos=None, comps=None, comps_name=None, module_md=None, module_md_name=None, with_opts="", without_opts=""):
542 """ 543 :type user: models.User 544 :type mock_chroot: models.MockChroot 545 """ 546 if buildroot_pkgs is None: 547 buildroot_pkgs = "" 548 if repos is None: 549 repos = "" 550 UsersLogic.raise_if_cant_update_copr( 551 user, copr, 552 "Only owners and admins may update their projects.") 553 554 chroot = models.CoprChroot(copr=copr, mock_chroot=mock_chroot) 555 cls._update_chroot(buildroot_pkgs, repos, comps, comps_name, module_md, module_md_name, chroot, with_opts, without_opts) 556 return chroot
557 558 @classmethod
559 - def update_chroot(cls, user, copr_chroot, 560 buildroot_pkgs=None, repos=None, comps=None, comps_name=None, module_md=None, module_md_name=None, with_opts="", without_opts=""):
561 """ 562 :type user: models.User 563 :type copr_chroot: models.CoprChroot 564 """ 565 UsersLogic.raise_if_cant_update_copr( 566 user, copr_chroot.copr, 567 "Only owners and admins may update their projects.") 568 569 cls._update_chroot(buildroot_pkgs, repos, comps, comps_name, module_md, module_md_name, copr_chroot, with_opts, without_opts) 570 return copr_chroot
571 572 @classmethod
573 - def _update_chroot(cls, buildroot_pkgs, repos, comps, comps_name, module_md, module_md_name, copr_chroot, with_opts, without_opts):
574 if buildroot_pkgs is not None: 575 copr_chroot.buildroot_pkgs = buildroot_pkgs 576 577 if repos is not None: 578 copr_chroot.repos = repos.replace("\n", " ") 579 580 if with_opts is not None: 581 copr_chroot.with_opts = with_opts 582 583 if without_opts is not None: 584 copr_chroot.without_opts = without_opts 585 586 if comps_name is not None: 587 copr_chroot.update_comps(comps) 588 copr_chroot.comps_name = comps_name 589 ActionsLogic.send_update_comps(copr_chroot) 590 591 if module_md_name is not None: 592 copr_chroot.update_module_md(module_md) 593 copr_chroot.module_md_name = module_md_name 594 ActionsLogic.send_update_module_md(copr_chroot) 595 596 db.session.add(copr_chroot)
597 598 @classmethod
599 - def update_from_names(cls, user, copr, names):
600 UsersLogic.raise_if_cant_update_copr( 601 user, copr, 602 "Only owners and admins may update their projects.") 603 current_chroots = copr.mock_chroots 604 new_chroots = cls.mock_chroots_from_names(names) 605 # add non-existing 606 for mock_chroot in new_chroots: 607 if mock_chroot not in current_chroots: 608 db.session.add( 609 models.CoprChroot(copr=copr, mock_chroot=mock_chroot)) 610 611 # delete no more present 612 to_remove = [] 613 for mock_chroot in current_chroots: 614 if mock_chroot not in new_chroots: 615 # can't delete here, it would change current_chroots and break 616 # iteration 617 to_remove.append(mock_chroot) 618 619 for mc in to_remove: 620 copr.mock_chroots.remove(mc)
621 622 @classmethod
623 - def remove_comps(cls, user, copr_chroot):
624 UsersLogic.raise_if_cant_update_copr( 625 user, copr_chroot.copr, 626 "Only owners and admins may update their projects.") 627 628 copr_chroot.comps_name = None 629 copr_chroot.comps_zlib = None 630 ActionsLogic.send_update_comps(copr_chroot) 631 db.session.add(copr_chroot)
632 633 @classmethod
634 - def remove_module_md(cls, user, copr_chroot):
635 UsersLogic.raise_if_cant_update_copr( 636 user, copr_chroot.copr, 637 "Only owners and admins may update their projects.") 638 639 copr_chroot.module_md_name = None 640 copr_chroot.module_md_zlib = None 641 ActionsLogic.send_update_module_md(copr_chroot) 642 db.session.add(copr_chroot)
643 644 @classmethod
645 - def remove_copr_chroot(cls, user, copr_chroot):
646 """ 647 :param models.CoprChroot chroot: 648 """ 649 UsersLogic.raise_if_cant_update_copr( 650 user, copr_chroot.copr, 651 "Only owners and admins may update their projects.") 652 653 db.session.delete(copr_chroot)
654
655 656 -class MockChrootsLogic(object):
657 @classmethod
658 - def get(cls, os_release, os_version, arch, active_only=False, noarch=False):
668 669 @classmethod
670 - def get_from_name(cls, chroot_name, active_only=False, noarch=False):
671 """ 672 chroot_name should be os-version-architecture, e.g. fedora-rawhide-x86_64 673 the architecture could be optional with noarch=True 674 675 Return MockChroot object for textual representation of chroot 676 """ 677 678 name_tuple = cls.tuple_from_name(chroot_name, noarch=noarch) 679 return cls.get(name_tuple[0], name_tuple[1], name_tuple[2], 680 active_only=active_only, noarch=noarch)
681 682 @classmethod
683 - def get_multiple(cls, active_only=False):
684 query = models.MockChroot.query 685 if active_only: 686 query = query.filter(models.MockChroot.is_active == True) 687 return query
688 689 @classmethod
690 - def add(cls, name):
691 name_tuple = cls.tuple_from_name(name) 692 if cls.get(*name_tuple).first(): 693 raise exceptions.DuplicateException( 694 "Mock chroot with this name already exists.") 695 new_chroot = models.MockChroot(os_release=name_tuple[0], 696 os_version=name_tuple[1], 697 arch=name_tuple[2]) 698 cls.new(new_chroot) 699 return new_chroot
700 701 @classmethod
702 - def new(cls, mock_chroot):
703 db.session.add(mock_chroot)
704 705 @classmethod
706 - def edit_by_name(cls, name, is_active):
707 name_tuple = cls.tuple_from_name(name) 708 mock_chroot = cls.get(*name_tuple).first() 709 if not mock_chroot: 710 raise exceptions.NotFoundException( 711 "Mock chroot with this name doesn't exist.") 712 713 mock_chroot.is_active = is_active 714 cls.update(mock_chroot) 715 return mock_chroot
716 717 @classmethod
718 - def update(cls, mock_chroot):
719 db.session.add(mock_chroot)
720 721 @classmethod
722 - def delete_by_name(cls, name):
723 name_tuple = cls.tuple_from_name(name) 724 mock_chroot = cls.get(*name_tuple).first() 725 if not mock_chroot: 726 raise exceptions.NotFoundException( 727 "Mock chroot with this name doesn't exist.") 728 729 cls.delete(mock_chroot)
730 731 @classmethod
732 - def delete(cls, mock_chroot):
733 db.session.delete(mock_chroot)
734 735 @classmethod
736 - def tuple_from_name(cls, name, noarch=False):
737 """ 738 input should be os-version-architecture, e.g. fedora-rawhide-x86_64 739 740 the architecture could be optional with noarch=True 741 742 returns ("os", "version", "arch") or ("os", "version", None) 743 """ 744 split_name = name.rsplit("-", 1) if noarch else name.rsplit("-", 2) 745 746 valid = False 747 if noarch and len(split_name) in [2, 3]: 748 valid = True 749 if not noarch and len(split_name) == 3: 750 valid = True 751 752 if not valid: 753 raise MalformedArgumentException( 754 "Chroot name is not valid") 755 756 if noarch and len(split_name) == 2: 757 split_name.append(None) 758 759 return tuple(split_name)
760