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.
26 from mic.utils import errors, misc, runner, fs_related as fs
28 import pykickstart.sections as kssections
29 import pykickstart.commands as kscommands
30 import pykickstart.constants as ksconstants
31 import pykickstart.errors as kserrors
32 import pykickstart.parser as ksparser
33 import pykickstart.version as ksversion
34 from pykickstart.handlers.control import commandMap
35 from pykickstart.handlers.control import dataMap
37 import custom_commands.desktop as desktop
38 import custom_commands.moblinrepo as moblinrepo
39 import custom_commands.micboot as micboot
40 import custom_commands.partition as partition
42 class PrepackageSection(kssections.Section):
43 sectionOpen = "%prepackages"
45 def handleLine(self, line):
49 (h, s, t) = line.partition('#')
52 self.handler.prepackages.add([line])
54 def handleHeader(self, lineno, args):
55 kssections.Section.handleHeader(self, lineno, args)
57 def read_kickstart(path):
58 """Parse a kickstart file and return a KickstartParser instance.
60 This is a simple utility function which takes a path to a kickstart file,
61 parses it and returns a pykickstart KickstartParser instance which can
62 be then passed to an ImageCreator constructor.
64 If an error occurs, a CreatorError exception is thrown.
67 #version = ksversion.makeVersion()
68 #ks = ksparser.KickstartParser(version)
70 using_version = ksversion.DEVEL
71 commandMap[using_version]["desktop"] = desktop.Moblin_Desktop
72 commandMap[using_version]["repo"] = moblinrepo.Moblin_Repo
73 commandMap[using_version]["bootloader"] = micboot.Moblin_Bootloader
74 commandMap[using_version]["part"] = partition.MeeGo_Partition
75 commandMap[using_version]["partition"] = partition.MeeGo_Partition
76 dataMap[using_version]["RepoData"] = moblinrepo.Moblin_RepoData
77 dataMap[using_version]["PartData"] = partition.MeeGo_PartData
78 superclass = ksversion.returnClassForVersion(version=using_version)
80 class KSHandlers(superclass):
81 def __init__(self, mapping={}):
82 superclass.__init__(self, mapping=commandMap[using_version])
83 self.prepackages = ksparser.Packages()
85 ks = ksparser.KickstartParser(KSHandlers())
86 ks.registerSection(PrepackageSection(ks.handler))
89 ks.readKickstart(path)
90 except kserrors.KickstartParseError, e:
91 msgptn = re.compile("^\D*(\d+).*(Section does not end with.*)$", re.S)
92 m = msgptn.match(str(e))
96 msger.warning("'%s:%s': %s" % (path, lineno, wrnmsg))
98 raise errors.KsError("'%s': %s" % (path, str(e)))
99 except kserrors.KickstartError, e:
100 raise errors.KsError("'%s': %s" % (path, str(e)))
103 def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
104 """Construct and return an image name string.
106 This is a utility function to help create sensible name and fslabel
107 strings. The name is constructed using the sans-prefix-and-extension
108 kickstart filename and the supplied prefix and suffix.
110 If the name exceeds the maxlen length supplied, the prefix is first dropped
111 and then the kickstart filename portion is reduced until it fits. In other
112 words, the suffix takes precedence over the kickstart portion and the
113 kickstart portion takes precedence over the prefix.
115 kscfg -- a path to a kickstart file
116 prefix -- a prefix to prepend to the name; defaults to None, which causes
118 suffix -- a suffix to append to the name; defaults to None, which causes
119 a YYYYMMDDHHMM suffix to be used
120 maxlen -- the maximum length for the returned string; defaults to None,
121 which means there is no restriction on the name length
123 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
126 name = os.path.basename(kscfg)
127 idx = name.rfind('.')
134 suffix = time.strftime("%Y%m%d%H%M")
136 if name.startswith(prefix):
137 name = name[len(prefix):]
139 ret = prefix + name + "-" + suffix
140 if not maxlen is None and len(ret) > maxlen:
141 ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
145 class KickstartConfig(object):
146 """A base class for applying kickstart configurations to a system."""
147 def __init__(self, instroot):
148 self.instroot = instroot
150 def path(self, subpath):
151 return self.instroot + subpath
153 def _check_sysconfig(self):
154 if not os.path.exists(self.path("/etc/sysconfig")):
155 fs.makedirs(self.path("/etc/sysconfig"))
158 os.chroot(self.instroot)
161 def call(self, args):
162 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
163 msger.warning("%s/%s" %(self.instroot, args[0]))
164 raise errors.KsError("Unable to run %s!" %(args))
165 subprocess.call(args, preexec_fn = self.chroot)
170 class LanguageConfig(KickstartConfig):
171 """A class to apply a kickstart language configuration to a system."""
172 def apply(self, kslang):
173 self._check_sysconfig()
175 f = open(self.path("/etc/sysconfig/i18n"), "w+")
176 f.write("LANG=\"" + kslang.lang + "\"\n")
179 class KeyboardConfig(KickstartConfig):
180 """A class to apply a kickstart keyboard configuration to a system."""
181 def apply(self, kskeyboard):
184 # should this impact the X keyboard config too?
185 # or do we want to make X be able to do this mapping?
187 #k = rhpl.keyboard.Keyboard()
188 #if kskeyboard.keyboard:
189 # k.set(kskeyboard.keyboard)
190 #k.write(self.instroot)
193 class TimezoneConfig(KickstartConfig):
194 """A class to apply a kickstart timezone configuration to a system."""
195 def apply(self, kstimezone):
196 self._check_sysconfig()
197 tz = kstimezone.timezone or "America/New_York"
198 utc = str(kstimezone.isUtc)
200 f = open(self.path("/etc/sysconfig/clock"), "w+")
201 f.write("ZONE=\"" + tz + "\"\n")
202 f.write("UTC=" + utc + "\n")
204 tz_source = "/usr/share/zoneinfo/%s" % (tz)
205 tz_dest = "/etc/localtime"
207 self.call(["/bin/cp", "-f", tz_source, tz_dest])
208 except (IOError, OSError), (errno, msg):
209 msger.warning("Failed to copy timezone info from '%s' to '%s': %s" \
210 % (tz_source, tz_dest, msg))
212 class AuthConfig(KickstartConfig):
213 """A class to apply a kickstart authconfig configuration to a system."""
214 def apply(self, ksauthconfig):
215 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
216 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
217 self.call(args + auth.split())
219 class FirewallConfig(KickstartConfig):
220 """A class to apply a kickstart firewall configuration to a system."""
221 def apply(self, ksfirewall):
223 # FIXME: should handle the rest of the options
225 if not os.path.exists(self.path("/usr/sbin/lokkit")):
227 if ksfirewall.enabled:
230 status = "--disabled"
232 self.call(["/usr/sbin/lokkit",
233 "-f", "--quiet", "--nostart", status])
235 class RootPasswordConfig(KickstartConfig):
236 """A class to apply a kickstart root password configuration to a system."""
238 self.call(["/usr/bin/passwd", "-d", "root"])
240 def set_encrypted(self, password):
241 self.call(["/usr/sbin/usermod", "-p", password, "root"])
243 def set_unencrypted(self, password):
244 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
245 if not os.path.exists("%s/%s" %(self.instroot, p)):
246 raise errors.KsError("Unable to set unencrypted password due "
249 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
250 stdout = subprocess.PIPE,
251 preexec_fn = self.chroot)
252 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
254 stdout = subprocess.PIPE,
255 preexec_fn = self.chroot)
258 def apply(self, ksrootpw):
259 if ksrootpw.isCrypted:
260 self.set_encrypted(ksrootpw.password)
261 elif ksrootpw.password != "":
262 self.set_unencrypted(ksrootpw.password)
266 class UserConfig(KickstartConfig):
267 def set_empty_passwd(self, user):
268 self.call(["/usr/bin/passwd", "-d", user])
270 def set_encrypted_passwd(self, user, password):
271 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
273 def set_unencrypted_passwd(self, user, password):
274 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
275 if not os.path.exists("%s/%s" %(self.instroot, p)):
276 raise errors.KsError("Unable to set unencrypted password due "
279 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
280 stdout = subprocess.PIPE,
281 preexec_fn = self.chroot)
282 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
284 stdout = subprocess.PIPE,
285 preexec_fn = self.chroot)
288 def addUser(self, userconfig):
289 args = [ "/usr/sbin/useradd" ]
290 if userconfig.groups:
291 args += [ "--groups", string.join(userconfig.groups, ",") ]
293 args.append(userconfig.name)
295 dev_null = os.open("/dev/null", os.O_WRONLY)
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__())
317 def apply(self, user):
318 for userconfig in user.userList:
320 self.addUser(userconfig)
324 class ServicesConfig(KickstartConfig):
325 """A class to apply a kickstart services configuration to a system."""
326 def apply(self, ksservices):
327 if not os.path.exists(self.path("/sbin/chkconfig")):
329 for s in ksservices.enabled:
330 self.call(["/sbin/chkconfig", s, "on"])
331 for s in ksservices.disabled:
332 self.call(["/sbin/chkconfig", s, "off"])
334 class XConfig(KickstartConfig):
335 """A class to apply a kickstart X configuration to a system."""
336 def apply(self, ksxconfig):
337 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
338 f = open(self.path("/etc/inittab"), "rw+")
340 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
344 if ksxconfig.defaultdesktop:
345 self._check_sysconfig()
346 f = open(self.path("/etc/sysconfig/desktop"), "w")
347 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
350 class DesktopConfig(KickstartConfig):
351 """A class to apply a kickstart desktop configuration to a system."""
352 def apply(self, ksdesktop):
353 if ksdesktop.defaultdesktop:
354 self._check_sysconfig()
355 f = open(self.path("/etc/sysconfig/desktop"), "w")
356 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
358 if os.path.exists(self.path("/etc/gdm/custom.conf")):
359 f = open(self.path("/etc/skel/.dmrc"), "w")
360 f.write("[Desktop]\n")
361 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
363 if ksdesktop.session:
364 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
365 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
366 f.write("session="+ksdesktop.session.lower()+"\n")
368 if ksdesktop.autologinuser:
369 self._check_sysconfig()
370 f = open(self.path("/etc/sysconfig/desktop"), "a+")
371 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
373 if os.path.exists(self.path("/etc/gdm/custom.conf")):
374 f = open(self.path("/etc/gdm/custom.conf"), "w")
375 f.write("[daemon]\n")
376 f.write("AutomaticLoginEnable=true\n")
377 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
380 class MoblinRepoConfig(KickstartConfig):
381 """A class to apply a kickstart desktop configuration to a system."""
382 def __create_repo_section(self, repo, type, fd):
385 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
386 reponame = repo.name + reposuffix[type]
389 baseurl = repo.baseurl
391 mirrorlist = repo.mirrorlist
393 elif type == "debuginfo":
395 if repo.baseurl.endswith("/"):
396 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
398 baseurl = os.path.dirname(repo.baseurl)
402 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
403 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
404 mirrorlist += "debug" + "-" + variant
406 elif type == "source":
408 if repo.baseurl.endswith("/"):
409 baseurl = os.path.dirname(
411 os.path.dirname(repo.baseurl)))
413 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
417 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
418 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
419 mirrorlist += "source" + "-" + variant
421 fd.write("[" + reponame + "]\n")
422 fd.write("name=" + reponame + "\n")
423 fd.write("failovermethod=priority\n")
425 fd.write("baseurl=" + baseurl + "\n")
427 fd.write("mirrorlist=" + mirrorlist + "\n")
428 """ Skip saving proxy settings """
430 # fd.write("proxy=" + repo.proxy + "\n")
431 #if repo.proxy_username:
432 # fd.write("proxy_username=" + repo.proxy_username + "\n")
433 #if repo.proxy_password:
434 # fd.write("proxy_password=" + repo.proxy_password + "\n")
436 fd.write("gpgkey=" + repo.gpgkey + "\n")
437 fd.write("gpgcheck=1\n")
439 fd.write("gpgcheck=0\n")
440 if type == "source" or type == "debuginfo" or repo.disable:
441 fd.write("enabled=0\n")
443 fd.write("enabled=1\n")
446 def __create_repo_file(self, repo, repodir):
447 fs.makedirs(self.path(repodir))
448 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
449 self.__create_repo_section(repo, "base", f)
451 self.__create_repo_section(repo, "debuginfo", f)
453 self.__create_repo_section(repo, "source", f)
456 def apply(self, ksrepo, repodata):
457 for repo in ksrepo.repoList:
459 #self.__create_repo_file(repo, "/etc/yum.repos.d")
460 self.__create_repo_file(repo, "/etc/zypp/repos.d")
461 """ Import repo gpg keys """
463 for repo in repodata:
466 "--root=%s" % self.instroot,
470 class RPMMacroConfig(KickstartConfig):
471 """A class to apply the specified rpm macros to the filesystem"""
475 if not os.path.exists(self.path("/etc/rpm")):
476 os.mkdir(self.path("/etc/rpm"))
477 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
479 f.write("%_excludedocs 1\n")
480 f.write("%__file_context_path %{nil}\n")
481 if inst_langs(ks) != None:
482 f.write("%_install_langs ")
483 f.write(inst_langs(ks))
487 class NetworkConfig(KickstartConfig):
488 """A class to apply a kickstart network configuration to a system."""
489 def write_ifcfg(self, network):
490 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
495 f.write("DEVICE=%s\n" % network.device)
496 f.write("BOOTPROTO=%s\n" % network.bootProto)
498 if network.bootProto.lower() == "static":
500 f.write("IPADDR=%s\n" % network.ip)
502 f.write("NETMASK=%s\n" % network.netmask)
505 f.write("ONBOOT=on\n")
507 f.write("ONBOOT=off\n")
510 f.write("ESSID=%s\n" % network.essid)
513 if network.ethtool.find("autoneg") == -1:
514 network.ethtool = "autoneg off " + network.ethtool
515 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
517 if network.bootProto.lower() == "dhcp":
519 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
520 if network.dhcpclass:
521 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
524 f.write("MTU=%s\n" % network.mtu)
528 def write_wepkey(self, network):
529 if not network.wepkey:
532 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
535 f.write("KEY=%s\n" % network.wepkey)
538 def write_sysconfig(self, useipv6, hostname, gateway):
539 path = self.path("/etc/sysconfig/network")
543 f.write("NETWORKING=yes\n")
546 f.write("NETWORKING_IPV6=yes\n")
548 f.write("NETWORKING_IPV6=no\n")
551 f.write("HOSTNAME=%s\n" % hostname)
553 f.write("HOSTNAME=localhost.localdomain\n")
556 f.write("GATEWAY=%s\n" % gateway)
560 def write_hosts(self, hostname):
562 if hostname and hostname != "localhost.localdomain":
563 localline += hostname + " "
564 l = hostname.split(".")
566 localline += l[0] + " "
567 localline += "localhost.localdomain localhost"
569 path = self.path("/etc/hosts")
572 f.write("127.0.0.1\t\t%s\n" % localline)
573 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
576 def write_resolv(self, nodns, nameservers):
577 if nodns or not nameservers:
580 path = self.path("/etc/resolv.conf")
584 for ns in (nameservers):
586 f.write("nameserver %s\n" % ns)
590 def apply(self, ksnet):
591 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
599 for network in ksnet.network:
600 if not network.device:
601 raise errors.KsError("No --device specified with "
602 "network kickstart command")
604 if (network.onboot and network.bootProto.lower() != "dhcp" and
605 not (network.ip and network.netmask)):
606 raise errors.KsError("No IP address and/or netmask "
607 "specified with static "
608 "configuration for '%s'" %
611 self.write_ifcfg(network)
612 self.write_wepkey(network)
620 hostname = network.hostname
622 gateway = network.gateway
624 if network.nameserver:
625 nameservers = network.nameserver.split(",")
627 self.write_sysconfig(useipv6, hostname, gateway)
628 self.write_hosts(hostname)
629 self.write_resolv(nodns, nameservers)
632 def get_image_size(ks, default = None):
634 for p in ks.handler.partition.partitions:
635 if p.mountpoint == "/" and p.size:
638 return int(__size) * 1024L * 1024L
642 def get_image_fstype(ks, default = None):
643 for p in ks.handler.partition.partitions:
644 if p.mountpoint == "/" and p.fstype:
648 def get_image_fsopts(ks, default = None):
649 for p in ks.handler.partition.partitions:
650 if p.mountpoint == "/" and p.fsopts:
656 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
657 devices.append(ks.handler.device)
659 devices.extend(ks.handler.device.deviceList)
662 for device in devices:
663 if not device.moduleName:
665 modules.extend(device.moduleName.split(":"))
669 def get_timeout(ks, default = None):
670 if not hasattr(ks.handler.bootloader, "timeout"):
672 if ks.handler.bootloader.timeout is None:
674 return int(ks.handler.bootloader.timeout)
676 def get_kernel_args(ks, default = "ro liveimg"):
677 if not hasattr(ks.handler.bootloader, "appendLine"):
679 if ks.handler.bootloader.appendLine is None:
681 return "%s %s" %(default, ks.handler.bootloader.appendLine)
683 def get_menu_args(ks, default = ""):
684 if not hasattr(ks.handler.bootloader, "menus"):
686 if ks.handler.bootloader.menus in (None, ""):
688 return "%s" % ks.handler.bootloader.menus
690 def get_default_kernel(ks, default = None):
691 if not hasattr(ks.handler.bootloader, "default"):
693 if not ks.handler.bootloader.default:
695 return ks.handler.bootloader.default
697 def get_repos(ks, repo_urls = {}):
699 for repo in ks.handler.repo.repoList:
701 if hasattr(repo, "includepkgs"):
702 inc.extend(repo.includepkgs)
705 if hasattr(repo, "excludepkgs"):
706 exc.extend(repo.excludepkgs)
708 baseurl = repo.baseurl
709 mirrorlist = repo.mirrorlist
711 if repo.name in repo_urls:
712 baseurl = repo_urls[repo.name]
715 if repos.has_key(repo.name):
716 msger.warning("Overriding already specified repo %s" %(repo.name,))
719 if hasattr(repo, "proxy"):
721 proxy_username = None
722 if hasattr(repo, "proxy_username"):
723 proxy_username = repo.proxy_username
724 proxy_password = None
725 if hasattr(repo, "proxy_password"):
726 proxy_password = repo.proxy_password
727 if hasattr(repo, "debuginfo"):
728 debuginfo = repo.debuginfo
729 if hasattr(repo, "source"):
731 if hasattr(repo, "gpgkey"):
733 if hasattr(repo, "disable"):
734 disable = repo.disable
736 if hasattr(repo, "ssl_verify"):
737 ssl_verify = repo.ssl_verify == "yes"
739 if hasattr(repo, "cost"):
742 if hasattr(repo, "priority"):
743 priority = repo.priority
745 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
746 proxy, proxy_username, proxy_password, debuginfo,
747 source, gpgkey, disable, ssl_verify, cost, priority)
749 return repos.values()
751 def convert_method_to_repo(ks):
753 ks.handler.repo.methodToRepo()
754 except (AttributeError, kserrors.KickstartError):
757 def get_pre_packages(ks, required = []):
758 return ks.handler.prepackages.packageList + required
760 def get_packages(ks, required = []):
761 return ks.handler.packages.packageList + required
763 def get_groups(ks, required = []):
764 return ks.handler.packages.groupList + required
766 def get_excluded(ks, required = []):
767 return ks.handler.packages.excludedList + required
769 def get_partitions(ks, required = []):
770 return ks.handler.partition.partitions
772 def ignore_missing(ks):
773 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
775 def exclude_docs(ks):
776 return ks.handler.packages.excludeDocs
779 if hasattr(ks.handler.packages, "instLange"):
780 return ks.handler.packages.instLange
781 elif hasattr(ks.handler.packages, "instLangs"):
782 return ks.handler.packages.instLangs
785 def get_post_scripts(ks):
787 for s in ks.handler.scripts:
788 if s.type != ksparser.KS_SCRIPT_POST:
793 def add_repo(ks, repostr):
794 args = repostr.split()
795 repoobj = ks.handler.repo.parse(args[1:])
796 if repoobj and repoobj not in ks.handler.repo.repoList:
797 ks.handler.repo.repoList.append(repoobj)
799 def remove_all_repos(ks):
800 while len(ks.handler.repo.repoList) != 0:
801 del ks.handler.repo.repoList[0]
803 def remove_duplicate_repos(ks):
807 if len(ks.handler.repo.repoList) < 2:
809 if i >= len(ks.handler.repo.repoList) - 1:
811 name = ks.handler.repo.repoList[i].name
812 baseurl = ks.handler.repo.repoList[i].baseurl
813 if j < len(ks.handler.repo.repoList):
814 if (ks.handler.repo.repoList[j].name == name or \
815 ks.handler.repo.repoList[j].baseurl == baseurl):
816 del ks.handler.repo.repoList[j]
819 if j >= len(ks.handler.repo.repoList):
826 def resolve_groups(creatoropts, repometadata):
828 if 'zypp' == creatoropts['pkgmgr']:
830 ks = creatoropts['ks']
832 for repo in repometadata:
833 """ Mustn't replace group with package list if repo is ready for the
834 corresponding package manager.
837 if iszypp and repo["patterns"]:
839 if not iszypp and repo["comps"]:
842 # But we also must handle such cases, use zypp but repo only has comps,
843 # use yum but repo only has patterns, use zypp but use_comps is true,
844 # use yum but use_comps is false.
846 if iszypp and repo["comps"]:
847 groupfile = repo["comps"]
848 get_pkglist_handler = misc.get_pkglist_in_comps
849 if not iszypp and repo["patterns"]:
850 groupfile = repo["patterns"]
851 get_pkglist_handler = misc.get_pkglist_in_patterns
856 if i >= len(ks.handler.packages.groupList):
858 pkglist = get_pkglist_handler(
859 ks.handler.packages.groupList[i].name,
862 del ks.handler.packages.groupList[i]
864 if pkg not in ks.handler.packages.packageList:
865 ks.handler.packages.packageList.append(pkg)