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 AUTH_URL_PTN = r"(?P<scheme>.*)://(?P<username>.*)(:?P<password>.*)?@(?P<url>.*)"
44 class PrepackageSection(kssections.Section):
45 sectionOpen = "%prepackages"
47 def handleLine(self, line):
51 (h, s, t) = line.partition('#')
54 self.handler.prepackages.add([line])
56 def handleHeader(self, lineno, args):
57 kssections.Section.handleHeader(self, lineno, args)
59 class AttachmentSection(kssections.Section):
60 sectionOpen = "%attachment"
62 def handleLine(self, line):
66 (h, s, t) = line.partition('#')
69 self.handler.attachment.add([line])
71 def handleHeader(self, lineno, args):
72 kssections.Section.handleHeader(self, lineno, args)
74 def apply_wrapper(func):
75 def wrapper(*kargs, **kwargs):
77 func(*kargs, **kwargs)
78 except (OSError, IOError, errors.KsError), err:
79 cfgcls = kargs[0].__class__.__name__
80 if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
81 msger.warning("%s" % err)
84 # just throw out the exception
88 def read_kickstart(path):
89 """Parse a kickstart file and return a KickstartParser instance.
91 This is a simple utility function which takes a path to a kickstart file,
92 parses it and returns a pykickstart KickstartParser instance which can
93 be then passed to an ImageCreator constructor.
95 If an error occurs, a CreatorError exception is thrown.
98 #version = ksversion.makeVersion()
99 #ks = ksparser.KickstartParser(version)
101 using_version = ksversion.DEVEL
102 commandMap[using_version]["desktop"] = desktop.Moblin_Desktop
103 commandMap[using_version]["repo"] = moblinrepo.Moblin_Repo
104 commandMap[using_version]["bootloader"] = micboot.Moblin_Bootloader
105 commandMap[using_version]["part"] = partition.MeeGo_Partition
106 commandMap[using_version]["partition"] = partition.MeeGo_Partition
107 dataMap[using_version]["RepoData"] = moblinrepo.Moblin_RepoData
108 dataMap[using_version]["PartData"] = partition.MeeGo_PartData
109 superclass = ksversion.returnClassForVersion(version=using_version)
111 class KSHandlers(superclass):
112 def __init__(self, mapping={}):
113 superclass.__init__(self, mapping=commandMap[using_version])
114 self.prepackages = ksparser.Packages()
115 self.attachment = ksparser.Packages()
117 ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False)
118 ks.registerSection(PrepackageSection(ks.handler))
119 ks.registerSection(AttachmentSection(ks.handler))
122 ks.readKickstart(path)
123 except (kserrors.KickstartParseError, kserrors.KickstartError), err:
124 if msger.ask("Errors occured on kickstart file, skip and continue?"):
125 msger.warning("%s" % err)
128 raise errors.KsError("%s" % err)
132 def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
133 """Construct and return an image name string.
135 This is a utility function to help create sensible name and fslabel
136 strings. The name is constructed using the sans-prefix-and-extension
137 kickstart filename and the supplied prefix and suffix.
139 If the name exceeds the maxlen length supplied, the prefix is first dropped
140 and then the kickstart filename portion is reduced until it fits. In other
141 words, the suffix takes precedence over the kickstart portion and the
142 kickstart portion takes precedence over the prefix.
144 kscfg -- a path to a kickstart file
145 prefix -- a prefix to prepend to the name; defaults to None, which causes
147 suffix -- a suffix to append to the name; defaults to None, which causes
148 a YYYYMMDDHHMM suffix to be used
149 maxlen -- the maximum length for the returned string; defaults to None,
150 which means there is no restriction on the name length
152 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
155 name = os.path.basename(kscfg)
156 idx = name.rfind('.')
163 suffix = time.strftime("%Y%m%d%H%M")
165 if name.startswith(prefix):
166 name = name[len(prefix):]
168 ret = prefix + name + "-" + suffix
169 if not maxlen is None and len(ret) > maxlen:
170 ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
174 class KickstartConfig(object):
175 """A base class for applying kickstart configurations to a system."""
176 def __init__(self, instroot):
177 self.instroot = instroot
179 def path(self, subpath):
180 return self.instroot + subpath
182 def _check_sysconfig(self):
183 if not os.path.exists(self.path("/etc/sysconfig")):
184 fs.makedirs(self.path("/etc/sysconfig"))
187 os.chroot(self.instroot)
190 def call(self, args):
191 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
192 raise errors.KsError("Can't find %s in chroot" % args[0])
193 subprocess.call(args, preexec_fn = self.chroot)
198 class LanguageConfig(KickstartConfig):
199 """A class to apply a kickstart language configuration to a system."""
201 def apply(self, kslang):
202 self._check_sysconfig()
204 f = open(self.path("/etc/sysconfig/i18n"), "w+")
205 f.write("LANG=\"" + kslang.lang + "\"\n")
208 class KeyboardConfig(KickstartConfig):
209 """A class to apply a kickstart keyboard configuration to a system."""
211 def apply(self, kskeyboard):
214 # should this impact the X keyboard config too?
215 # or do we want to make X be able to do this mapping?
217 #k = rhpl.keyboard.Keyboard()
218 #if kskeyboard.keyboard:
219 # k.set(kskeyboard.keyboard)
220 #k.write(self.instroot)
223 class TimezoneConfig(KickstartConfig):
224 """A class to apply a kickstart timezone configuration to a system."""
226 def apply(self, kstimezone):
227 self._check_sysconfig()
228 tz = kstimezone.timezone or "America/New_York"
229 utc = str(kstimezone.isUtc)
231 f = open(self.path("/etc/sysconfig/clock"), "w+")
232 f.write("ZONE=\"" + tz + "\"\n")
233 f.write("UTC=" + utc + "\n")
235 tz_source = "/usr/share/zoneinfo/%s" % (tz)
236 tz_dest = "/etc/localtime"
238 cpcmd = fs.find_binary_inchroot('cp', self.instroot)
240 self.call([cpcmd, "-f", tz_source, tz_dest])
242 cpcmd = fs.find_binary_path('cp')
243 subprocess.call([cpcmd, "-f",
244 self.path(tz_source),
246 except (IOError, OSError), (errno, msg):
247 raise errors.KsError("Timezone setting error: %s" % msg)
249 class AuthConfig(KickstartConfig):
250 """A class to apply a kickstart authconfig configuration to a system."""
252 def apply(self, ksauthconfig):
253 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
254 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
255 self.call(args + auth.split())
257 class FirewallConfig(KickstartConfig):
258 """A class to apply a kickstart firewall configuration to a system."""
260 def apply(self, ksfirewall):
262 # FIXME: should handle the rest of the options
264 if not os.path.exists(self.path("/usr/sbin/lokkit")):
266 if ksfirewall.enabled:
269 status = "--disabled"
271 self.call(["/usr/sbin/lokkit",
272 "-f", "--quiet", "--nostart", status])
274 class RootPasswordConfig(KickstartConfig):
275 """A class to apply a kickstart root password configuration to a system."""
277 self.call(["/usr/bin/passwd", "-d", "root"])
279 def set_encrypted(self, password):
280 self.call(["/usr/sbin/usermod", "-p", password, "root"])
282 def set_unencrypted(self, password):
283 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
284 if not os.path.exists("%s/%s" %(self.instroot, p)):
285 raise errors.KsError("Unable to set unencrypted password due "
288 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
289 stdout = subprocess.PIPE,
290 preexec_fn = self.chroot)
291 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
293 stdout = subprocess.PIPE,
294 preexec_fn = self.chroot)
298 def apply(self, ksrootpw):
299 if ksrootpw.isCrypted:
300 self.set_encrypted(ksrootpw.password)
301 elif ksrootpw.password != "":
302 self.set_unencrypted(ksrootpw.password)
306 class UserConfig(KickstartConfig):
307 def set_empty_passwd(self, user):
308 self.call(["/usr/bin/passwd", "-d", user])
310 def set_encrypted_passwd(self, user, password):
311 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
313 def set_unencrypted_passwd(self, user, password):
314 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
315 if not os.path.exists("%s/%s" %(self.instroot, p)):
316 raise errors.KsError("Unable to set unencrypted password due "
319 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
320 stdout = subprocess.PIPE,
321 preexec_fn = self.chroot)
322 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
324 stdout = subprocess.PIPE,
325 preexec_fn = self.chroot)
328 def addUser(self, userconfig):
329 args = [ "/usr/sbin/useradd" ]
330 if userconfig.groups:
331 args += [ "--groups", string.join(userconfig.groups, ",") ]
333 args.append(userconfig.name)
335 dev_null = os.open("/dev/null", os.O_WRONLY)
336 subprocess.call(args,
339 preexec_fn = self.chroot)
342 msger.warning('Cannot add user using "useradd"')
344 if userconfig.password not in (None, ""):
345 if userconfig.isCrypted:
346 self.set_encrypted_passwd(userconfig.name,
349 self.set_unencrypted_passwd(userconfig.name,
352 self.set_empty_passwd(userconfig.name)
354 raise errors.KsError("Invalid kickstart command: %s" \
355 % userconfig.__str__())
358 def apply(self, user):
359 for userconfig in user.userList:
361 self.addUser(userconfig)
365 class ServicesConfig(KickstartConfig):
366 """A class to apply a kickstart services configuration to a system."""
368 def apply(self, ksservices):
369 if not os.path.exists(self.path("/sbin/chkconfig")):
371 for s in ksservices.enabled:
372 self.call(["/sbin/chkconfig", s, "on"])
373 for s in ksservices.disabled:
374 self.call(["/sbin/chkconfig", s, "off"])
376 class XConfig(KickstartConfig):
377 """A class to apply a kickstart X configuration to a system."""
379 def apply(self, ksxconfig):
380 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
381 f = open(self.path("/etc/inittab"), "rw+")
383 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
387 if ksxconfig.defaultdesktop:
388 self._check_sysconfig()
389 f = open(self.path("/etc/sysconfig/desktop"), "w")
390 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
393 class DesktopConfig(KickstartConfig):
394 """A class to apply a kickstart desktop configuration to a system."""
396 def apply(self, ksdesktop):
397 if ksdesktop.defaultdesktop:
398 self._check_sysconfig()
399 f = open(self.path("/etc/sysconfig/desktop"), "w")
400 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
402 if os.path.exists(self.path("/etc/gdm/custom.conf")):
403 f = open(self.path("/etc/skel/.dmrc"), "w")
404 f.write("[Desktop]\n")
405 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
407 if ksdesktop.session:
408 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
409 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
410 f.write("session="+ksdesktop.session.lower()+"\n")
412 if ksdesktop.autologinuser:
413 self._check_sysconfig()
414 f = open(self.path("/etc/sysconfig/desktop"), "a+")
415 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
417 if os.path.exists(self.path("/etc/gdm/custom.conf")):
418 f = open(self.path("/etc/gdm/custom.conf"), "w")
419 f.write("[daemon]\n")
420 f.write("AutomaticLoginEnable=true\n")
421 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
424 class MoblinRepoConfig(KickstartConfig):
425 """A class to apply a kickstart desktop configuration to a system."""
426 def __create_repo_section(self, repo, type, fd):
429 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
430 reponame = repo.name + reposuffix[type]
433 baseurl = repo.baseurl
435 mirrorlist = repo.mirrorlist
437 elif type == "debuginfo":
439 if repo.baseurl.endswith("/"):
440 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
442 baseurl = os.path.dirname(repo.baseurl)
446 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
447 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
448 mirrorlist += "debug" + "-" + variant
450 elif type == "source":
452 if repo.baseurl.endswith("/"):
453 baseurl = os.path.dirname(
455 os.path.dirname(repo.baseurl)))
457 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
461 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
462 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
463 mirrorlist += "source" + "-" + variant
465 fd.write("[" + reponame + "]\n")
466 fd.write("name=" + reponame + "\n")
467 fd.write("failovermethod=priority\n")
469 auth_url = re.compile(AUTH_URL_PTN)
470 m = auth_url.match(baseurl)
472 baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
473 fd.write("baseurl=" + baseurl + "\n")
475 fd.write("mirrorlist=" + mirrorlist + "\n")
476 """ Skip saving proxy settings """
478 # fd.write("proxy=" + repo.proxy + "\n")
479 #if repo.proxy_username:
480 # fd.write("proxy_username=" + repo.proxy_username + "\n")
481 #if repo.proxy_password:
482 # fd.write("proxy_password=" + repo.proxy_password + "\n")
484 fd.write("gpgkey=" + repo.gpgkey + "\n")
485 fd.write("gpgcheck=1\n")
487 fd.write("gpgcheck=0\n")
488 if type == "source" or type == "debuginfo" or repo.disable:
489 fd.write("enabled=0\n")
491 fd.write("enabled=1\n")
494 def __create_repo_file(self, repo, repodir):
495 fs.makedirs(self.path(repodir))
496 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
497 self.__create_repo_section(repo, "base", f)
499 self.__create_repo_section(repo, "debuginfo", f)
501 self.__create_repo_section(repo, "source", f)
505 def apply(self, ksrepo, repodata, repourl):
506 for repo in ksrepo.repoList:
507 if repo.name in repourl:
508 repo.baseurl = repourl[repo.name]
510 #self.__create_repo_file(repo, "/etc/yum.repos.d")
511 self.__create_repo_file(repo, "/etc/zypp/repos.d")
512 """ Import repo gpg keys """
514 for repo in repodata:
517 "--root=%s" % self.instroot,
521 class RPMMacroConfig(KickstartConfig):
522 """A class to apply the specified rpm macros to the filesystem"""
527 if not os.path.exists(self.path("/etc/rpm")):
528 os.mkdir(self.path("/etc/rpm"))
529 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
531 f.write("%_excludedocs 1\n")
532 f.write("%__file_context_path %{nil}\n")
533 if inst_langs(ks) != None:
534 f.write("%_install_langs ")
535 f.write(inst_langs(ks))
539 class NetworkConfig(KickstartConfig):
540 """A class to apply a kickstart network configuration to a system."""
541 def write_ifcfg(self, network):
542 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
547 f.write("DEVICE=%s\n" % network.device)
548 f.write("BOOTPROTO=%s\n" % network.bootProto)
550 if network.bootProto.lower() == "static":
552 f.write("IPADDR=%s\n" % network.ip)
554 f.write("NETMASK=%s\n" % network.netmask)
557 f.write("ONBOOT=on\n")
559 f.write("ONBOOT=off\n")
562 f.write("ESSID=%s\n" % network.essid)
565 if network.ethtool.find("autoneg") == -1:
566 network.ethtool = "autoneg off " + network.ethtool
567 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
569 if network.bootProto.lower() == "dhcp":
571 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
572 if network.dhcpclass:
573 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
576 f.write("MTU=%s\n" % network.mtu)
580 def write_wepkey(self, network):
581 if not network.wepkey:
584 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
587 f.write("KEY=%s\n" % network.wepkey)
590 def write_sysconfig(self, useipv6, hostname, gateway):
591 path = self.path("/etc/sysconfig/network")
595 f.write("NETWORKING=yes\n")
598 f.write("NETWORKING_IPV6=yes\n")
600 f.write("NETWORKING_IPV6=no\n")
603 f.write("HOSTNAME=%s\n" % hostname)
605 f.write("HOSTNAME=localhost.localdomain\n")
608 f.write("GATEWAY=%s\n" % gateway)
612 def write_hosts(self, hostname):
614 if hostname and hostname != "localhost.localdomain":
615 localline += hostname + " "
616 l = hostname.split(".")
618 localline += l[0] + " "
619 localline += "localhost.localdomain localhost"
621 path = self.path("/etc/hosts")
624 f.write("127.0.0.1\t\t%s\n" % localline)
625 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
628 def write_resolv(self, nodns, nameservers):
629 if nodns or not nameservers:
632 path = self.path("/etc/resolv.conf")
636 for ns in (nameservers):
638 f.write("nameserver %s\n" % ns)
643 def apply(self, ksnet):
644 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
652 for network in ksnet.network:
653 if not network.device:
654 raise errors.KsError("No --device specified with "
655 "network kickstart command")
657 if (network.onboot and network.bootProto.lower() != "dhcp" and
658 not (network.ip and network.netmask)):
659 raise errors.KsError("No IP address and/or netmask "
660 "specified with static "
661 "configuration for '%s'" %
664 self.write_ifcfg(network)
665 self.write_wepkey(network)
673 hostname = network.hostname
675 gateway = network.gateway
677 if network.nameserver:
678 nameservers = network.nameserver.split(",")
680 self.write_sysconfig(useipv6, hostname, gateway)
681 self.write_hosts(hostname)
682 self.write_resolv(nodns, nameservers)
685 def get_image_size(ks, default = None):
687 for p in ks.handler.partition.partitions:
688 if p.mountpoint == "/" and p.size:
691 return int(__size) * 1024L * 1024L
695 def get_image_fstype(ks, default = None):
696 for p in ks.handler.partition.partitions:
697 if p.mountpoint == "/" and p.fstype:
701 def get_image_fsopts(ks, default = None):
702 for p in ks.handler.partition.partitions:
703 if p.mountpoint == "/" and p.fsopts:
709 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
710 devices.append(ks.handler.device)
712 devices.extend(ks.handler.device.deviceList)
715 for device in devices:
716 if not device.moduleName:
718 modules.extend(device.moduleName.split(":"))
722 def get_timeout(ks, default = None):
723 if not hasattr(ks.handler.bootloader, "timeout"):
725 if ks.handler.bootloader.timeout is None:
727 return int(ks.handler.bootloader.timeout)
729 def get_kernel_args(ks, default = "ro liveimg"):
730 if not hasattr(ks.handler.bootloader, "appendLine"):
732 if ks.handler.bootloader.appendLine is None:
734 return "%s %s" %(default, ks.handler.bootloader.appendLine)
736 def get_menu_args(ks, default = ""):
737 if not hasattr(ks.handler.bootloader, "menus"):
739 if ks.handler.bootloader.menus in (None, ""):
741 return "%s" % ks.handler.bootloader.menus
743 def get_default_kernel(ks, default = None):
744 if not hasattr(ks.handler.bootloader, "default"):
746 if not ks.handler.bootloader.default:
748 return ks.handler.bootloader.default
750 def get_repos(ks, repo_urls = {}):
752 for repo in ks.handler.repo.repoList:
754 if hasattr(repo, "includepkgs"):
755 inc.extend(repo.includepkgs)
758 if hasattr(repo, "excludepkgs"):
759 exc.extend(repo.excludepkgs)
761 baseurl = repo.baseurl
762 mirrorlist = repo.mirrorlist
764 if repo.name in repo_urls:
765 baseurl = repo_urls[repo.name]
768 if repos.has_key(repo.name):
769 msger.warning("Overriding already specified repo %s" %(repo.name,))
772 if hasattr(repo, "proxy"):
774 proxy_username = None
775 if hasattr(repo, "proxy_username"):
776 proxy_username = repo.proxy_username
777 proxy_password = None
778 if hasattr(repo, "proxy_password"):
779 proxy_password = repo.proxy_password
780 if hasattr(repo, "debuginfo"):
781 debuginfo = repo.debuginfo
782 if hasattr(repo, "source"):
784 if hasattr(repo, "gpgkey"):
786 if hasattr(repo, "disable"):
787 disable = repo.disable
789 if hasattr(repo, "ssl_verify"):
790 ssl_verify = repo.ssl_verify == "yes"
792 if hasattr(repo, "cost"):
795 if hasattr(repo, "priority"):
796 priority = repo.priority
798 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
799 proxy, proxy_username, proxy_password, debuginfo,
800 source, gpgkey, disable, ssl_verify, cost, priority)
802 return repos.values()
804 def convert_method_to_repo(ks):
806 ks.handler.repo.methodToRepo()
807 except (AttributeError, kserrors.KickstartError):
810 def get_attachment(ks, required = []):
811 return ks.handler.attachment.packageList + required
813 def get_pre_packages(ks, required = []):
814 return ks.handler.prepackages.packageList + required
816 def get_packages(ks, required = []):
817 return ks.handler.packages.packageList + required
819 def get_groups(ks, required = []):
820 return ks.handler.packages.groupList + required
822 def get_excluded(ks, required = []):
823 return ks.handler.packages.excludedList + required
825 def get_partitions(ks, required = []):
826 return ks.handler.partition.partitions
828 def ignore_missing(ks):
829 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
831 def exclude_docs(ks):
832 return ks.handler.packages.excludeDocs
835 if hasattr(ks.handler.packages, "instLange"):
836 return ks.handler.packages.instLange
837 elif hasattr(ks.handler.packages, "instLangs"):
838 return ks.handler.packages.instLangs
841 def get_post_scripts(ks):
843 for s in ks.handler.scripts:
844 if s.type != ksparser.KS_SCRIPT_POST:
849 def add_repo(ks, repostr):
850 args = repostr.split()
851 repoobj = ks.handler.repo.parse(args[1:])
852 if repoobj and repoobj not in ks.handler.repo.repoList:
853 ks.handler.repo.repoList.append(repoobj)
855 def remove_all_repos(ks):
856 while len(ks.handler.repo.repoList) != 0:
857 del ks.handler.repo.repoList[0]
859 def remove_duplicate_repos(ks):
863 if len(ks.handler.repo.repoList) < 2:
865 if i >= len(ks.handler.repo.repoList) - 1:
867 name = ks.handler.repo.repoList[i].name
868 baseurl = ks.handler.repo.repoList[i].baseurl
869 if j < len(ks.handler.repo.repoList):
870 if (ks.handler.repo.repoList[j].name == name or \
871 ks.handler.repo.repoList[j].baseurl == baseurl):
872 del ks.handler.repo.repoList[j]
875 if j >= len(ks.handler.repo.repoList):
882 def resolve_groups(creatoropts, repometadata):
884 if 'zypp' == creatoropts['pkgmgr']:
886 ks = creatoropts['ks']
888 for repo in repometadata:
889 """ Mustn't replace group with package list if repo is ready for the
890 corresponding package manager.
893 if iszypp and repo["patterns"]:
895 if not iszypp and repo["comps"]:
898 # But we also must handle such cases, use zypp but repo only has comps,
899 # use yum but repo only has patterns, use zypp but use_comps is true,
900 # use yum but use_comps is false.
902 if iszypp and repo["comps"]:
903 groupfile = repo["comps"]
904 get_pkglist_handler = misc.get_pkglist_in_comps
905 if not iszypp and repo["patterns"]:
906 groupfile = repo["patterns"]
907 get_pkglist_handler = misc.get_pkglist_in_patterns
912 if i >= len(ks.handler.packages.groupList):
914 pkglist = get_pkglist_handler(
915 ks.handler.packages.groupList[i].name,
918 del ks.handler.packages.groupList[i]
920 if pkg not in ks.handler.packages.packageList:
921 ks.handler.packages.packageList.append(pkg)