3 # Copyright (c) 2007 Red Hat, Inc.
4 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 from mic.utils import errors, misc, runner, fs_related as fs
28 import pykickstart.sections as kssections
29 import pykickstart.commands as kscommands
30 import pykickstart.constants as ksconstants
31 import pykickstart.errors as kserrors
32 import pykickstart.parser as ksparser
33 import pykickstart.version as ksversion
34 from pykickstart.handlers.control import commandMap
35 from pykickstart.handlers.control import dataMap
37 import custom_commands.desktop as desktop
38 import custom_commands.moblinrepo as moblinrepo
39 import custom_commands.micboot as micboot
40 import custom_commands.partition as partition
42 class PrepackageSection(kssections.Section):
43 sectionOpen = "%prepackages"
45 def handleLine(self, line):
49 (h, s, t) = line.partition('#')
52 self.handler.prepackages.add([line])
54 def handleHeader(self, lineno, args):
55 kssections.Section.handleHeader(self, lineno, args)
57 class AttachmentSection(kssections.Section):
58 sectionOpen = "%attachment"
60 def handleLine(self, line):
64 (h, s, t) = line.partition('#')
67 self.handler.attachment.add([line])
69 def handleHeader(self, lineno, args):
70 kssections.Section.handleHeader(self, lineno, args)
72 def apply_wrapper(func):
73 def wrapper(*kargs, **kwargs):
75 func(*kargs, **kwargs)
76 except (OSError, IOError, errors.KsError), err:
77 cfgcls = kargs[0].__class__.__name__
78 if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
79 msger.warning("%s" % err)
82 # just throw out the exception
86 def read_kickstart(path):
87 """Parse a kickstart file and return a KickstartParser instance.
89 This is a simple utility function which takes a path to a kickstart file,
90 parses it and returns a pykickstart KickstartParser instance which can
91 be then passed to an ImageCreator constructor.
93 If an error occurs, a CreatorError exception is thrown.
96 #version = ksversion.makeVersion()
97 #ks = ksparser.KickstartParser(version)
99 using_version = ksversion.DEVEL
100 commandMap[using_version]["desktop"] = desktop.Moblin_Desktop
101 commandMap[using_version]["repo"] = moblinrepo.Moblin_Repo
102 commandMap[using_version]["bootloader"] = micboot.Moblin_Bootloader
103 commandMap[using_version]["part"] = partition.MeeGo_Partition
104 commandMap[using_version]["partition"] = partition.MeeGo_Partition
105 dataMap[using_version]["RepoData"] = moblinrepo.Moblin_RepoData
106 dataMap[using_version]["PartData"] = partition.MeeGo_PartData
107 superclass = ksversion.returnClassForVersion(version=using_version)
109 class KSHandlers(superclass):
110 def __init__(self, mapping={}):
111 superclass.__init__(self, mapping=commandMap[using_version])
112 self.prepackages = ksparser.Packages()
113 self.attachment = ksparser.Packages()
115 ks = ksparser.KickstartParser(KSHandlers())
116 ks.registerSection(PrepackageSection(ks.handler))
117 ks.registerSection(AttachmentSection(ks.handler))
120 ks.readKickstart(path)
121 except kserrors.KickstartParseError, e:
122 msgptn = re.compile("^\D*(\d+).*(Section does not end with.*)$", re.S)
123 m = msgptn.match(str(e))
127 msger.warning("'%s:%s': %s" % (path, lineno, wrnmsg))
129 raise errors.KsError("'%s': %s" % (path, str(e)))
130 except kserrors.KickstartError, e:
131 raise errors.KsError("'%s': %s" % (path, str(e)))
134 def build_name(kscfg, prefix = None, suffix = None, maxlen = None):
135 """Construct and return an image name string.
137 This is a utility function to help create sensible name and fslabel
138 strings. The name is constructed using the sans-prefix-and-extension
139 kickstart filename and the supplied prefix and suffix.
141 If the name exceeds the maxlen length supplied, the prefix is first dropped
142 and then the kickstart filename portion is reduced until it fits. In other
143 words, the suffix takes precedence over the kickstart portion and the
144 kickstart portion takes precedence over the prefix.
146 kscfg -- a path to a kickstart file
147 prefix -- a prefix to prepend to the name; defaults to None, which causes
149 suffix -- a suffix to append to the name; defaults to None, which causes
150 a YYYYMMDDHHMM suffix to be used
151 maxlen -- the maximum length for the returned string; defaults to None,
152 which means there is no restriction on the name length
154 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
157 name = os.path.basename(kscfg)
158 idx = name.rfind('.')
165 suffix = time.strftime("%Y%m%d%H%M")
167 if name.startswith(prefix):
168 name = name[len(prefix):]
170 ret = prefix + name + "-" + suffix
171 if not maxlen is None and len(ret) > maxlen:
172 ret = name[:maxlen - len(suffix) - 1] + "-" + suffix
176 class KickstartConfig(object):
177 """A base class for applying kickstart configurations to a system."""
178 def __init__(self, instroot):
179 self.instroot = instroot
181 def path(self, subpath):
182 return self.instroot + subpath
184 def _check_sysconfig(self):
185 if not os.path.exists(self.path("/etc/sysconfig")):
186 fs.makedirs(self.path("/etc/sysconfig"))
189 os.chroot(self.instroot)
192 def call(self, args):
193 if not os.path.exists("%s/%s" %(self.instroot, args[0])):
194 raise errors.KsError("Can't find %s in chroot" % args[0])
195 subprocess.call(args, preexec_fn = self.chroot)
200 class LanguageConfig(KickstartConfig):
201 """A class to apply a kickstart language configuration to a system."""
203 def apply(self, kslang):
204 self._check_sysconfig()
206 f = open(self.path("/etc/sysconfig/i18n"), "w+")
207 f.write("LANG=\"" + kslang.lang + "\"\n")
210 class KeyboardConfig(KickstartConfig):
211 """A class to apply a kickstart keyboard configuration to a system."""
213 def apply(self, kskeyboard):
216 # should this impact the X keyboard config too?
217 # or do we want to make X be able to do this mapping?
219 #k = rhpl.keyboard.Keyboard()
220 #if kskeyboard.keyboard:
221 # k.set(kskeyboard.keyboard)
222 #k.write(self.instroot)
225 class TimezoneConfig(KickstartConfig):
226 """A class to apply a kickstart timezone configuration to a system."""
228 def apply(self, kstimezone):
229 self._check_sysconfig()
230 tz = kstimezone.timezone or "America/New_York"
231 utc = str(kstimezone.isUtc)
233 f = open(self.path("/etc/sysconfig/clock"), "w+")
234 f.write("ZONE=\"" + tz + "\"\n")
235 f.write("UTC=" + utc + "\n")
237 tz_source = "/usr/share/zoneinfo/%s" % (tz)
238 tz_dest = "/etc/localtime"
240 cpcmd = fs.find_binary_inchroot('cp', self.instroot)
242 self.call([cpcmd, "-f", tz_source, tz_dest])
244 cpcmd = fs.find_binary_path('cp')
245 subprocess.call([cpcmd, "-f",
246 self.path(tz_source),
248 except (IOError, OSError), (errno, msg):
249 raise errors.KsError("Timezone setting error: %s" % msg)
251 class AuthConfig(KickstartConfig):
252 """A class to apply a kickstart authconfig configuration to a system."""
254 def apply(self, ksauthconfig):
255 auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
256 args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
257 self.call(args + auth.split())
259 class FirewallConfig(KickstartConfig):
260 """A class to apply a kickstart firewall configuration to a system."""
262 def apply(self, ksfirewall):
264 # FIXME: should handle the rest of the options
266 if not os.path.exists(self.path("/usr/sbin/lokkit")):
268 if ksfirewall.enabled:
271 status = "--disabled"
273 self.call(["/usr/sbin/lokkit",
274 "-f", "--quiet", "--nostart", status])
276 class RootPasswordConfig(KickstartConfig):
277 """A class to apply a kickstart root password configuration to a system."""
279 self.call(["/usr/bin/passwd", "-d", "root"])
281 def set_encrypted(self, password):
282 self.call(["/usr/sbin/usermod", "-p", password, "root"])
284 def set_unencrypted(self, password):
285 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
286 if not os.path.exists("%s/%s" %(self.instroot, p)):
287 raise errors.KsError("Unable to set unencrypted password due "
290 p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
291 stdout = subprocess.PIPE,
292 preexec_fn = self.chroot)
293 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
295 stdout = subprocess.PIPE,
296 preexec_fn = self.chroot)
300 def apply(self, ksrootpw):
301 if ksrootpw.isCrypted:
302 self.set_encrypted(ksrootpw.password)
303 elif ksrootpw.password != "":
304 self.set_unencrypted(ksrootpw.password)
308 class UserConfig(KickstartConfig):
309 def set_empty_passwd(self, user):
310 self.call(["/usr/bin/passwd", "-d", user])
312 def set_encrypted_passwd(self, user, password):
313 self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
315 def set_unencrypted_passwd(self, user, password):
316 for p in ("/bin/echo", "/usr/sbin/chpasswd"):
317 if not os.path.exists("%s/%s" %(self.instroot, p)):
318 raise errors.KsError("Unable to set unencrypted password due "
321 p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
322 stdout = subprocess.PIPE,
323 preexec_fn = self.chroot)
324 p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
326 stdout = subprocess.PIPE,
327 preexec_fn = self.chroot)
330 def addUser(self, userconfig):
331 args = [ "/usr/sbin/useradd" ]
332 if userconfig.groups:
333 args += [ "--groups", string.join(userconfig.groups, ",") ]
335 args.append(userconfig.name)
337 dev_null = os.open("/dev/null", os.O_WRONLY)
338 subprocess.call(args,
341 preexec_fn = self.chroot)
344 msger.warning('Cannot add user using "useradd"')
346 if userconfig.password not in (None, ""):
347 if userconfig.isCrypted:
348 self.set_encrypted_passwd(userconfig.name,
351 self.set_unencrypted_passwd(userconfig.name,
354 self.set_empty_passwd(userconfig.name)
356 raise errors.KsError("Invalid kickstart command: %s" \
357 % userconfig.__str__())
360 def apply(self, user):
361 for userconfig in user.userList:
363 self.addUser(userconfig)
367 class ServicesConfig(KickstartConfig):
368 """A class to apply a kickstart services configuration to a system."""
370 def apply(self, ksservices):
371 if not os.path.exists(self.path("/sbin/chkconfig")):
373 for s in ksservices.enabled:
374 self.call(["/sbin/chkconfig", s, "on"])
375 for s in ksservices.disabled:
376 self.call(["/sbin/chkconfig", s, "off"])
378 class XConfig(KickstartConfig):
379 """A class to apply a kickstart X configuration to a system."""
381 def apply(self, ksxconfig):
382 if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
383 f = open(self.path("/etc/inittab"), "rw+")
385 buf = buf.replace("id:3:initdefault", "id:5:initdefault")
389 if ksxconfig.defaultdesktop:
390 self._check_sysconfig()
391 f = open(self.path("/etc/sysconfig/desktop"), "w")
392 f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
395 class DesktopConfig(KickstartConfig):
396 """A class to apply a kickstart desktop configuration to a system."""
398 def apply(self, ksdesktop):
399 if ksdesktop.defaultdesktop:
400 self._check_sysconfig()
401 f = open(self.path("/etc/sysconfig/desktop"), "w")
402 f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
404 if os.path.exists(self.path("/etc/gdm/custom.conf")):
405 f = open(self.path("/etc/skel/.dmrc"), "w")
406 f.write("[Desktop]\n")
407 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
409 if ksdesktop.session:
410 if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
411 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
412 f.write("session="+ksdesktop.session.lower()+"\n")
414 if ksdesktop.autologinuser:
415 self._check_sysconfig()
416 f = open(self.path("/etc/sysconfig/desktop"), "a+")
417 f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
419 if os.path.exists(self.path("/etc/gdm/custom.conf")):
420 f = open(self.path("/etc/gdm/custom.conf"), "w")
421 f.write("[daemon]\n")
422 f.write("AutomaticLoginEnable=true\n")
423 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
426 class MoblinRepoConfig(KickstartConfig):
427 """A class to apply a kickstart desktop configuration to a system."""
428 def __create_repo_section(self, repo, type, fd):
431 reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
432 reponame = repo.name + reposuffix[type]
435 baseurl = repo.baseurl
437 mirrorlist = repo.mirrorlist
439 elif type == "debuginfo":
441 if repo.baseurl.endswith("/"):
442 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
444 baseurl = os.path.dirname(repo.baseurl)
448 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
449 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
450 mirrorlist += "debug" + "-" + variant
452 elif type == "source":
454 if repo.baseurl.endswith("/"):
455 baseurl = os.path.dirname(
457 os.path.dirname(repo.baseurl)))
459 baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
463 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
464 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
465 mirrorlist += "source" + "-" + variant
467 fd.write("[" + reponame + "]\n")
468 fd.write("name=" + reponame + "\n")
469 fd.write("failovermethod=priority\n")
471 fd.write("baseurl=" + baseurl + "\n")
473 fd.write("mirrorlist=" + mirrorlist + "\n")
474 """ Skip saving proxy settings """
476 # fd.write("proxy=" + repo.proxy + "\n")
477 #if repo.proxy_username:
478 # fd.write("proxy_username=" + repo.proxy_username + "\n")
479 #if repo.proxy_password:
480 # fd.write("proxy_password=" + repo.proxy_password + "\n")
482 fd.write("gpgkey=" + repo.gpgkey + "\n")
483 fd.write("gpgcheck=1\n")
485 fd.write("gpgcheck=0\n")
486 if type == "source" or type == "debuginfo" or repo.disable:
487 fd.write("enabled=0\n")
489 fd.write("enabled=1\n")
492 def __create_repo_file(self, repo, repodir):
493 fs.makedirs(self.path(repodir))
494 f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
495 self.__create_repo_section(repo, "base", f)
497 self.__create_repo_section(repo, "debuginfo", f)
499 self.__create_repo_section(repo, "source", f)
503 def apply(self, ksrepo, repodata):
504 for repo in ksrepo.repoList:
506 #self.__create_repo_file(repo, "/etc/yum.repos.d")
507 self.__create_repo_file(repo, "/etc/zypp/repos.d")
508 """ Import repo gpg keys """
510 for repo in repodata:
513 "--root=%s" % self.instroot,
517 class RPMMacroConfig(KickstartConfig):
518 """A class to apply the specified rpm macros to the filesystem"""
523 if not os.path.exists(self.path("/etc/rpm")):
524 os.mkdir(self.path("/etc/rpm"))
525 f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
527 f.write("%_excludedocs 1\n")
528 f.write("%__file_context_path %{nil}\n")
529 if inst_langs(ks) != None:
530 f.write("%_install_langs ")
531 f.write(inst_langs(ks))
535 class NetworkConfig(KickstartConfig):
536 """A class to apply a kickstart network configuration to a system."""
537 def write_ifcfg(self, network):
538 p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
543 f.write("DEVICE=%s\n" % network.device)
544 f.write("BOOTPROTO=%s\n" % network.bootProto)
546 if network.bootProto.lower() == "static":
548 f.write("IPADDR=%s\n" % network.ip)
550 f.write("NETMASK=%s\n" % network.netmask)
553 f.write("ONBOOT=on\n")
555 f.write("ONBOOT=off\n")
558 f.write("ESSID=%s\n" % network.essid)
561 if network.ethtool.find("autoneg") == -1:
562 network.ethtool = "autoneg off " + network.ethtool
563 f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
565 if network.bootProto.lower() == "dhcp":
567 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
568 if network.dhcpclass:
569 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
572 f.write("MTU=%s\n" % network.mtu)
576 def write_wepkey(self, network):
577 if not network.wepkey:
580 p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
583 f.write("KEY=%s\n" % network.wepkey)
586 def write_sysconfig(self, useipv6, hostname, gateway):
587 path = self.path("/etc/sysconfig/network")
591 f.write("NETWORKING=yes\n")
594 f.write("NETWORKING_IPV6=yes\n")
596 f.write("NETWORKING_IPV6=no\n")
599 f.write("HOSTNAME=%s\n" % hostname)
601 f.write("HOSTNAME=localhost.localdomain\n")
604 f.write("GATEWAY=%s\n" % gateway)
608 def write_hosts(self, hostname):
610 if hostname and hostname != "localhost.localdomain":
611 localline += hostname + " "
612 l = hostname.split(".")
614 localline += l[0] + " "
615 localline += "localhost.localdomain localhost"
617 path = self.path("/etc/hosts")
620 f.write("127.0.0.1\t\t%s\n" % localline)
621 f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
624 def write_resolv(self, nodns, nameservers):
625 if nodns or not nameservers:
628 path = self.path("/etc/resolv.conf")
632 for ns in (nameservers):
634 f.write("nameserver %s\n" % ns)
639 def apply(self, ksnet):
640 fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
648 for network in ksnet.network:
649 if not network.device:
650 raise errors.KsError("No --device specified with "
651 "network kickstart command")
653 if (network.onboot and network.bootProto.lower() != "dhcp" and
654 not (network.ip and network.netmask)):
655 raise errors.KsError("No IP address and/or netmask "
656 "specified with static "
657 "configuration for '%s'" %
660 self.write_ifcfg(network)
661 self.write_wepkey(network)
669 hostname = network.hostname
671 gateway = network.gateway
673 if network.nameserver:
674 nameservers = network.nameserver.split(",")
676 self.write_sysconfig(useipv6, hostname, gateway)
677 self.write_hosts(hostname)
678 self.write_resolv(nodns, nameservers)
681 def get_image_size(ks, default = None):
683 for p in ks.handler.partition.partitions:
684 if p.mountpoint == "/" and p.size:
687 return int(__size) * 1024L * 1024L
691 def get_image_fstype(ks, default = None):
692 for p in ks.handler.partition.partitions:
693 if p.mountpoint == "/" and p.fstype:
697 def get_image_fsopts(ks, default = None):
698 for p in ks.handler.partition.partitions:
699 if p.mountpoint == "/" and p.fsopts:
705 if isinstance(ks.handler.device, kscommands.device.FC3_Device):
706 devices.append(ks.handler.device)
708 devices.extend(ks.handler.device.deviceList)
711 for device in devices:
712 if not device.moduleName:
714 modules.extend(device.moduleName.split(":"))
718 def get_timeout(ks, default = None):
719 if not hasattr(ks.handler.bootloader, "timeout"):
721 if ks.handler.bootloader.timeout is None:
723 return int(ks.handler.bootloader.timeout)
725 def get_kernel_args(ks, default = "ro liveimg"):
726 if not hasattr(ks.handler.bootloader, "appendLine"):
728 if ks.handler.bootloader.appendLine is None:
730 return "%s %s" %(default, ks.handler.bootloader.appendLine)
732 def get_menu_args(ks, default = ""):
733 if not hasattr(ks.handler.bootloader, "menus"):
735 if ks.handler.bootloader.menus in (None, ""):
737 return "%s" % ks.handler.bootloader.menus
739 def get_default_kernel(ks, default = None):
740 if not hasattr(ks.handler.bootloader, "default"):
742 if not ks.handler.bootloader.default:
744 return ks.handler.bootloader.default
746 def get_repos(ks, repo_urls = {}):
748 for repo in ks.handler.repo.repoList:
750 if hasattr(repo, "includepkgs"):
751 inc.extend(repo.includepkgs)
754 if hasattr(repo, "excludepkgs"):
755 exc.extend(repo.excludepkgs)
757 baseurl = repo.baseurl
758 mirrorlist = repo.mirrorlist
760 if repo.name in repo_urls:
761 baseurl = repo_urls[repo.name]
764 if repos.has_key(repo.name):
765 msger.warning("Overriding already specified repo %s" %(repo.name,))
768 if hasattr(repo, "proxy"):
770 proxy_username = None
771 if hasattr(repo, "proxy_username"):
772 proxy_username = repo.proxy_username
773 proxy_password = None
774 if hasattr(repo, "proxy_password"):
775 proxy_password = repo.proxy_password
776 if hasattr(repo, "debuginfo"):
777 debuginfo = repo.debuginfo
778 if hasattr(repo, "source"):
780 if hasattr(repo, "gpgkey"):
782 if hasattr(repo, "disable"):
783 disable = repo.disable
785 if hasattr(repo, "ssl_verify"):
786 ssl_verify = repo.ssl_verify == "yes"
788 if hasattr(repo, "cost"):
791 if hasattr(repo, "priority"):
792 priority = repo.priority
794 repos[repo.name] = (repo.name, baseurl, mirrorlist, inc, exc,
795 proxy, proxy_username, proxy_password, debuginfo,
796 source, gpgkey, disable, ssl_verify, cost, priority)
798 return repos.values()
800 def convert_method_to_repo(ks):
802 ks.handler.repo.methodToRepo()
803 except (AttributeError, kserrors.KickstartError):
806 def get_attachment(ks, required = []):
807 return ks.handler.attachment.packageList + required
809 def get_pre_packages(ks, required = []):
810 return ks.handler.prepackages.packageList + required
812 def get_packages(ks, required = []):
813 return ks.handler.packages.packageList + required
815 def get_groups(ks, required = []):
816 return ks.handler.packages.groupList + required
818 def get_excluded(ks, required = []):
819 return ks.handler.packages.excludedList + required
821 def get_partitions(ks, required = []):
822 return ks.handler.partition.partitions
824 def ignore_missing(ks):
825 return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
827 def exclude_docs(ks):
828 return ks.handler.packages.excludeDocs
831 if hasattr(ks.handler.packages, "instLange"):
832 return ks.handler.packages.instLange
833 elif hasattr(ks.handler.packages, "instLangs"):
834 return ks.handler.packages.instLangs
837 def get_post_scripts(ks):
839 for s in ks.handler.scripts:
840 if s.type != ksparser.KS_SCRIPT_POST:
845 def add_repo(ks, repostr):
846 args = repostr.split()
847 repoobj = ks.handler.repo.parse(args[1:])
848 if repoobj and repoobj not in ks.handler.repo.repoList:
849 ks.handler.repo.repoList.append(repoobj)
851 def remove_all_repos(ks):
852 while len(ks.handler.repo.repoList) != 0:
853 del ks.handler.repo.repoList[0]
855 def remove_duplicate_repos(ks):
859 if len(ks.handler.repo.repoList) < 2:
861 if i >= len(ks.handler.repo.repoList) - 1:
863 name = ks.handler.repo.repoList[i].name
864 baseurl = ks.handler.repo.repoList[i].baseurl
865 if j < len(ks.handler.repo.repoList):
866 if (ks.handler.repo.repoList[j].name == name or \
867 ks.handler.repo.repoList[j].baseurl == baseurl):
868 del ks.handler.repo.repoList[j]
871 if j >= len(ks.handler.repo.repoList):
878 def resolve_groups(creatoropts, repometadata):
880 if 'zypp' == creatoropts['pkgmgr']:
882 ks = creatoropts['ks']
884 for repo in repometadata:
885 """ Mustn't replace group with package list if repo is ready for the
886 corresponding package manager.
889 if iszypp and repo["patterns"]:
891 if not iszypp and repo["comps"]:
894 # But we also must handle such cases, use zypp but repo only has comps,
895 # use yum but repo only has patterns, use zypp but use_comps is true,
896 # use yum but use_comps is false.
898 if iszypp and repo["comps"]:
899 groupfile = repo["comps"]
900 get_pkglist_handler = misc.get_pkglist_in_comps
901 if not iszypp and repo["patterns"]:
902 groupfile = repo["patterns"]
903 get_pkglist_handler = misc.get_pkglist_in_patterns
908 if i >= len(ks.handler.packages.groupList):
910 pkglist = get_pkglist_handler(
911 ks.handler.packages.groupList[i].name,
914 del ks.handler.packages.groupList[i]
916 if pkg not in ks.handler.packages.packageList:
917 ks.handler.packages.packageList.append(pkg)