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 class AttachmentSection(kssections.Section):
58 sectionOpen = "%attachment"
60 def handleLine(self, line):
64 (h, s, t) = line.partition('#')
67 self.handler.attachment.add([line])
69 def handleHeader(self, lineno, args):
70 kssections.Section.handleHeader(self, lineno, args)
72 def apply_wrapper(func):
73 def wrapper(*kargs, **kwargs):
75 func(*kargs, **kwargs)
76 except (OSError, IOError, errors.KsError), err:
77 cfgcls = kargs[0].__class__.__name__
78 if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
79 msger.warning("%s" % err)
82 # just throw out the exception
86 def read_kickstart(path):
87 """Parse a kickstart file and return a KickstartParser instance.
89 This is a simple utility function which takes a path to a kickstart file,
90 parses it and returns a pykickstart KickstartParser instance which can
91 be then passed to an ImageCreator constructor.
93 If an error occurs, a CreatorError exception is thrown.
96 #version = ksversion.makeVersion()
97 #ks = ksparser.KickstartParser(version)
99 using_version = ksversion.DEVEL
100 commandMap[using_version]["desktop"] = desktop.Moblin_Desktop
101 commandMap[using_version]["repo"] = moblinrepo.Moblin_Repo
102 commandMap[using_version]["bootloader"] = micboot.Moblin_Bootloader
103 commandMap[using_version]["part"] = partition.MeeGo_Partition
104 commandMap[using_version]["partition"] = partition.MeeGo_Partition
105 dataMap[using_version]["RepoData"] = moblinrepo.Moblin_RepoData
106 dataMap[using_version]["PartData"] = partition.MeeGo_PartData
107 superclass = ksversion.returnClassForVersion(version=using_version)
109 class KSHandlers(superclass):
110 def __init__(self, mapping={}):
111 superclass.__init__(self, mapping=commandMap[using_version])
112 self.prepackages = ksparser.Packages()
113 self.attachment = ksparser.Packages()
115 ks = ksparser.KickstartParser(KSHandlers())
116 ks.registerSection(PrepackageSection(ks.handler))
117 ks.registerSection(AttachmentSection(ks.handler))
120 ks.readKickstart(path)
121 except kserrors.KickstartParseError, e:
122 msgptn = re.compile("^\D*(\d+).*(Section does not end with.*)$", re.S)
123 m = msgptn.match(str(e))
127 msger.warning("'%s:%s': %s" % (path, lineno, wrnmsg))
129 raise errors.KsError("'%s': %s" % (path, str(e)))
130 except kserrors.KickstartError, e:
131 raise errors.KsError("'%s': %s" % (path, str(e)))
134 def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
135 """Construct and return an image name string.
137 This is a utility function to help create sensible name and fslabel
138 strings. The name is constructed using the sans-prefix-and-extension
139 kickstart filename and the supplied prefix and suffix.
141 If the name exceeds the maxlen length supplied, the prefix is first dropped
142 and then the kickstart filename portion is reduced until it fits. In other
143 words, the suffix takes precedence over the kickstart portion and the
144 kickstart portion takes precedence over the prefix.
146 kscfg -- a path to a kickstart file
147 prefix -- a prefix to prepend to the name; defaults to None, which causes
149 suffix -- a suffix to append to the name; defaults to None, which causes
150 a YYYYMMDDHHMM suffix to be used
151 maxlen -- the maximum length for the returned string; defaults to None,
152 which means there is no restriction on the name length
154 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
157 name = os.path.basename(kscfg)
158 idx = name.rfind('.')
165 suffix = time.strftime("%Y%m%d%H%M")
167 if name.startswith(prefix):
168 name = name[len(prefix):]
170 ret = prefix + name + "-" + suffix
171 if not maxlen is None and len(ret) > maxlen:
172 ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
176 class KickstartConfig(object):
177 """A base class for applying kickstart configurations to a system."""
178 def __init__(self, instroot):
179 self.instroot = instroot
181 def path(self, subpath):
182 return self.instroot + subpath
184 def _check_sysconfig(self):
185 if not os.path.exists(self.path("/etc/sysconfig")):
186 fs.makedirs(self.path("/etc/sysconfig"))
189 os.chroot(self.instroot)
192 def call(self, args):
193 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
194 raise errors.KsError("Can't find %s in chroot" % args[0])
195 subprocess.call(args, preexec_fn = self.chroot)
200 class LanguageConfig(KickstartConfig):
201 """A class to apply a kickstart language configuration to a system."""
203 def apply(self, kslang):
204 self._check_sysconfig()
206 f = open(self.path("/etc/sysconfig/i18n"), "w+")
207 f.write("LANG=\"" + kslang.lang + "\"\n")
210 class KeyboardConfig(KickstartConfig):
211 """A class to apply a kickstart keyboard configuration to a system."""
213 def apply(self, kskeyboard):
216 # should this impact the X keyboard config too?
217 # or do we want to make X be able to do this mapping?
219 #k = rhpl.keyboard.Keyboard()
220 #if kskeyboard.keyboard:
221 # k.set(kskeyboard.keyboard)
222 #k.write(self.instroot)
225 class TimezoneConfig(KickstartConfig):
226 """A class to apply a kickstart timezone configuration to a system."""
228 def apply(self, kstimezone):
229 self._check_sysconfig()
230 tz = kstimezone.timezone or "America/New_York"
231 utc = str(kstimezone.isUtc)
233 f = open(self.path("/etc/sysconfig/clock"), "w+")
234 f.write("ZONE=\"" + tz + "\"\n")
235 f.write("UTC=" + utc + "\n")
237 tz_source = "/usr/share/zoneinfo/%s" % (tz)
238 tz_dest = "/etc/localtime"
240 self.call(["/bin/cp", "-f", tz_source, tz_dest])
241 except (IOError, OSError), (errno, msg):
242 msger.warning("Failed to copy timezone info from '%s' to '%s': %s" \
243 % (tz_source, tz_dest, msg))
245 class AuthConfig(KickstartConfig):
246 """A class to apply a kickstart authconfig configuration to a system."""
248 def apply(self, ksauthconfig):
249 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
250 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
251 self.call(args + auth.split())
253 class FirewallConfig(KickstartConfig):
254 """A class to apply a kickstart firewall configuration to a system."""
256 def apply(self, ksfirewall):
258 # FIXME: should handle the rest of the options
260 if not os.path.exists(self.path("/usr/sbin/lokkit")):
262 if ksfirewall.enabled:
265 status = "--disabled"
267 self.call(["/usr/sbin/lokkit",
268 "-f", "--quiet", "--nostart", status])
270 class RootPasswordConfig(KickstartConfig):
271 """A class to apply a kickstart root password configuration to a system."""
273 self.call(["/usr/bin/passwd", "-d", "root"])
275 def set_encrypted(self, password):
276 self.call(["/usr/sbin/usermod", "-p", password, "root"])
278 def set_unencrypted(self, password):
279 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
280 if not os.path.exists("%s/%s" %(self.instroot, p)):
281 raise errors.KsError("Unable to set unencrypted password due "
284 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
285 stdout = subprocess.PIPE,
286 preexec_fn = self.chroot)
287 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
289 stdout = subprocess.PIPE,
290 preexec_fn = self.chroot)
294 def apply(self, ksrootpw):
295 if ksrootpw.isCrypted:
296 self.set_encrypted(ksrootpw.password)
297 elif ksrootpw.password != "":
298 self.set_unencrypted(ksrootpw.password)
302 class UserConfig(KickstartConfig):
303 def set_empty_passwd(self, user):
304 self.call(["/usr/bin/passwd", "-d", user])
306 def set_encrypted_passwd(self, user, password):
307 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
309 def set_unencrypted_passwd(self, user, password):
310 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
311 if not os.path.exists("%s/%s" %(self.instroot, p)):
312 raise errors.KsError("Unable to set unencrypted password due "
315 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
316 stdout = subprocess.PIPE,
317 preexec_fn = self.chroot)
318 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
320 stdout = subprocess.PIPE,
321 preexec_fn = self.chroot)
324 def addUser(self, userconfig):
325 args = [ "/usr/sbin/useradd" ]
326 if userconfig.groups:
327 args += [ "--groups", string.join(userconfig.groups, ",") ]
329 args.append(userconfig.name)
331 dev_null = os.open("/dev/null", os.O_WRONLY)
332 subprocess.call(args,
335 preexec_fn = self.chroot)
338 msger.warning('Cannot add user using "useradd"')
340 if userconfig.password not in (None, ""):
341 if userconfig.isCrypted:
342 self.set_encrypted_passwd(userconfig.name,
345 self.set_unencrypted_passwd(userconfig.name,
348 self.set_empty_passwd(userconfig.name)
350 raise errors.KsError("Invalid kickstart command: %s" \
351 % userconfig.__str__())
354 def apply(self, user):
355 for userconfig in user.userList:
357 self.addUser(userconfig)
361 class ServicesConfig(KickstartConfig):
362 """A class to apply a kickstart services configuration to a system."""
364 def apply(self, ksservices):
365 if not os.path.exists(self.path("/sbin/chkconfig")):
367 for s in ksservices.enabled:
368 self.call(["/sbin/chkconfig", s, "on"])
369 for s in ksservices.disabled:
370 self.call(["/sbin/chkconfig", s, "off"])
372 class XConfig(KickstartConfig):
373 """A class to apply a kickstart X configuration to a system."""
375 def apply(self, ksxconfig):
376 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
377 f = open(self.path("/etc/inittab"), "rw+")
379 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
383 if ksxconfig.defaultdesktop:
384 self._check_sysconfig()
385 f = open(self.path("/etc/sysconfig/desktop"), "w")
386 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
389 class DesktopConfig(KickstartConfig):
390 """A class to apply a kickstart desktop configuration to a system."""
392 def apply(self, ksdesktop):
393 if ksdesktop.defaultdesktop:
394 self._check_sysconfig()
395 f = open(self.path("/etc/sysconfig/desktop"), "w")
396 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
398 if os.path.exists(self.path("/etc/gdm/custom.conf")):
399 f = open(self.path("/etc/skel/.dmrc"), "w")
400 f.write("[Desktop]\n")
401 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
403 if ksdesktop.session:
404 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
405 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
406 f.write("session="+ksdesktop.session.lower()+"\n")
408 if ksdesktop.autologinuser:
409 self._check_sysconfig()
410 f = open(self.path("/etc/sysconfig/desktop"), "a+")
411 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
413 if os.path.exists(self.path("/etc/gdm/custom.conf")):
414 f = open(self.path("/etc/gdm/custom.conf"), "w")
415 f.write("[daemon]\n")
416 f.write("AutomaticLoginEnable=true\n")
417 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
420 class MoblinRepoConfig(KickstartConfig):
421 """A class to apply a kickstart desktop configuration to a system."""
422 def __create_repo_section(self, repo, type, fd):
425 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
426 reponame = repo.name + reposuffix[type]
429 baseurl = repo.baseurl
431 mirrorlist = repo.mirrorlist
433 elif type == "debuginfo":
435 if repo.baseurl.endswith("/"):
436 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
438 baseurl = os.path.dirname(repo.baseurl)
442 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
443 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
444 mirrorlist += "debug" + "-" + variant
446 elif type == "source":
448 if repo.baseurl.endswith("/"):
449 baseurl = os.path.dirname(
451 os.path.dirname(repo.baseurl)))
453 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
457 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
458 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
459 mirrorlist += "source" + "-" + variant
461 fd.write("[" + reponame + "]\n")
462 fd.write("name=" + reponame + "\n")
463 fd.write("failovermethod=priority\n")
465 fd.write("baseurl=" + baseurl + "\n")
467 fd.write("mirrorlist=" + mirrorlist + "\n")
468 """ Skip saving proxy settings """
470 # fd.write("proxy=" + repo.proxy + "\n")
471 #if repo.proxy_username:
472 # fd.write("proxy_username=" + repo.proxy_username + "\n")
473 #if repo.proxy_password:
474 # fd.write("proxy_password=" + repo.proxy_password + "\n")
476 fd.write("gpgkey=" + repo.gpgkey + "\n")
477 fd.write("gpgcheck=1\n")
479 fd.write("gpgcheck=0\n")
480 if type == "source" or type == "debuginfo" or repo.disable:
481 fd.write("enabled=0\n")
483 fd.write("enabled=1\n")
486 def __create_repo_file(self, repo, repodir):
487 fs.makedirs(self.path(repodir))
488 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
489 self.__create_repo_section(repo, "base", f)
491 self.__create_repo_section(repo, "debuginfo", f)
493 self.__create_repo_section(repo, "source", f)
497 def apply(self, ksrepo, repodata):
498 for repo in ksrepo.repoList:
500 #self.__create_repo_file(repo, "/etc/yum.repos.d")
501 self.__create_repo_file(repo, "/etc/zypp/repos.d")
502 """ Import repo gpg keys """
504 for repo in repodata:
507 "--root=%s" % self.instroot,
511 class RPMMacroConfig(KickstartConfig):
512 """A class to apply the specified rpm macros to the filesystem"""
517 if not os.path.exists(self.path("/etc/rpm")):
518 os.mkdir(self.path("/etc/rpm"))
519 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
521 f.write("%_excludedocs 1\n")
522 f.write("%__file_context_path %{nil}\n")
523 if inst_langs(ks) != None:
524 f.write("%_install_langs ")
525 f.write(inst_langs(ks))
529 class NetworkConfig(KickstartConfig):
530 """A class to apply a kickstart network configuration to a system."""
531 def write_ifcfg(self, network):
532 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
537 f.write("DEVICE=%s\n" % network.device)
538 f.write("BOOTPROTO=%s\n" % network.bootProto)
540 if network.bootProto.lower() == "static":
542 f.write("IPADDR=%s\n" % network.ip)
544 f.write("NETMASK=%s\n" % network.netmask)
547 f.write("ONBOOT=on\n")
549 f.write("ONBOOT=off\n")
552 f.write("ESSID=%s\n" % network.essid)
555 if network.ethtool.find("autoneg") == -1:
556 network.ethtool = "autoneg off " + network.ethtool
557 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
559 if network.bootProto.lower() == "dhcp":
561 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
562 if network.dhcpclass:
563 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
566 f.write("MTU=%s\n" % network.mtu)
570 def write_wepkey(self, network):
571 if not network.wepkey:
574 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
577 f.write("KEY=%s\n" % network.wepkey)
580 def write_sysconfig(self, useipv6, hostname, gateway):
581 path = self.path("/etc/sysconfig/network")
585 f.write("NETWORKING=yes\n")
588 f.write("NETWORKING_IPV6=yes\n")
590 f.write("NETWORKING_IPV6=no\n")
593 f.write("HOSTNAME=%s\n" % hostname)
595 f.write("HOSTNAME=localhost.localdomain\n")
598 f.write("GATEWAY=%s\n" % gateway)
602 def write_hosts(self, hostname):
604 if hostname and hostname != "localhost.localdomain":
605 localline += hostname + " "
606 l = hostname.split(".")
608 localline += l[0] + " "
609 localline += "localhost.localdomain localhost"
611 path = self.path("/etc/hosts")
614 f.write("127.0.0.1\t\t%s\n" % localline)
615 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
618 def write_resolv(self, nodns, nameservers):
619 if nodns or not nameservers:
622 path = self.path("/etc/resolv.conf")
626 for ns in (nameservers):
628 f.write("nameserver %s\n" % ns)
633 def apply(self, ksnet):
634 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
642 for network in ksnet.network:
643 if not network.device:
644 raise errors.KsError("No --device specified with "
645 "network kickstart command")
647 if (network.onboot and network.bootProto.lower() != "dhcp" and
648 not (network.ip and network.netmask)):
649 raise errors.KsError("No IP address and/or netmask "
650 "specified with static "
651 "configuration for '%s'" %
654 self.write_ifcfg(network)
655 self.write_wepkey(network)
663 hostname = network.hostname
665 gateway = network.gateway
667 if network.nameserver:
668 nameservers = network.nameserver.split(",")
670 self.write_sysconfig(useipv6, hostname, gateway)
671 self.write_hosts(hostname)
672 self.write_resolv(nodns, nameservers)
675 def get_image_size(ks, default = None):
677 for p in ks.handler.partition.partitions:
678 if p.mountpoint == "/" and p.size:
681 return int(__size) * 1024L * 1024L
685 def get_image_fstype(ks, default = None):
686 for p in ks.handler.partition.partitions:
687 if p.mountpoint == "/" and p.fstype:
691 def get_image_fsopts(ks, default = None):
692 for p in ks.handler.partition.partitions:
693 if p.mountpoint == "/" and p.fsopts:
699 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
700 devices.append(ks.handler.device)
702 devices.extend(ks.handler.device.deviceList)
705 for device in devices:
706 if not device.moduleName:
708 modules.extend(device.moduleName.split(":"))
712 def get_timeout(ks, default = None):
713 if not hasattr(ks.handler.bootloader, "timeout"):
715 if ks.handler.bootloader.timeout is None:
717 return int(ks.handler.bootloader.timeout)
719 def get_kernel_args(ks, default = "ro liveimg"):
720 if not hasattr(ks.handler.bootloader, "appendLine"):
722 if ks.handler.bootloader.appendLine is None:
724 return "%s %s" %(default, ks.handler.bootloader.appendLine)
726 def get_menu_args(ks, default = ""):
727 if not hasattr(ks.handler.bootloader, "menus"):
729 if ks.handler.bootloader.menus in (None, ""):
731 return "%s" % ks.handler.bootloader.menus
733 def get_default_kernel(ks, default = None):
734 if not hasattr(ks.handler.bootloader, "default"):
736 if not ks.handler.bootloader.default:
738 return ks.handler.bootloader.default
740 def get_repos(ks, repo_urls = {}):
742 for repo in ks.handler.repo.repoList:
744 if hasattr(repo, "includepkgs"):
745 inc.extend(repo.includepkgs)
748 if hasattr(repo, "excludepkgs"):
749 exc.extend(repo.excludepkgs)
751 baseurl = repo.baseurl
752 mirrorlist = repo.mirrorlist
754 if repo.name in repo_urls:
755 baseurl = repo_urls[repo.name]
758 if repos.has_key(repo.name):
759 msger.warning("Overriding already specified repo %s" %(repo.name,))
762 if hasattr(repo, "proxy"):
764 proxy_username = None
765 if hasattr(repo, "proxy_username"):
766 proxy_username = repo.proxy_username
767 proxy_password = None
768 if hasattr(repo, "proxy_password"):
769 proxy_password = repo.proxy_password
770 if hasattr(repo, "debuginfo"):
771 debuginfo = repo.debuginfo
772 if hasattr(repo, "source"):
774 if hasattr(repo, "gpgkey"):
776 if hasattr(repo, "disable"):
777 disable = repo.disable
779 if hasattr(repo, "ssl_verify"):
780 ssl_verify = repo.ssl_verify == "yes"
782 if hasattr(repo, "cost"):
785 if hasattr(repo, "priority"):
786 priority = repo.priority
788 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
789 proxy, proxy_username, proxy_password, debuginfo,
790 source, gpgkey, disable, ssl_verify, cost, priority)
792 return repos.values()
794 def convert_method_to_repo(ks):
796 ks.handler.repo.methodToRepo()
797 except (AttributeError, kserrors.KickstartError):
800 def get_attachment(ks, required = []):
801 return ks.handler.attachment.packageList + required
803 def get_pre_packages(ks, required = []):
804 return ks.handler.prepackages.packageList + required
806 def get_packages(ks, required = []):
807 return ks.handler.packages.packageList + required
809 def get_groups(ks, required = []):
810 return ks.handler.packages.groupList + required
812 def get_excluded(ks, required = []):
813 return ks.handler.packages.excludedList + required
815 def get_partitions(ks, required = []):
816 return ks.handler.partition.partitions
818 def ignore_missing(ks):
819 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
821 def exclude_docs(ks):
822 return ks.handler.packages.excludeDocs
825 if hasattr(ks.handler.packages, "instLange"):
826 return ks.handler.packages.instLange
827 elif hasattr(ks.handler.packages, "instLangs"):
828 return ks.handler.packages.instLangs
831 def get_post_scripts(ks):
833 for s in ks.handler.scripts:
834 if s.type != ksparser.KS_SCRIPT_POST:
839 def add_repo(ks, repostr):
840 args = repostr.split()
841 repoobj = ks.handler.repo.parse(args[1:])
842 if repoobj and repoobj not in ks.handler.repo.repoList:
843 ks.handler.repo.repoList.append(repoobj)
845 def remove_all_repos(ks):
846 while len(ks.handler.repo.repoList) != 0:
847 del ks.handler.repo.repoList[0]
849 def remove_duplicate_repos(ks):
853 if len(ks.handler.repo.repoList) < 2:
855 if i >= len(ks.handler.repo.repoList) - 1:
857 name = ks.handler.repo.repoList[i].name
858 baseurl = ks.handler.repo.repoList[i].baseurl
859 if j < len(ks.handler.repo.repoList):
860 if (ks.handler.repo.repoList[j].name == name or \
861 ks.handler.repo.repoList[j].baseurl == baseurl):
862 del ks.handler.repo.repoList[j]
865 if j >= len(ks.handler.repo.repoList):
872 def resolve_groups(creatoropts, repometadata):
874 if 'zypp' == creatoropts['pkgmgr']:
876 ks = creatoropts['ks']
878 for repo in repometadata:
879 """ Mustn't replace group with package list if repo is ready for the
880 corresponding package manager.
883 if iszypp and repo["patterns"]:
885 if not iszypp and repo["comps"]:
888 # But we also must handle such cases, use zypp but repo only has comps,
889 # use yum but repo only has patterns, use zypp but use_comps is true,
890 # use yum but use_comps is false.
892 if iszypp and repo["comps"]:
893 groupfile = repo["comps"]
894 get_pkglist_handler = misc.get_pkglist_in_comps
895 if not iszypp and repo["patterns"]:
896 groupfile = repo["patterns"]
897 get_pkglist_handler = misc.get_pkglist_in_patterns
902 if i >= len(ks.handler.packages.groupList):
904 pkglist = get_pkglist_handler(
905 ks.handler.packages.groupList[i].name,
908 del ks.handler.packages.groupList[i]
910 if pkg not in ks.handler.packages.packageList:
911 ks.handler.packages.packageList.append(pkg)