3 # Copyright (c) 2007 Red Hat, Inc.
4 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 from mic.utils import errors, misc, runner, fs_related as fs
27 import pykickstart.sections as kssections
28 import pykickstart.commands as kscommands
29 import pykickstart.constants as ksconstants
30 import pykickstart.errors as kserrors
31 import pykickstart.parser as ksparser
32 import pykickstart.version as ksversion
33 from pykickstart.handlers.control import commandMap
34 from pykickstart.handlers.control import dataMap
36 import custom_commands.desktop as desktop
37 import custom_commands.micrepo as micrepo
38 import custom_commands.micboot as micboot
39 import custom_commands.partition as partition
41 AUTH_URL_PTN = r"(?P<scheme>.*)://(?P<username>.*)(:?P<password>.*)?@(?P<url>.*)"
43 class PrepackageSection(kssections.Section):
44 sectionOpen = "%prepackages"
46 def handleLine(self, line):
50 (h, s, t) = line.partition('#')
53 self.handler.prepackages.add([line])
55 def handleHeader(self, lineno, args):
56 kssections.Section.handleHeader(self, lineno, args)
58 class AttachmentSection(kssections.Section):
59 sectionOpen = "%attachment"
61 def handleLine(self, line):
65 (h, s, t) = line.partition('#')
68 self.handler.attachment.add([line])
70 def handleHeader(self, lineno, args):
71 kssections.Section.handleHeader(self, lineno, args)
73 def apply_wrapper(func):
74 def wrapper(*kargs, **kwargs):
76 func(*kargs, **kwargs)
77 except (OSError, IOError, errors.KsError), err:
78 cfgcls = kargs[0].__class__.__name__
79 if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
80 msger.warning("%s" % err)
83 # just throw out the exception
87 def read_kickstart(path):
88 """Parse a kickstart file and return a KickstartParser instance.
90 This is a simple utility function which takes a path to a kickstart file,
91 parses it and returns a pykickstart KickstartParser instance which can
92 be then passed to an ImageCreator constructor.
94 If an error occurs, a CreatorError exception is thrown.
97 #version = ksversion.makeVersion()
98 #ks = ksparser.KickstartParser(version)
100 using_version = ksversion.DEVEL
101 commandMap[using_version]["desktop"] = desktop.Mic_Desktop
102 commandMap[using_version]["repo"] = micrepo.Mic_Repo
103 commandMap[using_version]["bootloader"] = micboot.Mic_Bootloader
104 commandMap[using_version]["part"] = partition.Mic_Partition
105 commandMap[using_version]["partition"] = partition.Mic_Partition
106 dataMap[using_version]["RepoData"] = micrepo.Mic_RepoData
107 dataMap[using_version]["PartData"] = partition.Mic_PartData
108 superclass = ksversion.returnClassForVersion(version=using_version)
110 class KSHandlers(superclass):
111 def __init__(self, mapping={}):
112 superclass.__init__(self, mapping=commandMap[using_version])
113 self.prepackages = ksparser.Packages()
114 self.attachment = ksparser.Packages()
116 ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False)
117 ks.registerSection(PrepackageSection(ks.handler))
118 ks.registerSection(AttachmentSection(ks.handler))
121 ks.readKickstart(path)
122 except (kserrors.KickstartParseError, kserrors.KickstartError), err:
123 if msger.ask("Errors occured on kickstart file, skip and continue?"):
124 msger.warning("%s" % err)
127 raise errors.KsError("%s" % err)
131 class KickstartConfig(object):
132 """A base class for applying kickstart configurations to a system."""
133 def __init__(self, instroot):
134 self.instroot = instroot
136 def path(self, subpath):
137 return self.instroot + subpath
139 def _check_sysconfig(self):
140 if not os.path.exists(self.path("/etc/sysconfig")):
141 fs.makedirs(self.path("/etc/sysconfig"))
144 os.chroot(self.instroot)
147 def call(self, args):
148 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
149 raise errors.KsError("Can't find %s in chroot" % args[0])
150 subprocess.call(args, preexec_fn = self.chroot)
155 class LanguageConfig(KickstartConfig):
156 """A class to apply a kickstart language configuration to a system."""
158 def apply(self, kslang):
159 self._check_sysconfig()
161 f = open(self.path("/etc/sysconfig/i18n"), "w+")
162 f.write("LANG=\"" + kslang.lang + "\"\n")
165 class KeyboardConfig(KickstartConfig):
166 """A class to apply a kickstart keyboard configuration to a system."""
168 def apply(self, kskeyboard):
171 # should this impact the X keyboard config too?
172 # or do we want to make X be able to do this mapping?
174 #k = rhpl.keyboard.Keyboard()
175 #if kskeyboard.keyboard:
176 # k.set(kskeyboard.keyboard)
177 #k.write(self.instroot)
180 class TimezoneConfig(KickstartConfig):
181 """A class to apply a kickstart timezone configuration to a system."""
183 def apply(self, kstimezone):
184 self._check_sysconfig()
185 tz = kstimezone.timezone or "America/New_York"
186 utc = str(kstimezone.isUtc)
188 f = open(self.path("/etc/sysconfig/clock"), "w+")
189 f.write("ZONE=\"" + tz + "\"\n")
190 f.write("UTC=" + utc + "\n")
192 tz_source = "/usr/share/zoneinfo/%s" % (tz)
193 tz_dest = "/etc/localtime"
195 cpcmd = fs.find_binary_inchroot('cp', self.instroot)
197 self.call([cpcmd, "-f", tz_source, tz_dest])
199 cpcmd = fs.find_binary_path('cp')
200 subprocess.call([cpcmd, "-f",
201 self.path(tz_source),
203 except (IOError, OSError), (errno, msg):
204 raise errors.KsError("Timezone setting error: %s" % msg)
206 class AuthConfig(KickstartConfig):
207 """A class to apply a kickstart authconfig configuration to a system."""
209 def apply(self, ksauthconfig):
210 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
211 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
212 self.call(args + auth.split())
214 class FirewallConfig(KickstartConfig):
215 """A class to apply a kickstart firewall configuration to a system."""
217 def apply(self, ksfirewall):
219 # FIXME: should handle the rest of the options
221 if not os.path.exists(self.path("/usr/sbin/lokkit")):
223 if ksfirewall.enabled:
226 status = "--disabled"
228 self.call(["/usr/sbin/lokkit",
229 "-f", "--quiet", "--nostart", status])
231 class RootPasswordConfig(KickstartConfig):
232 """A class to apply a kickstart root password configuration to a system."""
234 self.call(["/usr/bin/passwd", "-d", "root"])
236 def set_encrypted(self, password):
237 self.call(["/usr/sbin/usermod", "-p", password, "root"])
239 def set_unencrypted(self, password):
240 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
241 if not os.path.exists("%s/%s" %(self.instroot, p)):
242 raise errors.KsError("Unable to set unencrypted password due "
245 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
246 stdout = subprocess.PIPE,
247 preexec_fn = self.chroot)
248 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
250 stdout = subprocess.PIPE,
251 preexec_fn = self.chroot)
255 def apply(self, ksrootpw):
256 if ksrootpw.isCrypted:
257 self.set_encrypted(ksrootpw.password)
258 elif ksrootpw.password != "":
259 self.set_unencrypted(ksrootpw.password)
263 class UserConfig(KickstartConfig):
264 def set_empty_passwd(self, user):
265 self.call(["/usr/bin/passwd", "-d", user])
267 def set_encrypted_passwd(self, user, password):
268 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
270 def set_unencrypted_passwd(self, user, password):
271 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
272 if not os.path.exists("%s/%s" %(self.instroot, p)):
273 raise errors.KsError("Unable to set unencrypted password due "
276 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
277 stdout = subprocess.PIPE,
278 preexec_fn = self.chroot)
279 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
281 stdout = subprocess.PIPE,
282 preexec_fn = self.chroot)
285 def addUser(self, userconfig):
286 args = [ "/usr/sbin/useradd" ]
287 if userconfig.groups:
288 args += [ "--groups", string.join(userconfig.groups, ",") ]
291 args += [ "-d", "/home/%s" % userconfig.name ]
292 args.append(userconfig.name)
294 dev_null = os.open("/dev/null", os.O_WRONLY)
295 msger.debug('adding user with %s' % args)
296 subprocess.call(args,
299 preexec_fn = self.chroot)
302 msger.warning('Cannot add user using "useradd"')
304 if userconfig.password not in (None, ""):
305 if userconfig.isCrypted:
306 self.set_encrypted_passwd(userconfig.name,
309 self.set_unencrypted_passwd(userconfig.name,
312 self.set_empty_passwd(userconfig.name)
314 raise errors.KsError("Invalid kickstart command: %s" \
315 % userconfig.__str__())
318 def apply(self, user):
319 for userconfig in user.userList:
321 self.addUser(userconfig)
325 class ServicesConfig(KickstartConfig):
326 """A class to apply a kickstart services configuration to a system."""
328 def apply(self, ksservices):
329 if not os.path.exists(self.path("/sbin/chkconfig")):
331 for s in ksservices.enabled:
332 self.call(["/sbin/chkconfig", s, "on"])
333 for s in ksservices.disabled:
334 self.call(["/sbin/chkconfig", s, "off"])
336 class XConfig(KickstartConfig):
337 """A class to apply a kickstart X configuration to a system."""
339 def apply(self, ksxconfig):
340 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
341 f = open(self.path("/etc/inittab"), "rw+")
343 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
347 if ksxconfig.defaultdesktop:
348 self._check_sysconfig()
349 f = open(self.path("/etc/sysconfig/desktop"), "w")
350 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
353 class DesktopConfig(KickstartConfig):
354 """A class to apply a kickstart desktop configuration to a system."""
356 def apply(self, ksdesktop):
357 if ksdesktop.defaultdesktop:
358 self._check_sysconfig()
359 f = open(self.path("/etc/sysconfig/desktop"), "w")
360 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
362 if os.path.exists(self.path("/etc/gdm/custom.conf")):
363 f = open(self.path("/etc/skel/.dmrc"), "w")
364 f.write("[Desktop]\n")
365 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
367 if ksdesktop.session:
368 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
369 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
370 f.write("session="+ksdesktop.session.lower()+"\n")
372 if ksdesktop.autologinuser:
373 self._check_sysconfig()
374 f = open(self.path("/etc/sysconfig/desktop"), "a+")
375 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
377 if os.path.exists(self.path("/etc/gdm/custom.conf")):
378 f = open(self.path("/etc/gdm/custom.conf"), "w")
379 f.write("[daemon]\n")
380 f.write("AutomaticLoginEnable=true\n")
381 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
384 class MoblinRepoConfig(KickstartConfig):
385 """A class to apply a kickstart desktop configuration to a system."""
386 def __create_repo_section(self, repo, type, fd):
389 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
390 reponame = repo.name + reposuffix[type]
393 baseurl = repo.baseurl
395 mirrorlist = repo.mirrorlist
397 elif type == "debuginfo":
399 if repo.baseurl.endswith("/"):
400 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
402 baseurl = os.path.dirname(repo.baseurl)
406 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
407 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
408 mirrorlist += "debug" + "-" + variant
410 elif type == "source":
412 if repo.baseurl.endswith("/"):
413 baseurl = os.path.dirname(
415 os.path.dirname(repo.baseurl)))
417 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
421 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
422 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
423 mirrorlist += "source" + "-" + variant
425 fd.write("[" + reponame + "]\n")
426 fd.write("name=" + reponame + "\n")
427 fd.write("failovermethod=priority\n")
429 auth_url = re.compile(AUTH_URL_PTN)
430 m = auth_url.match(baseurl)
432 baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
433 fd.write("baseurl=" + baseurl + "\n")
435 fd.write("mirrorlist=" + mirrorlist + "\n")
436 """ Skip saving proxy settings """
438 # fd.write("proxy=" + repo.proxy + "\n")
439 #if repo.proxy_username:
440 # fd.write("proxy_username=" + repo.proxy_username + "\n")
441 #if repo.proxy_password:
442 # fd.write("proxy_password=" + repo.proxy_password + "\n")
444 fd.write("gpgkey=" + repo.gpgkey + "\n")
445 fd.write("gpgcheck=1\n")
447 fd.write("gpgcheck=0\n")
448 if type == "source" or type == "debuginfo" or repo.disable:
449 fd.write("enabled=0\n")
451 fd.write("enabled=1\n")
454 def __create_repo_file(self, repo, repodir):
455 fs.makedirs(self.path(repodir))
456 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
457 self.__create_repo_section(repo, "base", f)
459 self.__create_repo_section(repo, "debuginfo", f)
461 self.__create_repo_section(repo, "source", f)
465 def apply(self, ksrepo, repodata, repourl):
466 for repo in ksrepo.repoList:
467 if repo.name in repourl:
468 repo.baseurl = repourl[repo.name]
470 #self.__create_repo_file(repo, "/etc/yum.repos.d")
471 self.__create_repo_file(repo, "/etc/zypp/repos.d")
472 """ Import repo gpg keys """
474 for repo in repodata:
477 "--root=%s" % self.instroot,
481 class RPMMacroConfig(KickstartConfig):
482 """A class to apply the specified rpm macros to the filesystem"""
487 if not os.path.exists(self.path("/etc/rpm")):
488 os.mkdir(self.path("/etc/rpm"))
489 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
491 f.write("%_excludedocs 1\n")
492 f.write("%__file_context_path %{nil}\n")
493 if inst_langs(ks) != None:
494 f.write("%_install_langs ")
495 f.write(inst_langs(ks))
499 class NetworkConfig(KickstartConfig):
500 """A class to apply a kickstart network configuration to a system."""
501 def write_ifcfg(self, network):
502 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
507 f.write("DEVICE=%s\n" % network.device)
508 f.write("BOOTPROTO=%s\n" % network.bootProto)
510 if network.bootProto.lower() == "static":
512 f.write("IPADDR=%s\n" % network.ip)
514 f.write("NETMASK=%s\n" % network.netmask)
517 f.write("ONBOOT=on\n")
519 f.write("ONBOOT=off\n")
522 f.write("ESSID=%s\n" % network.essid)
525 if network.ethtool.find("autoneg") == -1:
526 network.ethtool = "autoneg off " + network.ethtool
527 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
529 if network.bootProto.lower() == "dhcp":
531 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
532 if network.dhcpclass:
533 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
536 f.write("MTU=%s\n" % network.mtu)
540 def write_wepkey(self, network):
541 if not network.wepkey:
544 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
547 f.write("KEY=%s\n" % network.wepkey)
550 def write_sysconfig(self, useipv6, hostname, gateway):
551 path = self.path("/etc/sysconfig/network")
555 f.write("NETWORKING=yes\n")
558 f.write("NETWORKING_IPV6=yes\n")
560 f.write("NETWORKING_IPV6=no\n")
563 f.write("HOSTNAME=%s\n" % hostname)
565 f.write("HOSTNAME=localhost.localdomain\n")
568 f.write("GATEWAY=%s\n" % gateway)
572 def write_hosts(self, hostname):
574 if hostname and hostname != "localhost.localdomain":
575 localline += hostname + " "
576 l = hostname.split(".")
578 localline += l[0] + " "
579 localline += "localhost.localdomain localhost"
581 path = self.path("/etc/hosts")
584 f.write("127.0.0.1\t\t%s\n" % localline)
585 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
588 def write_resolv(self, nodns, nameservers):
589 if nodns or not nameservers:
592 path = self.path("/etc/resolv.conf")
596 for ns in (nameservers):
598 f.write("nameserver %s\n" % ns)
603 def apply(self, ksnet):
604 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
612 for network in ksnet.network:
613 if not network.device:
614 raise errors.KsError("No --device specified with "
615 "network kickstart command")
617 if (network.onboot and network.bootProto.lower() != "dhcp" and
618 not (network.ip and network.netmask)):
619 raise errors.KsError("No IP address and/or netmask "
620 "specified with static "
621 "configuration for '%s'" %
624 self.write_ifcfg(network)
625 self.write_wepkey(network)
633 hostname = network.hostname
635 gateway = network.gateway
637 if network.nameserver:
638 nameservers = network.nameserver.split(",")
640 self.write_sysconfig(useipv6, hostname, gateway)
641 self.write_hosts(hostname)
642 self.write_resolv(nodns, nameservers)
645 def get_image_size(ks, default = None):
647 for p in ks.handler.partition.partitions:
648 if p.mountpoint == "/" and p.size:
651 return int(__size) * 1024L * 1024L
655 def get_image_fstype(ks, default = None):
656 for p in ks.handler.partition.partitions:
657 if p.mountpoint == "/" and p.fstype:
661 def get_image_fsopts(ks, default = None):
662 for p in ks.handler.partition.partitions:
663 if p.mountpoint == "/" and p.fsopts:
669 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
670 devices.append(ks.handler.device)
672 devices.extend(ks.handler.device.deviceList)
675 for device in devices:
676 if not device.moduleName:
678 modules.extend(device.moduleName.split(":"))
682 def get_timeout(ks, default = None):
683 if not hasattr(ks.handler.bootloader, "timeout"):
685 if ks.handler.bootloader.timeout is None:
687 return int(ks.handler.bootloader.timeout)
689 def get_kernel_args(ks, default = "ro rd.live.image"):
690 if not hasattr(ks.handler.bootloader, "appendLine"):
692 if ks.handler.bootloader.appendLine is None:
694 return "%s %s" %(default, ks.handler.bootloader.appendLine)
696 def get_menu_args(ks, default = ""):
697 if not hasattr(ks.handler.bootloader, "menus"):
699 if ks.handler.bootloader.menus in (None, ""):
701 return "%s" % ks.handler.bootloader.menus
703 def get_default_kernel(ks, default = None):
704 if not hasattr(ks.handler.bootloader, "default"):
706 if not ks.handler.bootloader.default:
708 return ks.handler.bootloader.default
710 def get_repos(ks, repo_urls = {}):
712 for repo in ks.handler.repo.repoList:
714 if hasattr(repo, "includepkgs"):
715 inc.extend(repo.includepkgs)
718 if hasattr(repo, "excludepkgs"):
719 exc.extend(repo.excludepkgs)
721 baseurl = repo.baseurl
722 mirrorlist = repo.mirrorlist
724 if repo.name in repo_urls:
725 baseurl = repo_urls[repo.name]
728 if repos.has_key(repo.name):
729 msger.warning("Overriding already specified repo %s" %(repo.name,))
732 if hasattr(repo, "proxy"):
734 proxy_username = None
735 if hasattr(repo, "proxy_username"):
736 proxy_username = repo.proxy_username
737 proxy_password = None
738 if hasattr(repo, "proxy_password"):
739 proxy_password = repo.proxy_password
740 if hasattr(repo, "debuginfo"):
741 debuginfo = repo.debuginfo
742 if hasattr(repo, "source"):
744 if hasattr(repo, "gpgkey"):
746 if hasattr(repo, "disable"):
747 disable = repo.disable
749 if hasattr(repo, "ssl_verify"):
750 ssl_verify = repo.ssl_verify == "yes"
752 if hasattr(repo, "nocache"):
753 nocache = repo.nocache
755 if hasattr(repo, "cost"):
758 if hasattr(repo, "priority"):
759 priority = repo.priority
761 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
762 proxy, proxy_username, proxy_password, debuginfo,
763 source, gpgkey, disable, ssl_verify, nocache,
766 return repos.values()
768 def convert_method_to_repo(ks):
770 ks.handler.repo.methodToRepo()
771 except (AttributeError, kserrors.KickstartError):
774 def get_attachment(ks, required = []):
775 return ks.handler.attachment.packageList + required
777 def get_pre_packages(ks, required = []):
778 return ks.handler.prepackages.packageList + required
780 def get_packages(ks, required = []):
781 return ks.handler.packages.packageList + required
783 def get_groups(ks, required = []):
784 return ks.handler.packages.groupList + required
786 def get_excluded(ks, required = []):
787 return ks.handler.packages.excludedList + required
789 def get_partitions(ks, required = []):
790 return ks.handler.partition.partitions
792 def ignore_missing(ks):
793 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
795 def exclude_docs(ks):
796 return ks.handler.packages.excludeDocs
799 if hasattr(ks.handler.packages, "instLange"):
800 return ks.handler.packages.instLange
801 elif hasattr(ks.handler.packages, "instLangs"):
802 return ks.handler.packages.instLangs
805 def get_post_scripts(ks):
807 for s in ks.handler.scripts:
808 if s.type != ksparser.KS_SCRIPT_POST:
813 def add_repo(ks, repostr):
814 args = repostr.split()
815 repoobj = ks.handler.repo.parse(args[1:])
816 if repoobj and repoobj not in ks.handler.repo.repoList:
817 ks.handler.repo.repoList.append(repoobj)
819 def remove_all_repos(ks):
820 while len(ks.handler.repo.repoList) != 0:
821 del ks.handler.repo.repoList[0]
823 def remove_duplicate_repos(ks):
827 if len(ks.handler.repo.repoList) < 2:
829 if i >= len(ks.handler.repo.repoList) - 1:
831 name = ks.handler.repo.repoList[i].name
832 baseurl = ks.handler.repo.repoList[i].baseurl
833 if j < len(ks.handler.repo.repoList):
834 if (ks.handler.repo.repoList[j].name == name or \
835 ks.handler.repo.repoList[j].baseurl == baseurl):
836 del ks.handler.repo.repoList[j]
839 if j >= len(ks.handler.repo.repoList):
846 def resolve_groups(creatoropts, repometadata):
848 if 'zypp' == creatoropts['pkgmgr']:
850 ks = creatoropts['ks']
852 for repo in repometadata:
853 """ Mustn't replace group with package list if repo is ready for the
854 corresponding package manager.
857 if iszypp and repo["patterns"]:
859 if not iszypp and repo["comps"]:
862 # But we also must handle such cases, use zypp but repo only has comps,
863 # use yum but repo only has patterns, use zypp but use_comps is true,
864 # use yum but use_comps is false.
866 if iszypp and repo["comps"]:
867 groupfile = repo["comps"]
868 get_pkglist_handler = misc.get_pkglist_in_comps
869 if not iszypp and repo["patterns"]:
870 groupfile = repo["patterns"]
871 get_pkglist_handler = misc.get_pkglist_in_patterns
876 if i >= len(ks.handler.packages.groupList):
878 pkglist = get_pkglist_handler(
879 ks.handler.packages.groupList[i].name,
882 del ks.handler.packages.groupList[i]
884 if pkg not in ks.handler.packages.packageList:
885 ks.handler.packages.packageList.append(pkg)