Home | History | Annotate | Download | only in gyp_gen
      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 
      8 import collections
      9 import 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.
     15 class 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 
     87 VAR_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 
    100 class 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 
    132 def 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