blob: 6be2402a04828015610ab56e86edaa501fed3d07 [file] [log] [blame]
#!/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