From ba69f5bddd355bd8542c4a6b360aaf6fb95914c1 Mon Sep 17 00:00:00 2001 From: Anders Blomdell <anders.blomdell@control.lth.se> Date: Mon, 26 Aug 2019 16:18:54 +0200 Subject: [PATCH] Adjust sorting from cmp= to key= syntax --- src/hostinfo.py | 110 ++++++++++++++--------------------------- src/hostinfo/parser.py | 66 ++----------------------- 2 files changed, 43 insertions(+), 133 deletions(-) diff --git a/src/hostinfo.py b/src/hostinfo.py index 604217e..25121d3 100755 --- a/src/hostinfo.py +++ b/src/hostinfo.py @@ -75,7 +75,7 @@ if not hasattr(__builtins__, "True"): __builtins__["True"] = 1 __builtins__["False"] = 0 -attr_weight = { +attr_key_table = { ('host', 'name') : 1, ('disk', 'host') : 1, ('disk', 'root') : 2, @@ -91,13 +91,20 @@ attr_weight = { ('subnet', 'netmask') : 4, ('subnet', 'gateway') : 5, ('subnet', 'name_servers') : 6, + None : 99, } -class AttributeDict(dict): - __getattr__ = dict.__getitem__ +def attr_key(node, attr): # , b + return + try: + return attr_key_table[node._tag, attr] + except: + return attr_key_table[None] + +def network_order(n): + net = hostinfo.util.network(n) + return (net.version, net) -def network_order(a, b): - a_net = hostinfo.util.network(a) b_net = hostinfo.util.network(b) if not a_net or not b_net: return cmp(a,b) @@ -105,7 +112,7 @@ def network_order(a, b): return cmp(a_net, b_net) return cmp(a_net.version, b_net.version) -def host_order(a,b): +def host_order(h): def fqn(host): n = host.name[0] return n and n.endswith('.') @@ -122,44 +129,32 @@ def host_order(a,b): def all_addr(host): return ether(host) and ip(host) + # Virtual hosts (no ethernet, with ip) + if h.virtual[0] == 'yes': return (1, h.name[0]) + # Fully qualified names - if fqn(a) or fqn(b): - if fqn(a) and fqn(b): return cmp(a.name[0], b.name[0]) - if fqn(a): return -1 - if fqn(b): return 1 - pass - + if fqn(h): return (2, h.name[0]) + # Hosts without ether an ip address (reusable names) - if no_addr(a) or no_addr(b): - if no_addr(a) and no_addr(b): return cmp(a.name[0], b.name[0]) - if no_addr(a): return -1 - if no_addr(b): return 1 - pass + if no_addr(h): return (3, h.name[0]) # Hosts with ip and ether (active machines) - if all_addr(a) or all_addr(b): - if all_addr(a) and all_addr(b): return cmp(a.name[0], b.name[0]) - if all_addr(a): return -1 - if all_addr(b): return 1 - pass + if all_addr(h): return (4, h.name[0]) + # This should be machines with ether but no ip (decommissioned) - if ip(a): + if ip(h): raise hostinfo.util.HostinfoException('Unexpected ip address %s' % - a.name[0], where=a) - if ip(b): - raise hostinfo.util.HostinfoException('Unexpected ip address %s' % - b.name[0], where=b) - return cmp(a.name[0], b.name[0]) + h.name[0], where=h) + return (5, h.name[0]) -tag_weight = { +node_key_table = { ('hostinfo', 'soa') : (1, None), ('hostinfo', 'subnet') : (2, network_order), ('hostinfo', 'nameserver') : (3, None), - ('hostinfo', 'netgroup') : (4, - lambda a,b: cmp(a.name[0],b.name[0])), + ('hostinfo', 'netgroup') : (4, lambda n: n.name[0]), ('hostinfo', 'host') : (5, host_order), ('host', 'role') : (1, None), - ('host', 'automount') : (2, lambda a,b: cmp(a.host[0],b.host[0])), + ('host', 'automount') : (2, lambda a: a.host[0]), ('host', 'mio') : (3, None), ('host', 'qemu') : (4, None), ('interface', 'kickstart') : (1, None), @@ -168,51 +163,22 @@ tag_weight = { ('interface', 'alias') : (4, None), ('interface', 'dhcpserver') : (5, None), ('interface', 'nameserver') : (6, None), - ('automount', 'entry') : (1, lambda a,b: cmp(a.key[0],b.key[0])), + ('automount', 'entry') : (1, lambda e: e.key[0]), + (None) : (99, None) } -def attr_sort(node, a, b): +def node_key(parent, node): try: - aw = attr_weight[node._tag, a] + (w, subkey) = node_key_table[parent._tag, node._tag] except: - aw = 0 + (w, subkey) = node_key_table[None] + pass - try: - bw = attr_weight[node._tag, b] - except: - bw = 0 - - if aw and bw: - return cmp(aw, bw) - elif aw: - return -1 - elif bw: - return 1 - else: - return cmp(a, b) - -def tag_sort(parent, a, b): - try: - (aw, sort) = tag_weight[parent._tag, a._tag] - except: - aw = 0 + if subkey != None: + subkey = subkey(node) + pass - try: - (bw, sort) = tag_weight[parent._tag, b._tag] - except: - bw = 0 - - if aw and bw: - if aw == bw and sort: - return sort(a,b) - else: - return cmp(aw, bw) - elif aw: - return -1 - elif bw: - return 1 - else: - return None + return (w, subkey) if __name__ == '__main__': optParser = argparse.ArgumentParser(usage="%(prog)s [options] [hostinfo]") @@ -343,7 +309,7 @@ if __name__ == '__main__': if options.pretty: result = "<?xml version='1.0' encoding='utf-8'?>\n\n" - result += tree._xml(attr_sort=attr_sort, tag_sort=tag_sort) + result += tree._xml(attr_key=attr_key, node_key=node_key) print(result.encode("utf-8")) sys.exit(0) diff --git a/src/hostinfo/parser.py b/src/hostinfo/parser.py index 582871a..20eb8d9 100755 --- a/src/hostinfo/parser.py +++ b/src/hostinfo/parser.py @@ -136,58 +136,6 @@ def xml_escape(s): return result -class AttrSortWrapper: - """Wrapper class for sorting attributes - - [see Node._xml(...)]""" - def __init__(self, node, sort): - self.node = node - self.sort = sort - - def __call__(self, a, b): - """ - Return the sort order between attributes 'a' and 'b'. - - If sort returns None, a standard Python comparison is used. - """ - result = None - if self.sort: - result = self.sort(self.node, a, b) - if result == None: - if a < b: - result = -1 - elif a > b: - result = 1 - else: - result = 0 - return result - -class TagSortWrapper: - """Wrapper class for sorting tags - - [see Node._xml(...)]""" - def __init__(self, parent, sort): - self.parent = parent - self.sort = sort - - def __call__(self, a, b): - """ - Return the sort order between tags 'a' and 'b'. - - If sort returns None, a standard Python comparison is used. - """ - result = None - if self.sort: - result = self.sort(self.parent, a, b) - if result == None: - if a._tag < b._tag: - result = -1 - elif a._tag > b._tag: - result = 1 - else: - result = 0 - return result - class ChildAccessor: """Helper class for iterating over xml trees @@ -374,14 +322,13 @@ class Node: else: return AttributeAccessor(self, attr) - def _xml(self, indent=0, attr_sort=None, tag_sort=None, width=80): + def _xml(self, indent=0, attr_key=None, node_key=None, width=80): """Generate a prettyprinted xml of the tree rooted in this node""" result = "" line = "%s<%s" % (" " * indent, self._tag) blanks = " " * len(line) for k in sorted(self._attribute.keys(), - key=(attr_sort and AttrSortWrapper(self, attr_sort) - or None)): + key=attr_key and (lambda a: attr_key(self, a))): s = " %s='%s'" % (k, xml_escape(self._attribute[k])) if len(line) + len(s) > width: result += "%s\n" % line @@ -396,12 +343,9 @@ class Node: result += '\n'.join(self._char) result += '\n' pass - print("YYY", (tag_sort and TagSortWrapper(self, tag_sort) - or None), "\n") for c in sorted(self._children, - key=(tag_sort and TagSortWrapper(self, tag_sort) - or None)): - result += c._xml(indent + 1, attr_sort, tag_sort, width) + key=node_key and (lambda c: node_key(self, c))): + result += c._xml(indent + 1, attr_key, node_key, width) result += "%s</%s>\n" % (" " * indent, self._tag) return result @@ -462,7 +406,7 @@ class Comment: """Copy node and all children""" return self.__copy__() - def _xml(self, indent=0, attr_sort=None, tag_sort=None, width=80): + def _xml(self, indent=0, attr_key=None, node_key=None, width=80): """Generate a prettyprinted xml of the tree rooted in this node""" result = "%s<!--" % (" " * indent) result += self._attribute[''] -- GitLab