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, ",") ]
334 args += [ "-d", "/home/%s" % userconfig.name ]
335 args.append(userconfig.name)
337 dev_null = os.open("/dev/null", os.O_WRONLY)
338 msger.debug('adding user with %s' % args)
339 subprocess.call(args,
342 preexec_fn = self.chroot)
345 msger.warning('Cannot add user using "useradd"')
347 if userconfig.password not in (None, ""):
348 if userconfig.isCrypted:
349 self.set_encrypted_passwd(userconfig.name,
352 self.set_unencrypted_passwd(userconfig.name,
355 self.set_empty_passwd(userconfig.name)
357 raise errors.KsError("Invalid kickstart command: %s" \
358 % userconfig.__str__())
361 def apply(self, user):
362 for userconfig in user.userList:
364 self.addUser(userconfig)
368 class ServicesConfig(KickstartConfig):
369 """A class to apply a kickstart services configuration to a system."""
371 def apply(self, ksservices):
372 if not os.path.exists(self.path("/sbin/chkconfig")):
374 for s in ksservices.enabled:
375 self.call(["/sbin/chkconfig", s, "on"])
376 for s in ksservices.disabled:
377 self.call(["/sbin/chkconfig", s, "off"])
379 class XConfig(KickstartConfig):
380 """A class to apply a kickstart X configuration to a system."""
382 def apply(self, ksxconfig):
383 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
384 f = open(self.path("/etc/inittab"), "rw+")
386 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
390 if ksxconfig.defaultdesktop:
391 self._check_sysconfig()
392 f = open(self.path("/etc/sysconfig/desktop"), "w")
393 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
396 class DesktopConfig(KickstartConfig):
397 """A class to apply a kickstart desktop configuration to a system."""
399 def apply(self, ksdesktop):
400 if ksdesktop.defaultdesktop:
401 self._check_sysconfig()
402 f = open(self.path("/etc/sysconfig/desktop"), "w")
403 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
405 if os.path.exists(self.path("/etc/gdm/custom.conf")):
406 f = open(self.path("/etc/skel/.dmrc"), "w")
407 f.write("[Desktop]\n")
408 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
410 if ksdesktop.session:
411 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
412 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
413 f.write("session="+ksdesktop.session.lower()+"\n")
415 if ksdesktop.autologinuser:
416 self._check_sysconfig()
417 f = open(self.path("/etc/sysconfig/desktop"), "a+")
418 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
420 if os.path.exists(self.path("/etc/gdm/custom.conf")):
421 f = open(self.path("/etc/gdm/custom.conf"), "w")
422 f.write("[daemon]\n")
423 f.write("AutomaticLoginEnable=true\n")
424 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
427 class MoblinRepoConfig(KickstartConfig):
428 """A class to apply a kickstart desktop configuration to a system."""
429 def __create_repo_section(self, repo, type, fd):
432 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
433 reponame = repo.name + reposuffix[type]
436 baseurl = repo.baseurl
438 mirrorlist = repo.mirrorlist
440 elif type == "debuginfo":
442 if repo.baseurl.endswith("/"):
443 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
445 baseurl = os.path.dirname(repo.baseurl)
449 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
450 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
451 mirrorlist += "debug" + "-" + variant
453 elif type == "source":
455 if repo.baseurl.endswith("/"):
456 baseurl = os.path.dirname(
458 os.path.dirname(repo.baseurl)))
460 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
464 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
465 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
466 mirrorlist += "source" + "-" + variant
468 fd.write("[" + reponame + "]\n")
469 fd.write("name=" + reponame + "\n")
470 fd.write("failovermethod=priority\n")
472 auth_url = re.compile(AUTH_URL_PTN)
473 m = auth_url.match(baseurl)
475 baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
476 fd.write("baseurl=" + baseurl + "\n")
478 fd.write("mirrorlist=" + mirrorlist + "\n")
479 """ Skip saving proxy settings """
481 # fd.write("proxy=" + repo.proxy + "\n")
482 #if repo.proxy_username:
483 # fd.write("proxy_username=" + repo.proxy_username + "\n")
484 #if repo.proxy_password:
485 # fd.write("proxy_password=" + repo.proxy_password + "\n")
487 fd.write("gpgkey=" + repo.gpgkey + "\n")
488 fd.write("gpgcheck=1\n")
490 fd.write("gpgcheck=0\n")
491 if type == "source" or type == "debuginfo" or repo.disable:
492 fd.write("enabled=0\n")
494 fd.write("enabled=1\n")
497 def __create_repo_file(self, repo, repodir):
498 fs.makedirs(self.path(repodir))
499 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
500 self.__create_repo_section(repo, "base", f)
502 self.__create_repo_section(repo, "debuginfo", f)
504 self.__create_repo_section(repo, "source", f)
508 def apply(self, ksrepo, repodata, repourl):
509 for repo in ksrepo.repoList:
510 if repo.name in repourl:
511 repo.baseurl = repourl[repo.name]
513 #self.__create_repo_file(repo, "/etc/yum.repos.d")
514 self.__create_repo_file(repo, "/etc/zypp/repos.d")
515 """ Import repo gpg keys """
517 for repo in repodata:
520 "--root=%s" % self.instroot,
524 class RPMMacroConfig(KickstartConfig):
525 """A class to apply the specified rpm macros to the filesystem"""
530 if not os.path.exists(self.path("/etc/rpm")):
531 os.mkdir(self.path("/etc/rpm"))
532 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
534 f.write("%_excludedocs 1\n")
535 f.write("%__file_context_path %{nil}\n")
536 if inst_langs(ks) != None:
537 f.write("%_install_langs ")
538 f.write(inst_langs(ks))
542 class NetworkConfig(KickstartConfig):
543 """A class to apply a kickstart network configuration to a system."""
544 def write_ifcfg(self, network):
545 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
550 f.write("DEVICE=%s\n" % network.device)
551 f.write("BOOTPROTO=%s\n" % network.bootProto)
553 if network.bootProto.lower() == "static":
555 f.write("IPADDR=%s\n" % network.ip)
557 f.write("NETMASK=%s\n" % network.netmask)
560 f.write("ONBOOT=on\n")
562 f.write("ONBOOT=off\n")
565 f.write("ESSID=%s\n" % network.essid)
568 if network.ethtool.find("autoneg") == -1:
569 network.ethtool = "autoneg off " + network.ethtool
570 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
572 if network.bootProto.lower() == "dhcp":
574 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
575 if network.dhcpclass:
576 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
579 f.write("MTU=%s\n" % network.mtu)
583 def write_wepkey(self, network):
584 if not network.wepkey:
587 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
590 f.write("KEY=%s\n" % network.wepkey)
593 def write_sysconfig(self, useipv6, hostname, gateway):
594 path = self.path("/etc/sysconfig/network")
598 f.write("NETWORKING=yes\n")
601 f.write("NETWORKING_IPV6=yes\n")
603 f.write("NETWORKING_IPV6=no\n")
606 f.write("HOSTNAME=%s\n" % hostname)
608 f.write("HOSTNAME=localhost.localdomain\n")
611 f.write("GATEWAY=%s\n" % gateway)
615 def write_hosts(self, hostname):
617 if hostname and hostname != "localhost.localdomain":
618 localline += hostname + " "
619 l = hostname.split(".")
621 localline += l[0] + " "
622 localline += "localhost.localdomain localhost"
624 path = self.path("/etc/hosts")
627 f.write("127.0.0.1\t\t%s\n" % localline)
628 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
631 def write_resolv(self, nodns, nameservers):
632 if nodns or not nameservers:
635 path = self.path("/etc/resolv.conf")
639 for ns in (nameservers):
641 f.write("nameserver %s\n" % ns)
646 def apply(self, ksnet):
647 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
655 for network in ksnet.network:
656 if not network.device:
657 raise errors.KsError("No --device specified with "
658 "network kickstart command")
660 if (network.onboot and network.bootProto.lower() != "dhcp" and
661 not (network.ip and network.netmask)):
662 raise errors.KsError("No IP address and/or netmask "
663 "specified with static "
664 "configuration for '%s'" %
667 self.write_ifcfg(network)
668 self.write_wepkey(network)
676 hostname = network.hostname
678 gateway = network.gateway
680 if network.nameserver:
681 nameservers = network.nameserver.split(",")
683 self.write_sysconfig(useipv6, hostname, gateway)
684 self.write_hosts(hostname)
685 self.write_resolv(nodns, nameservers)
688 def get_image_size(ks, default = None):
690 for p in ks.handler.partition.partitions:
691 if p.mountpoint == "/" and p.size:
694 return int(__size) * 1024L * 1024L
698 def get_image_fstype(ks, default = None):
699 for p in ks.handler.partition.partitions:
700 if p.mountpoint == "/" and p.fstype:
704 def get_image_fsopts(ks, default = None):
705 for p in ks.handler.partition.partitions:
706 if p.mountpoint == "/" and p.fsopts:
712 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
713 devices.append(ks.handler.device)
715 devices.extend(ks.handler.device.deviceList)
718 for device in devices:
719 if not device.moduleName:
721 modules.extend(device.moduleName.split(":"))
725 def get_timeout(ks, default = None):
726 if not hasattr(ks.handler.bootloader, "timeout"):
728 if ks.handler.bootloader.timeout is None:
730 return int(ks.handler.bootloader.timeout)
732 def get_kernel_args(ks, default = "ro rd.live.image"):
733 if not hasattr(ks.handler.bootloader, "appendLine"):
735 if ks.handler.bootloader.appendLine is None:
737 return "%s %s" %(default, ks.handler.bootloader.appendLine)
739 def get_menu_args(ks, default = ""):
740 if not hasattr(ks.handler.bootloader, "menus"):
742 if ks.handler.bootloader.menus in (None, ""):
744 return "%s" % ks.handler.bootloader.menus
746 def get_default_kernel(ks, default = None):
747 if not hasattr(ks.handler.bootloader, "default"):
749 if not ks.handler.bootloader.default:
751 return ks.handler.bootloader.default
753 def get_repos(ks, repo_urls = {}):
755 for repo in ks.handler.repo.repoList:
757 if hasattr(repo, "includepkgs"):
758 inc.extend(repo.includepkgs)
761 if hasattr(repo, "excludepkgs"):
762 exc.extend(repo.excludepkgs)
764 baseurl = repo.baseurl
765 mirrorlist = repo.mirrorlist
767 if repo.name in repo_urls:
768 baseurl = repo_urls[repo.name]
771 if repos.has_key(repo.name):
772 msger.warning("Overriding already specified repo %s" %(repo.name,))
775 if hasattr(repo, "proxy"):
777 proxy_username = None
778 if hasattr(repo, "proxy_username"):
779 proxy_username = repo.proxy_username
780 proxy_password = None
781 if hasattr(repo, "proxy_password"):
782 proxy_password = repo.proxy_password
783 if hasattr(repo, "debuginfo"):
784 debuginfo = repo.debuginfo
785 if hasattr(repo, "source"):
787 if hasattr(repo, "gpgkey"):
789 if hasattr(repo, "disable"):
790 disable = repo.disable
792 if hasattr(repo, "ssl_verify"):
793 ssl_verify = repo.ssl_verify == "yes"
795 if hasattr(repo, "cost"):
798 if hasattr(repo, "priority"):
799 priority = repo.priority
801 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
802 proxy, proxy_username, proxy_password, debuginfo,
803 source, gpgkey, disable, ssl_verify, cost, priority)
805 return repos.values()
807 def convert_method_to_repo(ks):
809 ks.handler.repo.methodToRepo()
810 except (AttributeError, kserrors.KickstartError):
813 def get_attachment(ks, required = []):
814 return ks.handler.attachment.packageList + required
816 def get_pre_packages(ks, required = []):
817 return ks.handler.prepackages.packageList + required
819 def get_packages(ks, required = []):
820 return ks.handler.packages.packageList + required
822 def get_groups(ks, required = []):
823 return ks.handler.packages.groupList + required
825 def get_excluded(ks, required = []):
826 return ks.handler.packages.excludedList + required
828 def get_partitions(ks, required = []):
829 return ks.handler.partition.partitions
831 def ignore_missing(ks):
832 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
834 def exclude_docs(ks):
835 return ks.handler.packages.excludeDocs
838 if hasattr(ks.handler.packages, "instLange"):
839 return ks.handler.packages.instLange
840 elif hasattr(ks.handler.packages, "instLangs"):
841 return ks.handler.packages.instLangs
844 def get_post_scripts(ks):
846 for s in ks.handler.scripts:
847 if s.type != ksparser.KS_SCRIPT_POST:
852 def add_repo(ks, repostr):
853 args = repostr.split()
854 repoobj = ks.handler.repo.parse(args[1:])
855 if repoobj and repoobj not in ks.handler.repo.repoList:
856 ks.handler.repo.repoList.append(repoobj)
858 def remove_all_repos(ks):
859 while len(ks.handler.repo.repoList) != 0:
860 del ks.handler.repo.repoList[0]
862 def remove_duplicate_repos(ks):
866 if len(ks.handler.repo.repoList) < 2:
868 if i >= len(ks.handler.repo.repoList) - 1:
870 name = ks.handler.repo.repoList[i].name
871 baseurl = ks.handler.repo.repoList[i].baseurl
872 if j < len(ks.handler.repo.repoList):
873 if (ks.handler.repo.repoList[j].name == name or \
874 ks.handler.repo.repoList[j].baseurl == baseurl):
875 del ks.handler.repo.repoList[j]
878 if j >= len(ks.handler.repo.repoList):
885 def resolve_groups(creatoropts, repometadata):
887 if 'zypp' == creatoropts['pkgmgr']:
889 ks = creatoropts['ks']
891 for repo in repometadata:
892 """ Mustn't replace group with package list if repo is ready for the
893 corresponding package manager.
896 if iszypp and repo["patterns"]:
898 if not iszypp and repo["comps"]:
901 # But we also must handle such cases, use zypp but repo only has comps,
902 # use yum but repo only has patterns, use zypp but use_comps is true,
903 # use yum but use_comps is false.
905 if iszypp and repo["comps"]:
906 groupfile = repo["comps"]
907 get_pkglist_handler = misc.get_pkglist_in_comps
908 if not iszypp and repo["patterns"]:
909 groupfile = repo["patterns"]
910 get_pkglist_handler = misc.get_pkglist_in_patterns
915 if i >= len(ks.handler.packages.groupList):
917 pkglist = get_pkglist_handler(
918 ks.handler.packages.groupList[i].name,
921 del ks.handler.packages.groupList[i]
923 if pkg not in ks.handler.packages.packageList:
924 ks.handler.packages.packageList.append(pkg)