Ignore the pylint warning of raising-bad-type and unbalanced-tuple-unpacking in conne...
[tools/mic.git] / mic / 3rdparty / pykickstart / sections.py
1 #
2 # sections.py:  Kickstart file sections.
3 #
4 # Chris Lumens <clumens@redhat.com>
5 #
6 # Copyright 2011-2016 Red Hat, Inc.
7 #
8 # This copyrighted material is made available to anyone wishing to use, modify,
9 # copy, or redistribute it subject to the terms and conditions of the GNU
10 # General Public License v.2.  This program is distributed in the hope that it
11 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
12 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 # See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc., 51
17 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  Any Red Hat
18 # trademarks that are incorporated in the source code or documentation are not
19 # subject to the GNU General Public License and may only be used or replicated
20 # with the express permission of Red Hat, Inc.
21 #
22 """
23 This module exports the classes that define a section of a kickstart file.  A
24 section is a chunk of the file starting with a %tag and ending with a %end.
25 Examples of sections include %packages, %pre, and %post.
26
27 You may use this module to define your own custom sections which will be
28 treated just the same as a predefined one by the kickstart parser.  All that
29 is necessary is to create a new subclass of Section and call
30 parser.registerSection with an instance of your new class.
31 """
32 import warnings
33 from pykickstart.constants import KS_SCRIPT_PRE, KS_SCRIPT_POST, KS_SCRIPT_TRACEBACK, \
34                                   KS_SCRIPT_PREINSTALL, KS_SCRIPT_ONERROR, \
35                                   KS_MISSING_IGNORE, KS_MISSING_PROMPT, \
36                                   KS_BROKEN_IGNORE, KS_BROKEN_REPORT, KS_SCRIPT_RUN, KS_SCRIPT_UMOUNT
37 from pykickstart.errors import KickstartError, KickstartParseError, KickstartDeprecationWarning
38 from pykickstart.options import KSOptionParser
39 from pykickstart.version import FC4, F7, F9, F18, F21, F22, F24, F32, F34, RHEL6, RHEL7, RHEL9, \
40     isRHEL
41 from pykickstart.i18n import _
42
43 class Section(object):
44     """The base class for defining kickstart sections.  You are free to
45        subclass this as appropriate.
46
47        Class attributes:
48
49        allLines    -- Does this section require the parser to call handleLine
50                       for every line in the section, even blanks and comments?
51        sectionOpen -- The string that denotes the start of this section.  You
52                       must start your tag with a percent sign.
53        timesSeen   -- This attribute is for informational purposes only.  It is
54                       incremented every time handleHeader is called to keep
55                       track of the number of times a section of this type is
56                       seen.
57     """
58     allLines = False
59     sectionOpen = ""
60     timesSeen = 0
61
62     def __init__(self, handler, **kwargs):
63         """Create a new Script instance.  At the least, you must pass in an
64            instance of a baseHandler subclass.
65
66            Valid kwargs:
67
68            dataObj -- A class that should be populated by this Section.  It almost
69                       always should be Script, or some subclass of it.
70         """
71         self.handler = handler
72         self.version = self.handler.version
73
74         self.dataObj = kwargs.get("dataObj", None)
75
76     def finalize(self):
77         """This method is called when the %end tag for a section is seen.  It
78            is not required to be provided.
79         """
80
81     def handleLine(self, line):
82         """This method is called for every line of a section.  Take whatever
83            action is appropriate.  While this method is not required to be
84            provided, not providing it does not make a whole lot of sense.
85
86            Arguments:
87
88            line -- The complete line, with any trailing newline.
89         """
90
91     # pylint: disable=unused-argument
92     def handleHeader(self, lineno, args):
93         """This method is called when the opening tag for a section is seen.
94            Not all sections will need this method, though all provided with
95            kickstart include one.
96
97            Arguments:
98
99            args -- A list of all strings passed as arguments to the section
100                    opening tag.
101         """
102         self.timesSeen += 1
103     # pylint: enable=unused-argument
104
105     @property
106     def seen(self):
107         """This property is given for consistency with KickstartCommand objects
108            only.  It simply returns whether timesSeen is non-zero.
109         """
110         return self.timesSeen > 0
111
112 class NullSection(Section):
113     """This defines a section that pykickstart will recognize but do nothing
114        with.  If the parser runs across a %section that has no object registered,
115        it will raise an error.  Sometimes, you may want to simply ignore those
116        sections instead.  This class is useful for that purpose.
117     """
118     allLines = True
119
120     def __init__(self, *args, **kwargs):
121         """Create a new NullSection instance.  You must pass a sectionOpen
122            parameter (including a leading '%') for the section you wish to
123            ignore.
124         """
125         Section.__init__(self, *args, **kwargs)
126         self.sectionOpen = kwargs.get("sectionOpen")
127         self._args = []
128         self._body = []
129
130     def handleHeader(self, lineno, args):
131         self._args = args
132
133     def handleLine(self, line):
134         self._body.append(line)
135
136     def finalize(self):
137         body = "\n".join(self._body)
138         if body:
139             s = "%s\n%s\n%%end" % (" ".join(self._args), body)
140         else:
141             s = "%s\n%%end" % " ".join(self._args)
142
143         self.handler._null_section_strings.append(s)
144
145         self._args = []
146         self._body = []
147
148 class ScriptSection(Section):
149     allLines = True
150     _description = ""
151     _epilog = ""
152     _title = ""
153
154     def __init__(self, *args, **kwargs):
155         Section.__init__(self, *args, **kwargs)
156         self._script = {}
157         self._resetScript()
158
159     def _getParser(self):
160         op = KSOptionParser(prog=self.sectionOpen,
161                             description=self._description,
162                             epilog=self._epilog,
163                             version=FC4)
164
165         op.add_argument("--erroronfail", dest="errorOnFail", action="store_true",
166                         default=False, help="""
167                         If the error script fails, this option will cause an
168                         error dialog to be displayed and will halt installation.
169                         The error message will direct you to where the cause of
170                         the failure is logged.""", version=FC4)
171         op.add_argument("--interpreter", dest="interpreter", default="/bin/sh",
172                         version=FC4, metavar="/usr/bin/python", help="""
173                         Allows you to specify a different scripting language,
174                         such as Python. Replace /usr/bin/python with the
175                         scripting language of your choice.
176                         """)
177         op.add_argument("--log", "--logfile", dest="log", version=FC4,
178                         help="""
179                         Log all messages from the script to the given log file.
180                         """)
181         return op
182
183     def _resetScript(self):
184         self._script = {"interp": "/bin/sh", "log": None, "errorOnFail": False,
185                         "lineno": None, "chroot": False, "body": []}
186
187     def handleLine(self, line):
188         self._script["body"].append(line)
189
190     def finalize(self):
191         if " ".join(self._script["body"]).strip() == "":
192             return
193
194         kwargs = {"interp": self._script["interp"],
195                   "inChroot": self._script["chroot"],
196                   "lineno": self._script["lineno"],
197                   "logfile": self._script["log"],
198                   "errorOnFail": self._script["errorOnFail"],
199                   "type": self._script["type"]}
200
201         if self.dataObj is not None:
202             s = self.dataObj(self._script["body"], **kwargs)
203             self._resetScript()
204             self.handler.scripts.append(s)
205
206     def handleHeader(self, lineno, args):
207         """Process the arguments to a %pre/%post/%traceback header for later
208            setting on a Script instance once the end of the script is found.
209            This method may be overridden in a subclass if necessary.
210         """
211         Section.handleHeader(self, lineno, args)
212         op = self._getParser()
213
214         ns = op.parse_args(args=args[1:], lineno=lineno)
215
216         self._script["interp"] = ns.interpreter
217         self._script["lineno"] = lineno
218         self._script["log"] = ns.log
219         self._script["errorOnFail"] = ns.errorOnFail
220         if hasattr(ns, "nochroot"):
221             self._script["chroot"] = not ns.nochroot
222
223 class PreScriptSection(ScriptSection):
224     sectionOpen = "%pre"
225     _title = "Pre-installation script"
226     _description = """
227         You can add commands to run on the system immediately after the ks.cfg
228         has been parsed and the lang, keyboard, and url options have been
229         processed. This section must be at the end of the kickstart file (after
230         the commands) and must start with the %pre command. You can access the
231         network in the %pre section; however, name service has not been
232         configured at this point, so only IP addresses will work.
233
234         Preinstallation scripts are required to be closed with %end.
235
236         If your script spawns a daemon process, you must make sure to close
237         ``stdout`` and ``stderr``. Doing so is standard procedure for creating
238         daemons. If you do not close these file descriptors, the installation
239         will appear hung as anaconda waits for an EOF from the script.
240
241         .. note::
242
243             The pre-installation script is not run in the chroot environment.
244     """
245     _epilog = """
246     Example
247     -------
248
249     Here is an example %pre section::
250
251         %pre
252         #!/bin/bash
253         hds=""
254         mymedia=""
255
256         for file in /sys/block/sd*; do
257         hds="$hds $(basename $file)"
258         done
259
260         set $hds
261         numhd=$(echo $#)
262
263         drive1=$(echo $hds | cut -d' ' -f1)
264         drive2=$(echo $hds | cut -d' ' -f2)
265
266
267         if [ $numhd == "2" ]  ; then
268             echo "#partitioning scheme generated in %pre for 2 drives" > /tmp/part-include
269             echo "clearpart --all" >> /tmp/part-include
270             echo "part /boot --fstype ext4 --size 512 --ondisk sda" >> /tmp/part-include
271             echo "part / --fstype ext4 --size 10000 --grow --ondisk sda" >> /tmp/part-include
272             echo "part swap --recommended --ondisk $drive1" >> /tmp/part-include
273             echo "part /home --fstype ext4 --size 10000 --grow --ondisk sdb" >> /tmp/part-include
274         else
275             echo "#partitioning scheme generated in %pre for 1 drive" > /tmp/part-include
276             echo "clearpart --all" >> /tmp/part-include
277             echo "part /boot --fstype ext4 --size 521" >> /tmp/part-include
278             echo "part swap --recommended" >> /tmp/part-include
279             echo "part / --fstype ext4 --size 2048" >> /tmp/part-include
280             echo "part /home --fstype ext4 --size 2048 --grow" >> /tmp/part-include
281         fi
282         %end
283
284     This script determines the number of hard drives in the system and
285     writes a text file with a different partitioning scheme depending on
286     whether it has one or two drives. Instead of having a set of
287     partitioning commands in the kickstart file, include the line:
288
289     ``%include /tmp/part-include``
290
291     The partitioning commands selected in the script will be used.
292     """
293
294     def _resetScript(self):
295         ScriptSection._resetScript(self)
296         self._script["type"] = KS_SCRIPT_PRE
297
298 class PreInstallScriptSection(ScriptSection):
299     sectionOpen = "%pre-install"
300     _title = "Pre-install Script"
301     _description="""
302     You can use the %pre-install section to run commands after the system has been
303     partitioned, filesystems created, and everything is mounted under /mnt/sysimage
304     Like %pre these scripts do not run in the chrooted environment.
305
306     Each %pre-install section is required to be closed with a corresponding %end.
307     """
308
309     def _resetScript(self):
310         ScriptSection._resetScript(self)
311         self._script["type"] = KS_SCRIPT_PREINSTALL
312
313 class PostScriptSection(ScriptSection):
314     sectionOpen = "%post"
315     _title = "Post-installation Script"
316     _description="""
317     You have the option of adding commands to run on the system once the
318     installation is complete. This section must be at the end of the
319     kickstart file and must start with the %post command. This section is
320     useful for functions such as installing additional software and
321     configuring an additional nameserver.
322
323     You may have more than one %post section, which can be useful for cases
324     where some post-installation scripts need to be run in the chroot and
325     others that need access outside the chroot.
326
327     Each %post section is required to be closed with a corresponding %end.
328
329     If you configured the network with static IP information, including a
330     nameserver, you can access the network and resolve IP addresses in the %post
331     section.  If you configured the network for DHCP, the /etc/resolv.conf file
332     has not been completed when the installation executes the %post section. You
333     can access the network, but you can not resolve IP addresses. Thus, if you
334     are using DHCP, you must specify IP addresses in the %post section.
335
336     If your script spawns a daemon process, you must make sure to close stdout
337     and stderr.  Doing so is standard procedure for creating daemons.  If you do
338     not close these file descriptors, the installation will appear hung as
339     anaconda waits for an EOF from the script.
340
341     The post-install script is run in a chroot environment; therefore, performing
342     tasks such as copying scripts or RPMs from the installation media will not
343     work.
344     """
345
346     _epilog="""
347     Examples
348     --------
349
350     Run a script named ``runme`` from an NFS share::
351
352         %post
353         mkdir /mnt/temp
354         mount 10.10.0.2:/usr/new-machines /mnt/temp
355         open -s -w -- /mnt/temp/runme
356         umount /mnt/temp
357         %end
358
359     Copy the file /etc/resolv.conf to the file system that was just
360     installed::
361
362         %post --nochroot
363         cp /etc/resolv.conf /mnt/sysimage/etc/resolv.conf
364         %end
365
366     **If your kickstart is being interpreted by the livecd-creator tool, you should
367     replace /mnt/sysimage above with $INSTALL_ROOT.**
368     """
369
370     def _getParser(self):
371         op = ScriptSection._getParser(self)
372         op.add_argument("--nochroot", dest="nochroot", action="store_true",
373                         default=False, version=FC4, help="""
374                         Allows you to specify commands that you would like to
375                         run outside of the chroot environment.""")
376         return op
377
378     def _resetScript(self):
379         ScriptSection._resetScript(self)
380         self._script["chroot"] = True
381         self._script["type"] = KS_SCRIPT_POST
382
383 class OnErrorScriptSection(ScriptSection):
384     sectionOpen = "%onerror"
385     _title = "Handling Errors"
386     _description="""
387     These scripts run when the installer hits a fatal error, but not necessarily
388     a bug in the installer.  Some examples of these situations include errors in
389     packages that have been requested to be installed, failures when starting VNC
390     when requested, and error when scanning storage.  When these situations happen,
391     installation cannot continue.  The installer will run all %onerror scripts in
392     the order they are provided in the kickstart file.
393
394     In addition, %onerror scripts will be run on a traceback as well.  To be exact,
395     all %onerror scripts will be run and then all %traceback scripts will be run
396     afterwards.
397
398     Each %onerror script is required to be closed with a corresponding %end.
399
400     .. note::
401
402         These scripts could potentially run at
403         any stage in installation - early on, between making filesystems and installing
404         packages, before the bootloader is installed, when attempting to reboot, and
405         so on.  For this reason, these scripts cannot be run in the chroot environment
406         and you should not trust anything in the installed system.  These scripts are
407         primarily for testing and error reporting purposes.
408     """
409
410     def _resetScript(self):
411         ScriptSection._resetScript(self)
412         self._script["type"] = KS_SCRIPT_ONERROR
413
414 class TracebackScriptSection(OnErrorScriptSection):
415     sectionOpen = "%traceback"
416     _title = "Handling Tracebacks"
417     _description="""
418     These scripts run when the installer hits an internal error (a traceback, as
419     they are called in Python) and cannot continue.  When this situation happens,
420     the installer will display an error dialog to the screen that prompts the user
421     to file a bug or reboot.  At the same time, it will run all %traceback scripts
422     in the order they are provided in the kickstart file.
423
424     Each %traceback script is required to be closed with a corresponding %end.
425
426     .. note::
427
428         These scripts could potentially run at
429         any stage in installation - early on, between making filesystems and installing
430         packages, before the bootloader is installed, when attempting to reboot, and
431         so on.  For this reason, these scripts cannot be run in the chroot environment
432         and you should not trust anything in the installed system.  These scripts are
433         primarily for testing and error reporting purposes.
434     """
435
436     def _resetScript(self):
437         OnErrorScriptSection._resetScript(self)
438         self._script["type"] = KS_SCRIPT_TRACEBACK
439
440     def handleHeader(self, lineno, args):
441         super().handleHeader(lineno, args)
442
443         if self.version < F34:
444             return
445
446         warnings.warn("The %traceback section has been deprecated. It may be removed in the "
447                       "future, which will result in a fatal error from kickstart. Please modify "
448                       "your kickstart file to use the %onerror section instead.",
449                       KickstartDeprecationWarning)
450
451 class RunScriptSection(ScriptSection):
452     sectionOpen = "%runscript"
453     def _resetScript(self):
454         ScriptSection._resetScript(self)
455         self._script["type"] = KS_SCRIPT_RUN
456
457     def finalize(self):
458         ScriptSection.finalize(self)
459         if self.handler:
460             for s in self.handler.scripts:
461                 if s.type == KS_SCRIPT_UMOUNT:
462                     raise KickstartError("%runscript and %post-umount " \
463                                          "can not be defined together")
464
465 class PostUmountScriptSection(ScriptSection):
466     sectionOpen = "%post-umount"
467
468     def _resetScript(self):
469         ScriptSection._resetScript(self)
470         self._script["type"] = KS_SCRIPT_UMOUNT
471
472     def finalize(self):
473         ScriptSection.finalize(self)
474         if self.handler:
475             for s in self.handler.scripts:
476                 if s.type == KS_SCRIPT_RUN:
477                     raise KickstartError("%runscript and %post-umount " \
478                                          "can not be defined together")
479
480 class PackageSection(Section):
481     sectionOpen = "%packages"
482     _title = "Package Selection"
483
484     def handleLine(self, line):
485         h = line.partition('#')[0]
486         line = h.rstrip()
487         self.handler.packages.add([line])
488
489     def _getParser(self):
490         op = KSOptionParser(prog=self.sectionOpen, description="""
491                             Use the %packages command to begin a kickstart file
492                             section that lists the packages you would like to
493                             install.
494
495                             Packages can be specified by group or by individual
496                             package name. The installation program defines
497                             several groups that contain related packages. Refer
498                             to the repodata/\\*comps\\*.xml file on the
499                             installation media or in installation repository
500                             for a list of groups. Each group has an id, user
501                             visibility value, name, description, and package
502                             list. In the package list, the packages marked as
503                             mandatory are always installed if the group is
504                             selected, the packages marked default are selected
505                             by default if the group is selected, and the packages
506                             marked optional must be specifically selected even
507                             if the group is selected to be installed.
508
509                             In most cases, it is only necessary to list the
510                             desired groups and not individual packages. Note
511                             that the Core group is always selected by default,
512                             so it is not necessary to specify it in the
513                             %packages section.
514
515                             The %packages section is required to be closed with
516                             %end. Also, multiple %packages sections may be given.
517                             This may be handy if the kickstart file is used as a
518                             template and pulls in various other files with the
519                             %include mechanism.
520
521                             Here is an example %packages selection::
522
523                                 %packages
524                                 @X Window System
525                                 @GNOME Desktop Environment
526                                 @Graphical Internet
527                                 @Sound and Video
528                                 dhcp
529                                 %end
530
531                             As you can see, groups are specified, one to a line,
532                             starting with an ``@`` symbol followed by the full
533                             group name as given in the comps.xml file. Groups
534                             can also be specified using the id for the group,
535                             such as gnome-desktop. Specify individual packages
536                             with no additional characters (the dhcp line in the
537                             example above is an individual package).
538
539                             The ``@`` prefix is also used to request installation
540                             of module streams in the following format::
541
542                                 @<module name>:<stream name>/<profile name>
543
544                             Profile name is optional and multiple profiles can be
545                             installed by using multiple lines, one per profile.
546                             Stream name is only optional only if the given module
547                             has a default stream.
548
549                             If there are a module and a group named the same,
550                             and no stream name and profile are specified,
551                             module will be selected instead of a group.
552
553                             Requesting one module more than once with different
554                             streams or not specifying a stream name for a module
555                             without a default stream will result in an error.
556
557                             Here is an example %packages selection with modules::
558
559                                 %packages
560                                 @^Fedora Server Edition
561                                 @nodejs:10
562                                 @django:1.6
563                                 @postgresql:9.6/server
564                                 @mariadb:10.1/server
565                                 @mysql:5.7/default
566                                 @scala:2.10/default
567                                 @gimp:2.10/devel
568                                 vim
569                                 %end
570
571                             You can also specify environments using the ``@^``
572                             prefix followed by full environment name as given in
573                             the comps.xml file.  If multiple environments are
574                             specified, only the last one specified will be used.
575                             Environments can be mixed with both group
576                             specifications (even if the given group is not part
577                             of the specified environment) and package
578                             specifications.
579
580                             Here is an example of requesting the GNOME Desktop
581                             environment to be selected for installation::
582
583                                 %packages
584                                 @^gnome-desktop-environment
585                                 %end
586
587                             Additionally, individual packages may be specified
588                             using globs. For instance::
589
590                                 %packages
591                                 vim*
592                                 kde-i18n-*
593                                 %end
594
595                             This would install all packages whose names start
596                             with "vim" or "kde-i18n-".
597
598                             You can also specify which packages or groups not to
599                             install from the default package list::
600
601                                 %packages
602                                 -autofs
603                                 -@Sound and Video
604                                 %end
605                             """, epilog="""
606                             Group-level options
607                             -------------------
608
609                             In addition, group lines in the %packages section
610                             can take the following options:
611
612                             ``--nodefaults``
613
614                                 Only install the group's mandatory packages, not
615                                 the default selections.
616
617                             ``--optional``
618
619                                 In addition to the mandatory and default packages,
620                                 also install the optional packages. This means all
621                                 packages in the group will be installed.
622                             """, version=FC4)
623
624         op.add_argument("--excludedocs", action="store_true", default=False,
625                         help="""
626                         Do not install any of the documentation from any packages.
627                         For the most part, this means files in /usr/share/doc*
628                         will not get installed though it could mean other files
629                         as well, depending on how the package was built.""",
630                         version=FC4)
631         op.add_argument("--ignoremissing", action="store_true", default=False,
632                         help="""
633                         Ignore any packages, groups or module streams specified in the
634                         packages section that are not found in any configured repository.
635                         The default behavior is to halt the installation and ask
636                         the user if the installation should be aborted or
637                         continued. This option allows fully automated
638                         installation even in the error case.""",
639                         version=FC4)
640         op.add_argument("--ignoredeps", dest="resolveDeps", action="store_false",
641                         deprecated=FC4, help="")
642         op.add_argument("--resolvedeps", dest="resolveDeps", action="store_true",
643                         deprecated=FC4, help="")
644
645         if self.version < F7:
646             return op
647
648         op.add_argument("--default", dest="defaultPackages", action="store_true",
649                         default=False, version=F7, help="""
650                         Install the default environment. This corresponds to the
651                         package set that would be installed if no other
652                         selections were made on the package customization screen
653                         during an interactive install.""")
654
655         if self.version < F9:
656             return op
657
658         op.remove_argument("--ignoredeps", version=F9)
659         op.remove_argument("--resolvedeps", version=F9)
660         op.add_argument("--instLangs", default=None, version=F9, help="""
661                         Specify the list of languages that should be installed.
662                         This is different from the package group level
663                         selections, though. This option does not specify what
664                         package groups should be installed. Instead, it controls
665                         which translation files from individual packages should
666                         be installed by setting RPM macros.""")
667
668         if self.version < RHEL6:
669             return op
670
671         op.add_argument("--nobase", action="store_true", default=False,
672                         version=RHEL6, help="""
673                         Do not install the @base group (installed by default,
674                         otherwise).""")
675
676         if self.version < F18:
677             return op
678
679         op.add_argument("--nobase", action="store_true", default=False,
680                         deprecated=F18)
681         op.add_argument("--multilib", dest="multiLib", action="store_true",
682                         default=False, version=F18, help="""
683                         Enable yum's "all" multilib_policy as opposed to the
684                         default of "best".""")
685
686         if self.version < F21:
687             return op
688
689         op.add_argument("--nocore", action="store_true", default=False,
690                         version=F21, help="""
691                         Do not install the @core group (installed by default,
692                         otherwise).
693
694                         **Omitting the core group can produce a system that is
695                         not bootable or that cannot finish the install. Use
696                         with caution.**""")
697
698         if self.version < RHEL7:
699             return op
700
701         op.add_argument("--timeout", dest="timeout", type=int,
702                         default=None, version=RHEL7, help="""
703                         Set up yum's or dnf's timeout. It is a number of seconds
704                         to wait for a connection before timing out.""")
705         op.add_argument("--retries", dest="retries", type=int,
706                         default=None, version=RHEL7, help="""
707                         Set up yum's or dnf's retries. It is a number of times
708                         any attempt to retrieve a file should retry before
709                         returning an error.""")
710
711         if self.version < F22:
712             return op
713
714         op.remove_argument("--nobase", version=F22)
715
716         if self.version < F24:
717             return op
718
719         op.add_argument("--excludeWeakdeps", dest="excludeWeakdeps",
720                         action="store_true", default=False, version=F24,
721                         help="""
722                         Do not install packages from weak dependencies. These
723                         are packages linked to the selected package set by
724                         Recommends and Supplements flags. By default weak
725                         dependencies will be installed.""")
726
727         if self.version < F32:
728             return op
729
730         op.add_argument("--instLangs", "--inst-langs", dest="instLangs", default=None,
731                         version=F32, help="Added ``--inst-langs`` alias")
732
733         op.add_argument("--excludeWeakdeps", "--exclude-weakdeps", dest="excludeWeakdeps",
734                         action="store_true", default=False, version=F32,
735                         help="Added ``--exclude-weakdeps`` alias")
736
737         op.add_argument("--ignorebroken", action="store_true", default=False, version=F32,
738                         help="""
739                         Ignore any packages, groups or modules with conflicting files.
740                         This issue will disable the DNF `strict` option. The default behavior
741                         is to abort the installation with error message describing the
742                         conflicting files.
743
744                         **WARNING: Usage of this parameter is DISCOURAGED! The DNF
745                         strict option will NOT log any information about what packages
746                         were skipped. Using this option may result in an unusable system.**
747                         """)
748
749         if isRHEL(self.version):
750             # The --ignorebroken feature is not supported on RHEL.
751             op.remove_argument("--ignorebroken", version=RHEL9)
752
753         return op
754
755     def handleHeader(self, lineno, args):
756         """Process the arguments to the %packages header and set attributes
757            on the Version's Packages instance appropriate.  This method may be
758            overridden in a subclass if necessary.
759         """
760         Section.handleHeader(self, lineno, args)
761         op = self._getParser()
762         ns = op.parse_args(args=args[1:], lineno=lineno)
763
764         self.handler.packages.seen = True
765         self.handler.packages.excludeDocs = ns.excludedocs
766         if ns.ignoremissing:
767             self.handler.packages.handleMissing = KS_MISSING_IGNORE
768         else:
769             self.handler.packages.handleMissing = KS_MISSING_PROMPT
770
771         if self.version < F7:
772             return
773
774         if ns.defaultPackages:
775             self.handler.packages.default = True
776
777         if self.version < F9:
778             return
779
780         if ns.instLangs is not None:
781             self.handler.packages.instLangs = ns.instLangs
782
783         if self.version < RHEL6:
784             return
785
786         if ns.defaultPackages and getattr(ns, "nobase", False):
787             raise KickstartParseError(_("--default and --nobase cannot be used together"), lineno=lineno)
788
789         self.handler.packages.addBase = not getattr(ns, "nobase", False)
790
791         if self.version < F18:
792             return
793
794         self.handler.packages.multiLib = ns.multiLib
795
796         if self.version < F21:
797             return
798
799         if ns.defaultPackages and ns.nocore:
800             raise KickstartParseError(_("--default and --nocore cannot be used together"), lineno=lineno)
801
802         self.handler.packages.nocore = ns.nocore
803
804         if self.version < RHEL7:
805             return
806
807         self.handler.packages.timeout = ns.timeout
808         self.handler.packages.retries = ns.retries
809
810         if self.version < F24:
811             return
812
813         self.handler.packages.excludeWeakdeps = ns.excludeWeakdeps
814
815         if self.version < F32:
816             return
817
818         if getattr(ns, "ignorebroken", False):
819             self.handler.packages.handleBroken = KS_BROKEN_IGNORE
820         else:
821             self.handler.packages.handleBroken = KS_BROKEN_REPORT
822
823         for arg in args:
824             for option, new_option in \
825                 {"--instLangs": "--inst-langs", "--excludeWeakdeps": "--exclude-weakdeps"}.items():
826                 if option in arg:
827                     warnings.warn(_("The %(option)s option on line %(lineno)s will be deprecated in "
828                                     "future releases. Please modify your kickstart file to replace "
829                                     "this option with its preferred alias %(new_option)s.")
830                                   % {"option": option, "lineno": lineno, "new_option": new_option},
831                                   KickstartDeprecationWarning)
832
833 class TpkPackageSection(Section):
834     sectionOpen = "%tpk_packages"
835
836     def handleLine(self, line):
837         if not self.handler:
838             return
839
840         (h, s, t) = line.partition('#')
841         line = h.rstrip()
842         self.handler.tpk_packages.add([line])
843
844     def handleHeader(self, lineno, args):
845         """Process the arguments to the %tpk_packages header and set attributes
846            on the Version's TpkPackages instance appropriate.  This method may be
847            overridden in a subclass if necessary.
848         """
849         Section.handleHeader(self, lineno, args)
850