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, repourl):
500 for repo in ksrepo.repoList:
501 if repo.name in repourl:
502 repo.baseurl = repourl[repo.name]
504 #self.__create_repo_file(repo, "/etc/yum.repos.d")
505 self.__create_repo_file(repo, "/etc/zypp/repos.d")
506 """ Import repo gpg keys """
508 for repo in repodata:
511 "--root=%s" % self.instroot,
515 class RPMMacroConfig(KickstartConfig):
516 """A class to apply the specified rpm macros to the filesystem"""
521 if not os.path.exists(self.path("/etc/rpm")):
522 os.mkdir(self.path("/etc/rpm"))
523 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
525 f.write("%_excludedocs 1\n")
526 f.write("%__file_context_path %{nil}\n")
527 if inst_langs(ks) != None:
528 f.write("%_install_langs ")
529 f.write(inst_langs(ks))
533 class NetworkConfig(KickstartConfig):
534 """A class to apply a kickstart network configuration to a system."""
535 def write_ifcfg(self, network):
536 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
541 f.write("DEVICE=%s\n" % network.device)
542 f.write("BOOTPROTO=%s\n" % network.bootProto)
544 if network.bootProto.lower() == "static":
546 f.write("IPADDR=%s\n" % network.ip)
548 f.write("NETMASK=%s\n" % network.netmask)
551 f.write("ONBOOT=on\n")
553 f.write("ONBOOT=off\n")
556 f.write("ESSID=%s\n" % network.essid)
559 if network.ethtool.find("autoneg") == -1:
560 network.ethtool = "autoneg off " + network.ethtool
561 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
563 if network.bootProto.lower() == "dhcp":
565 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
566 if network.dhcpclass:
567 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
570 f.write("MTU=%s\n" % network.mtu)
574 def write_wepkey(self, network):
575 if not network.wepkey:
578 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
581 f.write("KEY=%s\n" % network.wepkey)
584 def write_sysconfig(self, useipv6, hostname, gateway):
585 path = self.path("/etc/sysconfig/network")
589 f.write("NETWORKING=yes\n")
592 f.write("NETWORKING_IPV6=yes\n")
594 f.write("NETWORKING_IPV6=no\n")
597 f.write("HOSTNAME=%s\n" % hostname)
599 f.write("HOSTNAME=localhost.localdomain\n")
602 f.write("GATEWAY=%s\n" % gateway)
606 def write_hosts(self, hostname):
608 if hostname and hostname != "localhost.localdomain":
609 localline += hostname + " "
610 l = hostname.split(".")
612 localline += l[0] + " "
613 localline += "localhost.localdomain localhost"
615 path = self.path("/etc/hosts")
618 f.write("127.0.0.1\t\t%s\n" % localline)
619 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
622 def write_resolv(self, nodns, nameservers):
623 if nodns or not nameservers:
626 path = self.path("/etc/resolv.conf")
630 for ns in (nameservers):
632 f.write("nameserver %s\n" % ns)
637 def apply(self, ksnet):
638 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
646 for network in ksnet.network:
647 if not network.device:
648 raise errors.KsError("No --device specified with "
649 "network kickstart command")
651 if (network.onboot and network.bootProto.lower() != "dhcp" and
652 not (network.ip and network.netmask)):
653 raise errors.KsError("No IP address and/or netmask "
654 "specified with static "
655 "configuration for '%s'" %
658 self.write_ifcfg(network)
659 self.write_wepkey(network)
667 hostname = network.hostname
669 gateway = network.gateway
671 if network.nameserver:
672 nameservers = network.nameserver.split(",")
674 self.write_sysconfig(useipv6, hostname, gateway)
675 self.write_hosts(hostname)
676 self.write_resolv(nodns, nameservers)
679 def get_image_size(ks, default = None):
681 for p in ks.handler.partition.partitions:
682 if p.mountpoint == "/" and p.size:
685 return int(__size) * 1024L * 1024L
689 def get_image_fstype(ks, default = None):
690 for p in ks.handler.partition.partitions:
691 if p.mountpoint == "/" and p.fstype:
695 def get_image_fsopts(ks, default = None):
696 for p in ks.handler.partition.partitions:
697 if p.mountpoint == "/" and p.fsopts:
703 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
704 devices.append(ks.handler.device)
706 devices.extend(ks.handler.device.deviceList)
709 for device in devices:
710 if not device.moduleName:
712 modules.extend(device.moduleName.split(":"))
716 def get_timeout(ks, default = None):
717 if not hasattr(ks.handler.bootloader, "timeout"):
719 if ks.handler.bootloader.timeout is None:
721 return int(ks.handler.bootloader.timeout)
723 def get_kernel_args(ks, default = "ro liveimg"):
724 if not hasattr(ks.handler.bootloader, "appendLine"):
726 if ks.handler.bootloader.appendLine is None:
728 return "%s %s" %(default, ks.handler.bootloader.appendLine)
730 def get_menu_args(ks, default = ""):
731 if not hasattr(ks.handler.bootloader, "menus"):
733 if ks.handler.bootloader.menus in (None, ""):
735 return "%s" % ks.handler.bootloader.menus
737 def get_default_kernel(ks, default = None):
738 if not hasattr(ks.handler.bootloader, "default"):
740 if not ks.handler.bootloader.default:
742 return ks.handler.bootloader.default
744 def get_repos(ks, repo_urls = {}):
746 for repo in ks.handler.repo.repoList:
748 if hasattr(repo, "includepkgs"):
749 inc.extend(repo.includepkgs)
752 if hasattr(repo, "excludepkgs"):
753 exc.extend(repo.excludepkgs)
755 baseurl = repo.baseurl
756 mirrorlist = repo.mirrorlist
758 if repo.name in repo_urls:
759 baseurl = repo_urls[repo.name]
762 if repos.has_key(repo.name):
763 msger.warning("Overriding already specified repo %s" %(repo.name,))
766 if hasattr(repo, "proxy"):
768 proxy_username = None
769 if hasattr(repo, "proxy_username"):
770 proxy_username = repo.proxy_username
771 proxy_password = None
772 if hasattr(repo, "proxy_password"):
773 proxy_password = repo.proxy_password
774 if hasattr(repo, "debuginfo"):
775 debuginfo = repo.debuginfo
776 if hasattr(repo, "source"):
778 if hasattr(repo, "gpgkey"):
780 if hasattr(repo, "disable"):
781 disable = repo.disable
783 if hasattr(repo, "ssl_verify"):
784 ssl_verify = repo.ssl_verify == "yes"
786 if hasattr(repo, "cost"):
789 if hasattr(repo, "priority"):
790 priority = repo.priority
792 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
793 proxy, proxy_username, proxy_password, debuginfo,
794 source, gpgkey, disable, ssl_verify, cost, priority)
796 return repos.values()
798 def convert_method_to_repo(ks):
800 ks.handler.repo.methodToRepo()
801 except (AttributeError, kserrors.KickstartError):
804 def get_attachment(ks, required = []):
805 return ks.handler.attachment.packageList + required
807 def get_pre_packages(ks, required = []):
808 return ks.handler.prepackages.packageList + required
810 def get_packages(ks, required = []):
811 return ks.handler.packages.packageList + required
813 def get_groups(ks, required = []):
814 return ks.handler.packages.groupList + required
816 def get_excluded(ks, required = []):
817 return ks.handler.packages.excludedList + required
819 def get_partitions(ks, required = []):
820 return ks.handler.partition.partitions
822 def ignore_missing(ks):
823 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
825 def exclude_docs(ks):
826 return ks.handler.packages.excludeDocs
829 if hasattr(ks.handler.packages, "instLange"):
830 return ks.handler.packages.instLange
831 elif hasattr(ks.handler.packages, "instLangs"):
832 return ks.handler.packages.instLangs
835 def get_post_scripts(ks):
837 for s in ks.handler.scripts:
838 if s.type != ksparser.KS_SCRIPT_POST:
843 def add_repo(ks, repostr):
844 args = repostr.split()
845 repoobj = ks.handler.repo.parse(args[1:])
846 if repoobj and repoobj not in ks.handler.repo.repoList:
847 ks.handler.repo.repoList.append(repoobj)
849 def remove_all_repos(ks):
850 while len(ks.handler.repo.repoList) != 0:
851 del ks.handler.repo.repoList[0]
853 def remove_duplicate_repos(ks):
857 if len(ks.handler.repo.repoList) < 2:
859 if i >= len(ks.handler.repo.repoList) - 1:
861 name = ks.handler.repo.repoList[i].name
862 baseurl = ks.handler.repo.repoList[i].baseurl
863 if j < len(ks.handler.repo.repoList):
864 if (ks.handler.repo.repoList[j].name == name or \
865 ks.handler.repo.repoList[j].baseurl == baseurl):
866 del ks.handler.repo.repoList[j]
869 if j >= len(ks.handler.repo.repoList):
876 def resolve_groups(creatoropts, repometadata):
878 if 'zypp' == creatoropts['pkgmgr']:
880 ks = creatoropts['ks']
882 for repo in repometadata:
883 """ Mustn't replace group with package list if repo is ready for the
884 corresponding package manager.
887 if iszypp and repo["patterns"]:
889 if not iszypp and repo["comps"]:
892 # But we also must handle such cases, use zypp but repo only has comps,
893 # use yum but repo only has patterns, use zypp but use_comps is true,
894 # use yum but use_comps is false.
896 if iszypp and repo["comps"]:
897 groupfile = repo["comps"]
898 get_pkglist_handler = misc.get_pkglist_in_comps
899 if not iszypp and repo["patterns"]:
900 groupfile = repo["patterns"]
901 get_pkglist_handler = misc.get_pkglist_in_patterns
906 if i >= len(ks.handler.packages.groupList):
908 pkglist = get_pkglist_handler(
909 ks.handler.packages.groupList[i].name,
912 del ks.handler.packages.groupList[i]
914 if pkg not in ks.handler.packages.packageList:
915 ks.handler.packages.packageList.append(pkg)