osdict: Simplify os list sorting

Previously we tried to use a combination of distro class and version
number to produce a correct ordering that was independent of the
osinfo short ID. The original intent was to have correct ordering
for Windows entries in the virt-manager UI, since the short ID
values are all over the place.

Nowadays that doesn't really matter, since we weed out old
unsupported entries by default. And in the mean time, our current
sort method gives some weird results like interspersing silverblue
entries with fedora entries.

Using a natural/human sort is simpler and handles things pretty well.

Change the UI to sort by the OS label too which preserves some of
the good behavior of original method

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2022-02-11 12:17:21 -05:00
parent 96a40b1143
commit 95ba78f3e8
3 changed files with 15 additions and 85 deletions

View File

@ -52,7 +52,7 @@ class vmmOSList(vmmGObjectUI):
# (os object, label)
os_list_model = Gtk.ListStore(object, str)
all_os = virtinst.OSDB.list_os()
all_os = virtinst.OSDB.list_os(sortkey="label")
for os in all_os:
os_list_model.append([os, "%s (%s)" % (os.label, os.name)])

View File

@ -760,8 +760,8 @@ class _DebianDistro(_DistroTree):
if self.cache.debian_media_type == "daily":
log.debug("Appears to be debian 'daily' URL, using latest "
"debian OS")
return oses[0].name
"debiantesting")
return "debiantesting"
for osobj in oses:
if osobj.codename:

View File

@ -27,78 +27,6 @@ def _media_create_from_location(location):
return Libosinfo.Media.create_from_location_with_flags(location, None, 0)
###################
# Sorting helpers #
###################
def _sortby(osobj):
"""
Combines distro+version to make a more sort friendly string. Examples
fedora25 -> fedora-0025000000000000
ubuntu17.04 -> ubuntu-0017000400000000
win2k8r2 -> win-0006000100000000
"""
if osobj.is_generic():
# Sort generic at the end of the list
return "zzzzzz-000000000000"
version = osobj.version
try:
t = version.split(".")
t = t[:min(4, len(t))] + [0] * (4 - min(4, len(t)))
new_version = ""
for n in t:
new_version = new_version + ("%.4i" % int(n))
version = new_version
except Exception:
pass
return "%s-%s" % (osobj.distro, version)
def _sort(tosort):
sortby_mappings = {}
distro_mappings = {}
retlist = []
for key, osinfo in tosort.items():
# Libosinfo has some duplicate version numbers here, so append .1
# if there's a collision
sortby = _sortby(osinfo)
while sortby_mappings.get(sortby):
sortby = sortby + ".1"
sortby_mappings[sortby] = key
# Group by distro first, so debian is clumped together, fedora, etc.
distro = osinfo.distro
if osinfo.is_generic():
distro = "zzzzzz"
if distro not in distro_mappings:
distro_mappings[distro] = []
distro_mappings[distro].append(sortby)
# We want returned lists to be sorted descending by 'distro', so we get
# debian5, debian4, fedora14, fedora13
# rather than
# debian4, debian5, fedora13, fedora14
for distro_list in list(distro_mappings.values()):
distro_list.sort()
distro_list.reverse()
sorted_distro_list = list(distro_mappings.keys())
sorted_distro_list.sort()
# Build the final list of sorted os objects
for distro in sorted_distro_list:
distro_list = distro_mappings[distro]
for key in distro_list:
orig_key = sortby_mappings[key]
retlist.append(tosort[orig_key])
return retlist
class _OsinfoIter:
"""
Helper to turn osinfo style get_length/get_nth lists into python
@ -221,19 +149,21 @@ class _OSDB(object):
return None # pragma: no cover
return osobj.get_short_id(), _OsTree(treeobj)
def list_os(self):
def list_os(self, sortkey="name"):
"""
List all OSes in the DB
List all OSes in the DB, sorting by the passes _OsVariant attribute
"""
sortmap = {}
oslist = [_OsVariant(osent) for osent in
self._os_db.get_os_list().get_elements()]
oslist.append(self._os_generic)
oslist = self._os_db.get_os_list().get_elements()
for osent in oslist:
osobj = _OsVariant(osent)
sortmap[osobj.name] = osobj
sortmap[self._os_generic.name] = self._os_generic
return _sort(sortmap)
# human/natural sort, but with reverse sorted numbers
def to_int(text):
return (int(text) * -1) if text.isdigit() else text.lower()
def alphanum_key(obj):
val = getattr(obj, sortkey)
return [to_int(c) for c in re.split('([0-9]+)', val)]
return list(sorted(oslist, key=alphanum_key))
OSDB = _OSDB()