| #!/usr/bin/python |
| |
| # Copyright 2014 Google Inc. |
| # |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import collections |
| import types |
| |
| # The goal of this class is to store a set of unique items in the order in |
| # which they are inserted. This is important for the final makefile, where |
| # we want to make sure the image decoders are in a particular order. See |
| # images.gyp for more information. |
| class OrderedSet(object): |
| """Ordered set of unique items that supports addition and removal. |
| |
| Retains the order in which items are inserted. |
| """ |
| |
| def __init__(self): |
| self.__ordered_set = [] |
| |
| def add(self, item): |
| """Add item, if it is not already in the set. |
| |
| item is appended to the end if it is not already in the set. |
| |
| Args: |
| item: The item to add. |
| """ |
| if item not in self.__ordered_set: |
| self.__ordered_set.append(item) |
| |
| def __contains__(self, item): |
| """Whether the set contains item. |
| |
| Args: |
| item: The item to search for in the set. |
| |
| Returns: |
| bool: Whether the item is in the set. |
| """ |
| return item in self.__ordered_set |
| |
| def __iter__(self): |
| """Iterator for the set. |
| """ |
| return self.__ordered_set.__iter__() |
| |
| def remove(self, item): |
| """ |
| Remove item from the set. |
| |
| Args: |
| item: Item to be removed. |
| |
| Raises: |
| ValueError if item is not in the set. |
| """ |
| self.__ordered_set.remove(item) |
| |
| def __len__(self): |
| """Number of items in the set. |
| """ |
| return len(self.__ordered_set) |
| |
| def __getitem__(self, index): |
| """Return item at index. |
| """ |
| return self.__ordered_set[index] |
| |
| def reset(self): |
| """Reset to empty. |
| """ |
| self.__ordered_set = [] |
| |
| def set(self, other): |
| """Replace this ordered set with another. |
| |
| Args: |
| other: OrderedSet to replace this one. After this call, this OrderedSet |
| will contain exactly the same elements as other. |
| """ |
| self.__ordered_set = list(other.__ordered_set) |
| |
| VAR_NAMES = ['LOCAL_CFLAGS', |
| 'LOCAL_CPPFLAGS', |
| 'LOCAL_SRC_FILES', |
| 'LOCAL_SHARED_LIBRARIES', |
| 'LOCAL_STATIC_LIBRARIES', |
| 'LOCAL_C_INCLUDES', |
| 'LOCAL_EXPORT_C_INCLUDE_DIRS', |
| 'DEFINES', |
| 'KNOWN_TARGETS', |
| # These are not parsed by gyp, but set manually. |
| 'LOCAL_MODULE_TAGS', |
| 'LOCAL_MODULE'] |
| |
| class VarsDict(collections.namedtuple('VarsDict', VAR_NAMES)): |
| """Custom class for storing the arguments to Android.mk variables. |
| |
| Can also be treated as a dictionary with fixed keys. |
| """ |
| |
| __slots__ = () |
| |
| def __new__(cls): |
| lists = [] |
| # TODO (scroggo): Is there a better way add N items? |
| for __unused__ in range(len(VAR_NAMES)): |
| lists.append(OrderedSet()) |
| return tuple.__new__(cls, lists) |
| |
| def keys(self): |
| """Return the field names as strings. |
| """ |
| return self._fields |
| |
| def __getitem__(self, index): |
| """Return an item, indexed by a number or a string. |
| """ |
| if type(index) == types.IntType: |
| # Treat the index as an array index into a tuple. |
| return tuple.__getitem__(self, index) |
| if type(index) == types.StringType: |
| # Treat the index as a key into a dictionary. |
| return eval('self.%s' % index) |
| return None |
| |
| |
| def intersect(var_dict_list): |
| """Compute intersection of VarsDicts. |
| |
| Find the intersection of a list of VarsDicts and trim each input to its |
| unique entries. |
| |
| Args: |
| var_dict_list: list of VarsDicts. WARNING: each VarsDict will be |
| modified in place, to remove the common elements! |
| Returns: |
| VarsDict containing list entries common to all VarsDicts in |
| var_dict_list |
| """ |
| intersection = VarsDict() |
| # First VarsDict |
| var_dict_a = var_dict_list[0] |
| # The rest. |
| other_var_dicts = var_dict_list[1:] |
| |
| for key in var_dict_a.keys(): |
| # Copy A's list, so we can continue iterating after modifying the original. |
| a_list = list(var_dict_a[key]) |
| for item in a_list: |
| # If item is in all lists, add to intersection, and remove from all. |
| in_all_lists = True |
| for var_dict in other_var_dicts: |
| if not item in var_dict[key]: |
| in_all_lists = False |
| break |
| if in_all_lists: |
| intersection[key].add(item) |
| for var_dict in var_dict_list: |
| var_dict[key].remove(item) |
| return intersection |
| |