From 90eeeb382e9397a16aaa8df2d150e7cf5489af2f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 23 Nov 2020 15:24:01 +0200 Subject: [PATCH] build script: support case insensitive target names --- build.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/build.py b/build.py index 86d70fce..e4d5cc43 100755 --- a/build.py +++ b/build.py @@ -24,6 +24,7 @@ if sys.hexversion < 0x3070000: print('Build module requires Python 3.7 or newer') exit(1) +import collections import argparse import re import os @@ -419,6 +420,78 @@ class DevilutionXTarget(CMakeTarget): opts['CMAKE_EXE_LINKER_FLAGS'] += extra_linker_args +# Case insensitive dictionary class from +# from https://github.com/psf/requests/blob/v2.25.0/requests/structures.py + +class CaseInsensitiveDict(collections.abc.MutableMapping): + """A case-insensitive ``dict``-like object. + Implements all methods and operations of + ``MutableMapping`` as well as dict's ``copy``. Also + provides ``lower_items``. + All keys are expected to be strings. The structure remembers the + case of the last key to be set, and ``iter(instance)``, + ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` + will contain case-sensitive keys. However, querying and contains + testing is case insensitive:: + cid = CaseInsensitiveDict() + cid['Accept'] = 'application/json' + cid['aCCEPT'] == 'application/json' # True + list(cid) == ['Accept'] # True + For example, ``headers['content-encoding']`` will return the + value of a ``'Content-Encoding'`` response header, regardless + of how the header name was originally stored. + If the constructor, ``.update``, or equality comparison + operations are given keys that have equal ``.lower()``s, the + behavior is undefined. + """ + + def __init__(self, data=None, **kwargs): + self._store = collections.OrderedDict() + if data is None: + data = {} + self.update(data, **kwargs) + + def __setitem__(self, key, value): + # Use the lowercased key for lookups, but store the actual + # key alongside the value. + self._store[key.lower()] = (key, value) + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __delitem__(self, key): + del self._store[key.lower()] + + def __iter__(self): + return (casedkey for casedkey, mappedvalue in self._store.values()) + + def __len__(self): + return len(self._store) + + def lower_items(self): + """Like iteritems(), but with all lowercase keys.""" + return ( + (lowerkey, keyval[1]) + for (lowerkey, keyval) + in self._store.items() + ) + + def __eq__(self, other): + if isinstance(other, collections.abc.Mapping): + other = CaseInsensitiveDict(other) + else: + return NotImplemented + # Compare insensitively + return dict(self.lower_items()) == dict(other.lower_items()) + + # Copy is required + def copy(self): + return CaseInsensitiveDict(self._store.values()) + + def __repr__(self): + return str(dict(self.items())) + + class Builder(object): def __init__(self, args: list): self._create_targets() @@ -527,7 +600,7 @@ class Builder(object): DevilutionXTarget(), ) - self.targets = {target.name: target for target in targets} + self.targets = CaseInsensitiveDict({target.name: target for target in targets}) def _parse_arguments(self, args: list): assert self.targets