[PATCH] Preserve the order of boot args added by kickstart.

Chris Lumens clumens at redhat.com
Wed Apr 8 14:20:10 UTC 2015


This adds OrderedSet to anaconda, just like it is in pykickstart.  I have added
additional functionality that we need to the Arguments class in bootloader.py
so if OrderedSet is needed elsewhere, it won't inherit the special behavior.

This also attempts to keep "rhgb quiet" at the end of the line by moving where
passed-in command line arguments are processed to the very end.  Note that the
storage args get popped off much earlier.

Resolves: rhbz#1188948
---
 anaconda.spec.in         |  2 +-
 pyanaconda/bootloader.py | 47 ++++++++++++++++++------------------
 pyanaconda/orderedset.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 24 deletions(-)
 create mode 100644 pyanaconda/orderedset.py

diff --git a/anaconda.spec.in b/anaconda.spec.in
index 92a54d2..b97f7d6 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -4,7 +4,7 @@ Summary: Graphical system installer
 Name:    anaconda
 Version: @PACKAGE_VERSION@
 Release: @PACKAGE_RELEASE@%{?dist}
-License: GPLv2+
+License: GPLv2+ and MIT
 Group:   Applications/System
 URL:     http://fedoraproject.org/wiki/Anaconda
 
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index cdd596f..568a61d 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -43,6 +43,7 @@ from pyanaconda.nm import nm_device_hwaddress
 from blivet import platform
 from blivet.size import Size
 from pyanaconda.i18n import _, N_
+from pyanaconda.orderedset import OrderedSet
 
 import logging
 log = logging.getLogger("anaconda")
@@ -124,12 +125,7 @@ def _is_on_iscsi(device):
 class BootLoaderError(Exception):
     pass
 
-class Arguments(set):
-    ordering_dict = {
-        "rhgb" : 99,
-        "quiet" : 100
-        }
-
+class Arguments(OrderedSet):
     def _merge_ip(self):
         """
         Find ip= arguments targetting the same interface and merge them.
@@ -140,7 +136,7 @@ class Arguments(set):
             # automatic network setup:
             return arg.startswith("ip=") and arg.count(":") == 1
         ip_params = filter(partition_p, self)
-        rest = set(filter(lambda p: not partition_p(p), self))
+        rest = OrderedSet(filter(lambda p: not partition_p(p), self))
 
         # split at the colon:
         ip_params = map(lambda p: p.split(":"), ip_params)
@@ -162,13 +158,18 @@ class Arguments(set):
 
     def __str__(self):
         self._merge_ip()
-        # sort the elements according to their values in ordering_dict. The
-        # higher the number the closer to the final string the argument
-        # gets. The default is 50.
-        lst = sorted(self, key=lambda s: self.ordering_dict.get(s, 50))
-
+        lst = list(self)
         return " ".join(lst)
 
+    def add(self, key):
+        self.discard(key)
+        OrderedSet.add(self, key)
+
+    def update(self, other):
+        for key in other:
+            self.discard(key)
+            self.add(key)
+
 class BootLoaderImage(object):
     """ Base class for bootloader images. Suitable for non-linux OS images. """
     def __init__(self, device=None, label=None, short=None):
@@ -845,17 +846,6 @@ class BootLoader(object):
                     self.boot_args.update(setup_args)
                     self.dracut_args.update(setup_args)
 
-        # passed-in objects
-        for cfg_obj in list(args) + kwargs.values():
-            if hasattr(cfg_obj, "dracutSetupArgs"):
-                setup_args = cfg_obj.dracutSetupArgs()
-                self.boot_args.update(setup_args)
-                self.dracut_args.update(setup_args)
-            else:
-                setup_string = cfg_obj.dracutSetupString()
-                self.boot_args.add(setup_string)
-                self.dracut_args.add(setup_string)
-
         # This is needed for FCoE, bug #743784. The case:
         # We discover LUN on an iface which is part of multipath setup.
         # If the iface is disconnected after discovery anaconda doesn't
@@ -890,6 +880,17 @@ class BootLoader(object):
 
             self.boot_args.add(new_arg)
 
+        # passed-in objects
+        for cfg_obj in list(args) + kwargs.values():
+            if hasattr(cfg_obj, "dracutSetupArgs"):
+                setup_args = cfg_obj.dracutSetupArgs()
+                self.boot_args.update(setup_args)
+                self.dracut_args.update(setup_args)
+            else:
+                setup_string = cfg_obj.dracutSetupString()
+                self.boot_args.add(setup_string)
+                self.dracut_args.add(setup_string)
+
     #
     # configuration
     #
diff --git a/pyanaconda/orderedset.py b/pyanaconda/orderedset.py
new file mode 100644
index 0000000..125d57c
--- /dev/null
+++ b/pyanaconda/orderedset.py
@@ -0,0 +1,63 @@
+# Copyright 2009 Raymond Hettinger
+# Distributed under the MIT license
+# Obtained at http://code.activestate.com/recipes/576694/
+
+import collections
+
+class OrderedSet(collections.MutableSet):
+
+    def __init__(self, iterable=None):
+        self.end = end = []
+        end += [None, end, end]         # sentinel node for doubly linked list
+        self.map = {}                   # key --> [key, prev, next]
+        if iterable is not None:
+            self |= iterable
+
+    def __len__(self):
+        return len(self.map)
+
+    def __contains__(self, key):
+        return key in self.map
+
+    def add(self, key):
+        if key not in self.map:
+            end = self.end
+            curr = end[1]
+            curr[2] = end[1] = self.map[key] = [key, curr, end]
+
+    def discard(self, key):
+        if key in self.map:
+            key, prev, next = self.map.pop(key) # pylint: disable=redefined-builtin
+            prev[2] = next
+            next[1] = prev
+
+    def __iter__(self):
+        end = self.end
+        curr = end[2]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[2]
+
+    def __reversed__(self):
+        end = self.end
+        curr = end[1]
+        while curr is not end:
+            yield curr[0]
+            curr = curr[1]
+
+    def pop(self, last=True): # pylint: disable=arguments-differ
+        if not self:
+            raise KeyError('set is empty')
+        key = self.end[1][0] if last else self.end[2][0]
+        self.discard(key)
+        return key
+
+    def __repr__(self):
+        if not self:
+            return '%s()' % (self.__class__.__name__,)
+        return '%s(%r)' % (self.__class__.__name__, list(self))
+
+    def __eq__(self, other):
+        if isinstance(other, OrderedSet):
+            return len(self) == len(other) and list(self) == list(other)
+        return set(self) == set(other)
-- 
2.2.2



More information about the anaconda-patches mailing list