1#!/usr/bin/python 2 3# Copyright 2014 Google Inc. 4# 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7 8import collections 9import types 10 11# The goal of this class is to store a set of unique items in the order in 12# which they are inserted. This is important for the final makefile, where 13# we want to make sure the image decoders are in a particular order. See 14# images.gyp for more information. 15class OrderedSet(object): 16 """Ordered set of unique items that supports addition and removal. 17 18 Retains the order in which items are inserted. 19 """ 20 21 def __init__(self): 22 self.__ordered_set = [] 23 24 def add(self, item): 25 """Add item, if it is not already in the set. 26 27 item is appended to the end if it is not already in the set. 28 29 Args: 30 item: The item to add. 31 """ 32 if item not in self.__ordered_set: 33 self.__ordered_set.append(item) 34 35 def __contains__(self, item): 36 """Whether the set contains item. 37 38 Args: 39 item: The item to search for in the set. 40 41 Returns: 42 bool: Whether the item is in the set. 43 """ 44 return item in self.__ordered_set 45 46 def __iter__(self): 47 """Iterator for the set. 48 """ 49 return self.__ordered_set.__iter__() 50 51 def remove(self, item): 52 """ 53 Remove item from the set. 54 55 Args: 56 item: Item to be removed. 57 58 Raises: 59 ValueError if item is not in the set. 60 """ 61 self.__ordered_set.remove(item) 62 63 def __len__(self): 64 """Number of items in the set. 65 """ 66 return len(self.__ordered_set) 67 68 def __getitem__(self, index): 69 """Return item at index. 70 """ 71 return self.__ordered_set[index] 72 73 def reset(self): 74 """Reset to empty. 75 """ 76 self.__ordered_set = [] 77 78 def set(self, other): 79 """Replace this ordered set with another. 80 81 Args: 82 other: OrderedSet to replace this one. After this call, this OrderedSet 83 will contain exactly the same elements as other. 84 """ 85 self.__ordered_set = list(other.__ordered_set) 86 87VAR_NAMES = ['LOCAL_CFLAGS', 88 'LOCAL_CPPFLAGS', 89 'LOCAL_SRC_FILES', 90 'LOCAL_SHARED_LIBRARIES', 91 'LOCAL_STATIC_LIBRARIES', 92 'LOCAL_C_INCLUDES', 93 'LOCAL_EXPORT_C_INCLUDE_DIRS', 94 'DEFINES', 95 'KNOWN_TARGETS', 96 # These are not parsed by gyp, but set manually. 97 'LOCAL_MODULE_TAGS', 98 'LOCAL_MODULE'] 99 100class VarsDict(collections.namedtuple('VarsDict', VAR_NAMES)): 101 """Custom class for storing the arguments to Android.mk variables. 102 103 Can also be treated as a dictionary with fixed keys. 104 """ 105 106 __slots__ = () 107 108 def __new__(cls): 109 lists = [] 110 # TODO (scroggo): Is there a better way add N items? 111 for __unused__ in range(len(VAR_NAMES)): 112 lists.append(OrderedSet()) 113 return tuple.__new__(cls, lists) 114 115 def keys(self): 116 """Return the field names as strings. 117 """ 118 return self._fields 119 120 def __getitem__(self, index): 121 """Return an item, indexed by a number or a string. 122 """ 123 if type(index) == types.IntType: 124 # Treat the index as an array index into a tuple. 125 return tuple.__getitem__(self, index) 126 if type(index) == types.StringType: 127 # Treat the index as a key into a dictionary. 128 return eval('self.%s' % index) 129 return None 130 131 132def intersect(var_dict_list): 133 """Compute intersection of VarsDicts. 134 135 Find the intersection of a list of VarsDicts and trim each input to its 136 unique entries. 137 138 Args: 139 var_dict_list: list of VarsDicts. WARNING: each VarsDict will be 140 modified in place, to remove the common elements! 141 Returns: 142 VarsDict containing list entries common to all VarsDicts in 143 var_dict_list 144 """ 145 intersection = VarsDict() 146 # First VarsDict 147 var_dict_a = var_dict_list[0] 148 # The rest. 149 other_var_dicts = var_dict_list[1:] 150 151 for key in var_dict_a.keys(): 152 # Copy A's list, so we can continue iterating after modifying the original. 153 a_list = list(var_dict_a[key]) 154 for item in a_list: 155 # If item is in all lists, add to intersection, and remove from all. 156 in_all_lists = True 157 for var_dict in other_var_dicts: 158 if not item in var_dict[key]: 159 in_all_lists = False 160 break 161 if in_all_lists: 162 intersection[key].add(item) 163 for var_dict in var_dict_list: 164 var_dict[key].remove(item) 165 return intersection 166 167