Home | History | Annotate | Download | only in testrunner
      1 #
      2 # Copyright 2012, The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #     http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 
     16 """Data structure for processing makefiles."""
     17 
     18 import os
     19 
     20 import android_build
     21 import android_mk
     22 import errors
     23 
     24 class MakeNode(object):
     25   """Represents single node in make tree."""
     26 
     27   def __init__(self, name, parent):
     28     self._name = name
     29     self._children_map = {}
     30     self._is_leaf = False
     31     self._parent = parent
     32     self._includes_submake = None
     33     if parent:
     34       self._path = os.path.join(parent._GetPath(), name)
     35     else:
     36       self._path = ""
     37 
     38   def _AddPath(self, path_segs):
     39     """Adds given path to this node.
     40 
     41     Args:
     42       path_segs: list of path segments
     43     """
     44     if not path_segs:
     45       # done processing path
     46       return self
     47     current_seg = path_segs.pop(0)
     48     child = self._children_map.get(current_seg)
     49     if not child:
     50       child = MakeNode(current_seg, self)
     51       self._children_map[current_seg] = child
     52     return child._AddPath(path_segs)
     53 
     54   def _SetLeaf(self, is_leaf):
     55     self._is_leaf = is_leaf
     56 
     57   def _GetPath(self):
     58     return self._path
     59 
     60   def _DoesIncludesSubMake(self):
     61     if self._includes_submake is None:
     62       if self._is_leaf:
     63         path = os.path.join(android_build.GetTop(), self._path)
     64         mk_parser = android_mk.CreateAndroidMK(path)
     65         self._includes_submake = mk_parser.IncludesMakefilesUnder()
     66       else:
     67         self._includes_submake = False
     68     return self._includes_submake
     69 
     70   def _DoesParentIncludeMe(self):
     71     return self._parent and self._parent._DoesIncludesSubMake()
     72 
     73   def _BuildPrunedMakeList(self, make_list):
     74     if self._is_leaf and not self._DoesParentIncludeMe():
     75       make_list.append(os.path.join(self._path, "Android.mk"))
     76     for child in self._children_map.itervalues():
     77       child._BuildPrunedMakeList(make_list)
     78 
     79 
     80 class MakeTree(MakeNode):
     81   """Data structure for building a non-redundant set of Android.mk paths.
     82 
     83   Used to collapse set of Android.mk files to use to prevent issuing make
     84   command that include same module multiple times due to include rules.
     85   """
     86 
     87   def __init__(self):
     88     super(MakeTree, self).__init__("", None)
     89 
     90   def AddPath(self, path):
     91     """Adds make directory path to tree.
     92 
     93     Will have no effect if path is already included in make set.
     94 
     95     Args:
     96       path: filesystem path to directory to build, relative to build root.
     97     """
     98     path = os.path.normpath(path)
     99     mk_path = os.path.join(android_build.GetTop(), path, "Android.mk")
    100     if not os.path.isfile(mk_path):
    101       raise errors.AbortError("%s does not exist" % mk_path)
    102     path_segs = path.split(os.sep)
    103     child = self._AddPath(path_segs)
    104     child._SetLeaf(True)
    105 
    106   def GetPrunedMakeList(self):
    107     """Return as list of the minimum set of Android.mk files necessary to
    108     build all leaf nodes in tree.
    109     """
    110     make_list = []
    111     self._BuildPrunedMakeList(make_list)
    112     return make_list
    113 
    114   def IsEmpty(self):
    115     return not self._children_map
    116 
    117