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(), errorsAreFatal=False)
116 ks.registerSection(PrepackageSection(ks.handler))
117 ks.registerSection(AttachmentSection(ks.handler))
120 ks.readKickstart(path)
121 except (kserrors.KickstartParseError, kserrors.KickstartError), err:
122 if msger.ask("Errors occured on kickstart file, skip and continue?"):
123 msger.warning("%s" % err)
126 raise errors.KsError("%s" % err)
130 def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
131 """Construct and return an image name string.
133 This is a utility function to help create sensible name and fslabel
134 strings. The name is constructed using the sans-prefix-and-extension
135 kickstart filename and the supplied prefix and suffix.
137 If the name exceeds the maxlen length supplied, the prefix is first dropped
138 and then the kickstart filename portion is reduced until it fits. In other
139 words, the suffix takes precedence over the kickstart portion and the
140 kickstart portion takes precedence over the prefix.
142 kscfg -- a path to a kickstart file
143 prefix -- a prefix to prepend to the name; defaults to None, which causes
145 suffix -- a suffix to append to the name; defaults to None, which causes
146 a YYYYMMDDHHMM suffix to be used
147 maxlen -- the maximum length for the returned string; defaults to None,
148 which means there is no restriction on the name length
150 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
153 name = os.path.basename(kscfg)
154 idx = name.rfind('.')
161 suffix = time.strftime("%Y%m%d%H%M")
163 if name.startswith(prefix):
164 name = name[len(prefix):]
166 ret = prefix + name + "-" + suffix
167 if not maxlen is None and len(ret) > maxlen:
168 ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
172 class KickstartConfig(object):
173 """A base class for applying kickstart configurations to a system."""
174 def __init__(self, instroot):
175 self.instroot = instroot
177 def path(self, subpath):
178 return self.instroot + subpath
180 def _check_sysconfig(self):
181 if not os.path.exists(self.path("/etc/sysconfig")):
182 fs.makedirs(self.path("/etc/sysconfig"))
185 os.chroot(self.instroot)
188 def call(self, args):
189 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
190 raise errors.KsError("Can't find %s in chroot" % args[0])
191 subprocess.call(args, preexec_fn = self.chroot)
196 class LanguageConfig(KickstartConfig):
197 """A class to apply a kickstart language configuration to a system."""
199 def apply(self, kslang):
200 self._check_sysconfig()
202 f = open(self.path("/etc/sysconfig/i18n"), "w+")
203 f.write("LANG=\"" + kslang.lang + "\"\n")
206 class KeyboardConfig(KickstartConfig):
207 """A class to apply a kickstart keyboard configuration to a system."""
209 def apply(self, kskeyboard):
212 # should this impact the X keyboard config too?
213 # or do we want to make X be able to do this mapping?
215 #k = rhpl.keyboard.Keyboard()
216 #if kskeyboard.keyboard:
217 # k.set(kskeyboard.keyboard)
218 #k.write(self.instroot)
221 class TimezoneConfig(KickstartConfig):
222 """A class to apply a kickstart timezone configuration to a system."""
224 def apply(self, kstimezone):
225 self._check_sysconfig()
226 tz = kstimezone.timezone or "America/New_York"
227 utc = str(kstimezone.isUtc)
229 f = open(self.path("/etc/sysconfig/clock"), "w+")
230 f.write("ZONE=\"" + tz + "\"\n")
231 f.write("UTC=" + utc + "\n")
233 tz_source = "/usr/share/zoneinfo/%s" % (tz)
234 tz_dest = "/etc/localtime"
236 cpcmd = fs.find_binary_inchroot('cp', self.instroot)
238 self.call([cpcmd, "-f", tz_source, tz_dest])
240 cpcmd = fs.find_binary_path('cp')
241 subprocess.call([cpcmd, "-f",
242 self.path(tz_source),
244 except (IOError, OSError), (errno, msg):
245 raise errors.KsError("Timezone setting error: %s" % msg)
247 class AuthConfig(KickstartConfig):
248 """A class to apply a kickstart authconfig configuration to a system."""
250 def apply(self, ksauthconfig):
251 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
252 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
253 self.call(args + auth.split())
255 class FirewallConfig(KickstartConfig):
256 """A class to apply a kickstart firewall configuration to a system."""
258 def apply(self, ksfirewall):
260 # FIXME: should handle the rest of the options
262 if not os.path.exists(self.path("/usr/sbin/lokkit")):
264 if ksfirewall.enabled:
267 status = "--disabled"
269 self.call(["/usr/sbin/lokkit",
270 "-f", "--quiet", "--nostart", status])
272 class RootPasswordConfig(KickstartConfig):
273 """A class to apply a kickstart root password configuration to a system."""
275 self.call(["/usr/bin/passwd", "-d", "root"])
277 def set_encrypted(self, password):
278 self.call(["/usr/sbin/usermod", "-p", password, "root"])
280 def set_unencrypted(self, password):
281 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
282 if not os.path.exists("%s/%s" %(self.instroot, p)):
283 raise errors.KsError("Unable to set unencrypted password due "
286 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
287 stdout = subprocess.PIPE,
288 preexec_fn = self.chroot)
289 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
291 stdout = subprocess.PIPE,
292 preexec_fn = self.chroot)
296 def apply(self, ksrootpw):
297 if ksrootpw.isCrypted:
298 self.set_encrypted(ksrootpw.password)
299 elif ksrootpw.password != "":
300 self.set_unencrypted(ksrootpw.password)
304 class UserConfig(KickstartConfig):
305 def set_empty_passwd(self, user):
306 self.call(["/usr/bin/passwd", "-d", user])
308 def set_encrypted_passwd(self, user, password):
309 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
311 def set_unencrypted_passwd(self, user, password):
312 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
313 if not os.path.exists("%s/%s" %(self.instroot, p)):
314 raise errors.KsError("Unable to set unencrypted password due "
317 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
318 stdout = subprocess.PIPE,
319 preexec_fn = self.chroot)
320 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
322 stdout = subprocess.PIPE,
323 preexec_fn = self.chroot)
326 def addUser(self, userconfig):
327 args = [ "/usr/sbin/useradd" ]
328 if userconfig.groups:
329 args += [ "--groups", string.join(userconfig.groups, ",") ]
331 args.append(userconfig.name)
333 dev_null = os.open("/dev/null", os.O_WRONLY)
334 subprocess.call(args,
337 preexec_fn = self.chroot)
340 msger.warning('Cannot add user using "useradd"')
342 if userconfig.password not in (None, ""):
343 if userconfig.isCrypted:
344 self.set_encrypted_passwd(userconfig.name,
347 self.set_unencrypted_passwd(userconfig.name,
350 self.set_empty_passwd(userconfig.name)
352 raise errors.KsError("Invalid kickstart command: %s" \
353 % userconfig.__str__())
356 def apply(self, user):
357 for userconfig in user.userList:
359 self.addUser(userconfig)
363 class ServicesConfig(KickstartConfig):
364 """A class to apply a kickstart services configuration to a system."""
366 def apply(self, ksservices):
367 if not os.path.exists(self.path("/sbin/chkconfig")):
369 for s in ksservices.enabled:
370 self.call(["/sbin/chkconfig", s, "on"])
371 for s in ksservices.disabled:
372 self.call(["/sbin/chkconfig", s, "off"])
374 class XConfig(KickstartConfig):
375 """A class to apply a kickstart X configuration to a system."""
377 def apply(self, ksxconfig):
378 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
379 f = open(self.path("/etc/inittab"), "rw+")
381 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
385 if ksxconfig.defaultdesktop:
386 self._check_sysconfig()
387 f = open(self.path("/etc/sysconfig/desktop"), "w")
388 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
391 class DesktopConfig(KickstartConfig):
392 """A class to apply a kickstart desktop configuration to a system."""
394 def apply(self, ksdesktop):
395 if ksdesktop.defaultdesktop:
396 self._check_sysconfig()
397 f = open(self.path("/etc/sysconfig/desktop"), "w")
398 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
400 if os.path.exists(self.path("/etc/gdm/custom.conf")):
401 f = open(self.path("/etc/skel/.dmrc"), "w")
402 f.write("[Desktop]\n")
403 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
405 if ksdesktop.session:
406 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
407 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
408 f.write("session="+ksdesktop.session.lower()+"\n")
410 if ksdesktop.autologinuser:
411 self._check_sysconfig()
412 f = open(self.path("/etc/sysconfig/desktop"), "a+")
413 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
415 if os.path.exists(self.path("/etc/gdm/custom.conf")):
416 f = open(self.path("/etc/gdm/custom.conf"), "w")
417 f.write("[daemon]\n")
418 f.write("AutomaticLoginEnable=true\n")
419 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
422 class MoblinRepoConfig(KickstartConfig):
423 """A class to apply a kickstart desktop configuration to a system."""
424 def __create_repo_section(self, repo, type, fd):
427 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
428 reponame = repo.name + reposuffix[type]
431 baseurl = repo.baseurl
433 mirrorlist = repo.mirrorlist
435 elif type == "debuginfo":
437 if repo.baseurl.endswith("/"):
438 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
440 baseurl = os.path.dirname(repo.baseurl)
444 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
445 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
446 mirrorlist += "debug" + "-" + variant
448 elif type == "source":
450 if repo.baseurl.endswith("/"):
451 baseurl = os.path.dirname(
453 os.path.dirname(repo.baseurl)))
455 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
459 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
460 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
461 mirrorlist += "source" + "-" + variant
463 fd.write("[" + reponame + "]\n")
464 fd.write("name=" + reponame + "\n")
465 fd.write("failovermethod=priority\n")
467 fd.write("baseurl=" + baseurl + "\n")
469 fd.write("mirrorlist=" + mirrorlist + "\n")
470 """ Skip saving proxy settings """
472 # fd.write("proxy=" + repo.proxy + "\n")
473 #if repo.proxy_username:
474 # fd.write("proxy_username=" + repo.proxy_username + "\n")
475 #if repo.proxy_password:
476 # fd.write("proxy_password=" + repo.proxy_password + "\n")
478 fd.write("gpgkey=" + repo.gpgkey + "\n")
479 fd.write("gpgcheck=1\n")
481 fd.write("gpgcheck=0\n")
482 if type == "source" or type == "debuginfo" or repo.disable:
483 fd.write("enabled=0\n")
485 fd.write("enabled=1\n")
488 def __create_repo_file(self, repo, repodir):
489 fs.makedirs(self.path(repodir))
490 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
491 self.__create_repo_section(repo, "base", f)
493 self.__create_repo_section(repo, "debuginfo", f)
495 self.__create_repo_section(repo, "source", f)
499 def apply(self, ksrepo, repodata):
500 for repo in ksrepo.repoList:
502 #self.__create_repo_file(repo, "/etc/yum.repos.d")
503 self.__create_repo_file(repo, "/etc/zypp/repos.d")
504 """ Import repo gpg keys """
506 for repo in repodata:
509 "--root=%s" % self.instroot,
513 class RPMMacroConfig(KickstartConfig):
514 """A class to apply the specified rpm macros to the filesystem"""
519 if not os.path.exists(self.path("/etc/rpm")):
520 os.mkdir(self.path("/etc/rpm"))
521 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
523 f.write("%_excludedocs 1\n")
524 f.write("%__file_context_path %{nil}\n")
525 if inst_langs(ks) != None:
526 f.write("%_install_langs ")
527 f.write(inst_langs(ks))
531 class NetworkConfig(KickstartConfig):
532 """A class to apply a kickstart network configuration to a system."""
533 def write_ifcfg(self, network):
534 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
539 f.write("DEVICE=%s\n" % network.device)
540 f.write("BOOTPROTO=%s\n" % network.bootProto)
542 if network.bootProto.lower() == "static":
544 f.write("IPADDR=%s\n" % network.ip)
546 f.write("NETMASK=%s\n" % network.netmask)
549 f.write("ONBOOT=on\n")
551 f.write("ONBOOT=off\n")
554 f.write("ESSID=%s\n" % network.essid)
557 if network.ethtool.find("autoneg") == -1:
558 network.ethtool = "autoneg off " + network.ethtool
559 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
561 if network.bootProto.lower() == "dhcp":
563 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
564 if network.dhcpclass:
565 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
568 f.write("MTU=%s\n" % network.mtu)
572 def write_wepkey(self, network):
573 if not network.wepkey:
576 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
579 f.write("KEY=%s\n" % network.wepkey)
582 def write_sysconfig(self, useipv6, hostname, gateway):
583 path = self.path("/etc/sysconfig/network")
587 f.write("NETWORKING=yes\n")
590 f.write("NETWORKING_IPV6=yes\n")
592 f.write("NETWORKING_IPV6=no\n")
595 f.write("HOSTNAME=%s\n" % hostname)
597 f.write("HOSTNAME=localhost.localdomain\n")
600 f.write("GATEWAY=%s\n" % gateway)
604 def write_hosts(self, hostname):
606 if hostname and hostname != "localhost.localdomain":
607 localline += hostname + " "
608 l = hostname.split(".")
610 localline += l[0] + " "
611 localline += "localhost.localdomain localhost"
613 path = self.path("/etc/hosts")
616 f.write("127.0.0.1\t\t%s\n" % localline)
617 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
620 def write_resolv(self, nodns, nameservers):
621 if nodns or not nameservers:
624 path = self.path("/etc/resolv.conf")
628 for ns in (nameservers):
630 f.write("nameserver %s\n" % ns)
635 def apply(self, ksnet):
636 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
644 for network in ksnet.network:
645 if not network.device:
646 raise errors.KsError("No --device specified with "
647 "network kickstart command")
649 if (network.onboot and network.bootProto.lower() != "dhcp" and
650 not (network.ip and network.netmask)):
651 raise errors.KsError("No IP address and/or netmask "
652 "specified with static "
653 "configuration for '%s'" %
656 self.write_ifcfg(network)
657 self.write_wepkey(network)
665 hostname = network.hostname
667 gateway = network.gateway
669 if network.nameserver:
670 nameservers = network.nameserver.split(",")
672 self.write_sysconfig(useipv6, hostname, gateway)
673 self.write_hosts(hostname)
674 self.write_resolv(nodns, nameservers)
677 def get_image_size(ks, default = None):
679 for p in ks.handler.partition.partitions:
680 if p.mountpoint == "/" and p.size:
683 return int(__size) * 1024L * 1024L
687 def get_image_fstype(ks, default = None):
688 for p in ks.handler.partition.partitions:
689 if p.mountpoint == "/" and p.fstype:
693 def get_image_fsopts(ks, default = None):
694 for p in ks.handler.partition.partitions:
695 if p.mountpoint == "/" and p.fsopts:
701 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
702 devices.append(ks.handler.device)
704 devices.extend(ks.handler.device.deviceList)
707 for device in devices:
708 if not device.moduleName:
710 modules.extend(device.moduleName.split(":"))
714 def get_timeout(ks, default = None):
715 if not hasattr(ks.handler.bootloader, "timeout"):
717 if ks.handler.bootloader.timeout is None:
719 return int(ks.handler.bootloader.timeout)
721 def get_kernel_args(ks, default = "ro liveimg"):
722 if not hasattr(ks.handler.bootloader, "appendLine"):
724 if ks.handler.bootloader.appendLine is None:
726 return "%s %s" %(default, ks.handler.bootloader.appendLine)
728 def get_menu_args(ks, default = ""):
729 if not hasattr(ks.handler.bootloader, "menus"):
731 if ks.handler.bootloader.menus in (None, ""):
733 return "%s" % ks.handler.bootloader.menus
735 def get_default_kernel(ks, default = None):
736 if not hasattr(ks.handler.bootloader, "default"):
738 if not ks.handler.bootloader.default:
740 return ks.handler.bootloader.default
742 def get_repos(ks, repo_urls = {}):
744 for repo in ks.handler.repo.repoList:
746 if hasattr(repo, "includepkgs"):
747 inc.extend(repo.includepkgs)
750 if hasattr(repo, "excludepkgs"):
751 exc.extend(repo.excludepkgs)
753 baseurl = repo.baseurl
754 mirrorlist = repo.mirrorlist
756 if repo.name in repo_urls:
757 baseurl = repo_urls[repo.name]
760 if repos.has_key(repo.name):
761 msger.warning("Overriding already specified repo %s" %(repo.name,))
764 if hasattr(repo, "proxy"):
766 proxy_username = None
767 if hasattr(repo, "proxy_username"):
768 proxy_username = repo.proxy_username
769 proxy_password = None
770 if hasattr(repo, "proxy_password"):
771 proxy_password = repo.proxy_password
772 if hasattr(repo, "debuginfo"):
773 debuginfo = repo.debuginfo
774 if hasattr(repo, "source"):
776 if hasattr(repo, "gpgkey"):
778 if hasattr(repo, "disable"):
779 disable = repo.disable
781 if hasattr(repo, "ssl_verify"):
782 ssl_verify = repo.ssl_verify == "yes"
784 if hasattr(repo, "cost"):
787 if hasattr(repo, "priority"):
788 priority = repo.priority
790 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
791 proxy, proxy_username, proxy_password, debuginfo,
792 source, gpgkey, disable, ssl_verify, cost, priority)
794 return repos.values()
796 def convert_method_to_repo(ks):
798 ks.handler.repo.methodToRepo()
799 except (AttributeError, kserrors.KickstartError):
802 def get_attachment(ks, required = []):
803 return ks.handler.attachment.packageList + required
805 def get_pre_packages(ks, required = []):
806 return ks.handler.prepackages.packageList + required
808 def get_packages(ks, required = []):
809 return ks.handler.packages.packageList + required
811 def get_groups(ks, required = []):
812 return ks.handler.packages.groupList + required
814 def get_excluded(ks, required = []):
815 return ks.handler.packages.excludedList + required
817 def get_partitions(ks, required = []):
818 return ks.handler.partition.partitions
820 def ignore_missing(ks):
821 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
823 def exclude_docs(ks):
824 return ks.handler.packages.excludeDocs
827 if hasattr(ks.handler.packages, "instLange"):
828 return ks.handler.packages.instLange
829 elif hasattr(ks.handler.packages, "instLangs"):
830 return ks.handler.packages.instLangs
833 def get_post_scripts(ks):
835 for s in ks.handler.scripts:
836 if s.type != ksparser.KS_SCRIPT_POST:
841 def add_repo(ks, repostr):
842 args = repostr.split()
843 repoobj = ks.handler.repo.parse(args[1:])
844 if repoobj and repoobj not in ks.handler.repo.repoList:
845 ks.handler.repo.repoList.append(repoobj)
847 def remove_all_repos(ks):
848 while len(ks.handler.repo.repoList) != 0:
849 del ks.handler.repo.repoList[0]
851 def remove_duplicate_repos(ks):
855 if len(ks.handler.repo.repoList) < 2:
857 if i >= len(ks.handler.repo.repoList) - 1:
859 name = ks.handler.repo.repoList[i].name
860 baseurl = ks.handler.repo.repoList[i].baseurl
861 if j < len(ks.handler.repo.repoList):
862 if (ks.handler.repo.repoList[j].name == name or \
863 ks.handler.repo.repoList[j].baseurl == baseurl):
864 del ks.handler.repo.repoList[j]
867 if j >= len(ks.handler.repo.repoList):
874 def resolve_groups(creatoropts, repometadata):
876 if 'zypp' == creatoropts['pkgmgr']:
878 ks = creatoropts['ks']
880 for repo in repometadata:
881 """ Mustn't replace group with package list if repo is ready for the
882 corresponding package manager.
885 if iszypp and repo["patterns"]:
887 if not iszypp and repo["comps"]:
890 # But we also must handle such cases, use zypp but repo only has comps,
891 # use yum but repo only has patterns, use zypp but use_comps is true,
892 # use yum but use_comps is false.
894 if iszypp and repo["comps"]:
895 groupfile = repo["comps"]
896 get_pkglist_handler = misc.get_pkglist_in_comps
897 if not iszypp and repo["patterns"]:
898 groupfile = repo["patterns"]
899 get_pkglist_handler = misc.get_pkglist_in_patterns
904 if i >= len(ks.handler.packages.groupList):
906 pkglist = get_pkglist_handler(
907 ks.handler.packages.groupList[i].name,
910 del ks.handler.packages.groupList[i]
912 if pkg not in ks.handler.packages.packageList:
913 ks.handler.packages.packageList.append(pkg)