Tweak svn/git ignores
[zxing.git] / cpp / scons / scons-local-2.0.0.final.0 / SCons / PathList.py
1 #
2 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "src/engine/SCons/PathList.py 5023 2010/06/14 22:05:46 scons"
25
26 __doc__ = """SCons.PathList
27
28 A module for handling lists of directory paths (the sort of things
29 that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
30 efficiency as we can while still keeping the evaluation delayed so that we
31 Do the Right Thing (almost) regardless of how the variable is specified.
32
33 """
34
35 import os
36
37 import SCons.Memoize
38 import SCons.Node
39 import SCons.Util
40
41 #
42 # Variables to specify the different types of entries in a PathList object:
43 #
44
45 TYPE_STRING_NO_SUBST = 0        # string with no '$'
46 TYPE_STRING_SUBST = 1           # string containing '$'
47 TYPE_OBJECT = 2                 # other object
48
49 def node_conv(obj):
50     """
51     This is the "string conversion" routine that we have our substitutions
52     use to return Nodes, not strings.  This relies on the fact that an
53     EntryProxy object has a get() method that returns the underlying
54     Node that it wraps, which is a bit of architectural dependence
55     that we might need to break or modify in the future in response to
56     additional requirements.
57     """
58     try:
59         get = obj.get
60     except AttributeError:
61         if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ):
62             result = obj
63         else:
64             result = str(obj)
65     else:
66         result = get()
67     return result
68
69 class _PathList(object):
70     """
71     An actual PathList object.
72     """
73     def __init__(self, pathlist):
74         """
75         Initializes a PathList object, canonicalizing the input and
76         pre-processing it for quicker substitution later.
77
78         The stored representation of the PathList is a list of tuples
79         containing (type, value), where the "type" is one of the TYPE_*
80         variables defined above.  We distinguish between:
81
82             strings that contain no '$' and therefore need no
83             delayed-evaluation string substitution (we expect that there
84             will be many of these and that we therefore get a pretty
85             big win from avoiding string substitution)
86
87             strings that contain '$' and therefore need substitution
88             (the hard case is things like '${TARGET.dir}/include',
89             which require re-evaluation for every target + source)
90
91             other objects (which may be something like an EntryProxy
92             that needs a method called to return a Node)
93
94         Pre-identifying the type of each element in the PathList up-front
95         and storing the type in the list of tuples is intended to reduce
96         the amount of calculation when we actually do the substitution
97         over and over for each target.
98         """
99         if SCons.Util.is_String(pathlist):
100             pathlist = pathlist.split(os.pathsep)
101         elif not SCons.Util.is_Sequence(pathlist):
102             pathlist = [pathlist]
103
104         pl = []
105         for p in pathlist:
106             try:
107                 index = p.find('$')
108             except (AttributeError, TypeError):
109                 type = TYPE_OBJECT
110             else:
111                 if index == -1:
112                     type = TYPE_STRING_NO_SUBST
113                 else:
114                     type = TYPE_STRING_SUBST
115             pl.append((type, p))
116
117         self.pathlist = tuple(pl)
118
119     def __len__(self): return len(self.pathlist)
120
121     def __getitem__(self, i): return self.pathlist[i]
122
123     def subst_path(self, env, target, source):
124         """
125         Performs construction variable substitution on a pre-digested
126         PathList for a specific target and source.
127         """
128         result = []
129         for type, value in self.pathlist:
130             if type == TYPE_STRING_SUBST:
131                 value = env.subst(value, target=target, source=source,
132                                   conv=node_conv)
133                 if SCons.Util.is_Sequence(value):
134                     result.extend(value)
135                     continue
136                     
137             elif type == TYPE_OBJECT:
138                 value = node_conv(value)
139             if value:
140                 result.append(value)
141         return tuple(result)
142
143
144 class PathListCache(object):
145     """
146     A class to handle caching of PathList lookups.
147
148     This class gets instantiated once and then deleted from the namespace,
149     so it's used as a Singleton (although we don't enforce that in the
150     usual Pythonic ways).  We could have just made the cache a dictionary
151     in the module namespace, but putting it in this class allows us to
152     use the same Memoizer pattern that we use elsewhere to count cache
153     hits and misses, which is very valuable.
154
155     Lookup keys in the cache are computed by the _PathList_key() method.
156     Cache lookup should be quick, so we don't spend cycles canonicalizing
157     all forms of the same lookup key.  For example, 'x:y' and ['x',
158     'y'] logically represent the same list, but we don't bother to
159     split string representations and treat those two equivalently.
160     (Note, however, that we do, treat lists and tuples the same.)
161
162     The main type of duplication we're trying to catch will come from
163     looking up the same path list from two different clones of the
164     same construction environment.  That is, given
165     
166         env2 = env1.Clone()
167
168     both env1 and env2 will have the same CPPPATH value, and we can
169     cheaply avoid re-parsing both values of CPPPATH by using the
170     common value from this cache.
171     """
172     if SCons.Memoize.use_memoizer:
173         __metaclass__ = SCons.Memoize.Memoized_Metaclass
174
175     memoizer_counters = []
176
177     def __init__(self):
178         self._memo = {}
179
180     def _PathList_key(self, pathlist):
181         """
182         Returns the key for memoization of PathLists.
183
184         Note that we want this to be pretty quick, so we don't completely
185         canonicalize all forms of the same list.  For example,
186         'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically
187         represent the same list if you're executing from $ROOT, but
188         we're not going to bother splitting strings into path elements,
189         or massaging strings into Nodes, to identify that equivalence.
190         We just want to eliminate obvious redundancy from the normal
191         case of re-using exactly the same cloned value for a path.
192         """
193         if SCons.Util.is_Sequence(pathlist):
194             pathlist = tuple(SCons.Util.flatten(pathlist))
195         return pathlist
196
197     memoizer_counters.append(SCons.Memoize.CountDict('PathList', _PathList_key))
198
199     def PathList(self, pathlist):
200         """
201         Returns the cached _PathList object for the specified pathlist,
202         creating and caching a new object as necessary.
203         """
204         pathlist = self._PathList_key(pathlist)
205         try:
206             memo_dict = self._memo['PathList']
207         except KeyError:
208             memo_dict = {}
209             self._memo['PathList'] = memo_dict
210         else:
211             try:
212                 return memo_dict[pathlist]
213             except KeyError:
214                 pass
215
216         result = _PathList(pathlist)
217
218         memo_dict[pathlist] = result
219
220         return result
221
222 PathList = PathListCache().PathList
223
224
225 del PathListCache
226
227 # Local Variables:
228 # tab-width:4
229 # indent-tabs-mode:nil
230 # End:
231 # vim: set expandtab tabstop=4 shiftwidth=4: