3 Various utility functions go here.
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
41 from UserDict import UserDict
47 from UserString import UserString
49 # "Borrowed" from the Python 2.2 UserString module
50 # and modified slightly for use with SCons.
52 def __init__(self, seq):
55 elif isinstance(seq, UserString):
56 self.data = seq.data[:]
59 def __str__(self): return str(self.data)
60 def __repr__(self): return repr(self.data)
61 def __int__(self): return int(self.data)
62 def __long__(self): return long(self.data)
63 def __float__(self): return float(self.data)
64 def __complex__(self): return complex(self.data)
65 def __hash__(self): return hash(self.data)
67 def __cmp__(self, string):
68 if isinstance(string, UserString):
69 return cmp(self.data, string.data)
71 return cmp(self.data, string)
72 def __contains__(self, char):
73 return char in self.data
75 def __len__(self): return len(self.data)
76 def __getitem__(self, index): return self.__class__(self.data[index])
77 def __getslice__(self, start, end):
78 start = max(start, 0); end = max(end, 0)
79 return self.__class__(self.data[start:end])
81 def __add__(self, other):
82 if isinstance(other, UserString):
83 return self.__class__(self.data + other.data)
84 elif is_String(other):
85 return self.__class__(self.data + other)
87 return self.__class__(self.data + str(other))
88 def __radd__(self, other):
90 return self.__class__(other + self.data)
92 return self.__class__(str(other) + self.data)
94 return self.__class__(self.data*n)
101 except AttributeError:
104 for i in xrange(len(lists[0])):
105 result.append(tuple(map(lambda l, i=i: l[i], lists)))
107 __builtin__.zip = zip
110 if _altsep is None and sys.platform == 'win32':
111 # My ActivePython 2.0.1 doesn't set os.altsep! What gives?
114 def rightmost_separator(path, sep, _altsep=_altsep):
116 return max(rfind(path, sep), rfind(path, _altsep))
118 rightmost_separator = string.rfind
120 # First two from the Python Cookbook, just for completeness.
121 # (Yeah, yeah, YAGNI...)
122 def containsAny(str, set):
123 """Check whether sequence str contains ANY of the items in set."""
125 if c in str: return 1
128 def containsAll(str, set):
129 """Check whether sequence str contains ALL of the items in set."""
131 if c not in str: return 0
134 def containsOnly(str, set):
135 """Check whether sequence str contains ONLY items in set."""
137 if c not in set: return 0
141 "Same as os.path.splitext() but faster."
142 sep = rightmost_separator(path, os.sep)
143 dot = string.rfind(path, '.')
144 # An ext is only real if it has at least one non-digit char
145 if dot > sep and not containsOnly(path[dot:], "0123456789."):
146 return path[:dot],path[dot:]
152 Make the drive letter (if any) upper case.
153 This is useful because Windows is inconsitent on the case
154 of the drive letter, which can cause inconsistencies when
155 calculating command signatures.
157 drive, rest = os.path.splitdrive(path)
159 path = string.upper(drive) + rest
163 # Generic convert-to-string functions that abstract away whether or
164 # not the Python we're executing has Unicode support. The wrapper
165 # to_String_for_signature() will use a for_signature() method if the
166 # specified object has one.
168 if hasattr(types, 'UnicodeType'):
170 if isinstance(s, UserString):
174 if t is types.UnicodeType:
181 def to_String_for_signature(obj):
183 f = obj.for_signature
184 except AttributeError:
185 return to_String(obj)
189 # Indexed by the SUBST_* constants below.
190 _strconv = [to_String, to_String, to_String_for_signature]
193 """A wrapper for a string. If you use this object wrapped
194 around a string, then it will be interpreted as literal.
195 When passed to the command interpreter, all special
196 characters will be escaped."""
197 def __init__(self, lstr):
203 def escape(self, escape_func):
204 return escape_func(self.lstr)
206 def for_signature(self):
209 def is_literal(self):
212 class SpecialAttrWrapper:
213 """This is a wrapper for what we call a 'Node special attribute.'
214 This is any of the attributes of a Node that we can reference from
215 Environment variable substitution, such as $TARGET.abspath or
216 $SOURCES[1].filebase. We implement the same methods as Literal
217 so we can handle special characters, plus a for_signature method,
218 such that we can return some canonical string during signature
219 calculation to avoid unnecessary rebuilds."""
221 def __init__(self, lstr, for_signature=None):
222 """The for_signature parameter, if supplied, will be the
223 canonical string we return from for_signature(). Else
224 we will simply return lstr."""
227 self.forsig = for_signature
234 def escape(self, escape_func):
235 return escape_func(self.lstr)
237 def for_signature(self):
240 def is_literal(self):
243 class CallableComposite(UserList.UserList):
244 """A simple composite callable class that, when called, will invoke all
245 of its contained callables with the same arguments."""
246 def __call__(self, *args, **kwargs):
247 retvals = map(lambda x, args=args, kwargs=kwargs: apply(x,
251 if self.data and (len(self.data) == len(filter(callable, retvals))):
252 return self.__class__(retvals)
253 return NodeList(retvals)
255 class NodeList(UserList.UserList):
256 """This class is almost exactly like a regular list of Nodes
257 (actually it can hold any object), with one important difference.
258 If you try to get an attribute from this list, it will return that
259 attribute from every item in the list. For example:
261 >>> someList = NodeList([ ' foo ', ' bar ' ])
265 def __nonzero__(self):
266 return len(self.data) != 0
269 return string.join(map(str, self.data))
271 def __getattr__(self, name):
273 # If there is nothing in the list, then we have no attributes to
274 # pass through, so raise AttributeError for everything.
275 raise AttributeError, "NodeList has no attribute: %s" % name
277 # Return a list of the attribute, gotten from every element
279 attrList = map(lambda x, n=name: getattr(x, n), self.data)
281 # Special case. If the attribute is callable, we do not want
282 # to return a list of callables. Rather, we want to return a
283 # single callable that, when called, will invoke the function on
284 # all elements of this list.
285 if self.data and (len(self.data) == len(filter(callable, attrList))):
286 return CallableComposite(attrList)
287 return self.__class__(attrList)
289 _valid_var = re.compile(r'[_a-zA-Z]\w*$')
290 _get_env_var = re.compile(r'^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$')
292 def is_valid_construction_var(varstr):
293 """Return if the specified string is a legitimate construction
296 return _valid_var.match(varstr)
298 def get_environment_var(varstr):
299 """Given a string, first determine if it looks like a reference
300 to a single environment variable, like "$FOO" or "${FOO}".
301 If so, return that variable with no decorations ("FOO").
302 If not, return None."""
303 mo=_get_env_var.match(to_String(varstr))
313 def quote_spaces(arg):
314 """Generic function for putting double quotes around any string that
315 has white space in it."""
316 if ' ' in arg or '\t' in arg:
321 class CmdStringHolder(UserString):
322 """This is a special class used to hold strings generated by
323 scons_subst() and scons_subst_list(). It defines a special method
324 escape(). When passed a function with an escape algorithm for a
325 particular platform, it will return the contained string with the
326 proper escape sequences inserted.
328 This should really be a subclass of UserString, but that module
329 doesn't exist in Python 1.5.2."""
330 def __init__(self, cmd, literal=None):
331 UserString.__init__(self, cmd)
332 self.literal = literal
334 def is_literal(self):
337 def escape(self, escape_func, quote_func=quote_spaces):
338 """Escape the string with the supplied function. The
339 function is expected to take an arbitrary string, then
340 return it with all special characters escaped and ready
341 for passing to the command interpreter.
343 After calling this function, the next call to str() will
344 return the escaped string.
347 if self.is_literal():
348 return escape_func(self.data)
349 elif ' ' in self.data or '\t' in self.data:
350 return quote_func(self.data)
356 self.__call__ = self.print_it
358 def print_it(self, text, append_newline=1):
359 if append_newline: text = text + '\n'
360 sys.stdout.write(text)
362 def dont_print(self, text, append_newline=1):
365 def set_mode(self, mode):
367 self.__call__ = self.print_it
369 self.__call__ = self.dont_print
371 def escape_list(list, escape_func):
372 """Escape a list of arguments by running the specified escape_func
373 on every object in the list that has an escape() method."""
374 def escape(obj, escape_func=escape_func):
377 except AttributeError:
380 return e(escape_func)
381 return map(escape, list)
384 """A wrapper class that delays turning a list of sources or targets
385 into a NodeList until it's needed. The specified function supplied
386 when the object is initialized is responsible for turning raw nodes
387 into proxies that implement the special attributes like .abspath,
388 .source, etc. This way, we avoid creating those proxies just
389 "in case" someone is going to use $TARGET or the like, and only
390 go through the trouble if we really have to.
392 In practice, this might be a wash performance-wise, but it's a little
393 cleaner conceptually...
396 def __init__(self, list, func):
399 def _create_nodelist(self):
402 except AttributeError:
406 elif not is_List(list):
408 # The map(self.func) call is what actually turns
409 # a list into appropriate proxies.
410 self.nodelist = NodeList(map(self.func, list))
413 class Targets_or_Sources(UserList.UserList):
414 """A class that implements $TARGETS or $SOURCES expansions by in turn
415 wrapping a NLWrapper. This class handles the different methods used
416 to access the list, calling the NLWrapper to create proxies on demand.
418 Note that we subclass UserList.UserList purely so that the is_List()
419 function will identify an object of this class as a list during
420 variable expansion. We're not really using any UserList.UserList
423 def __init__(self, nl):
425 def __getattr__(self, attr):
426 nl = self.nl._create_nodelist()
427 return getattr(nl, attr)
428 def __getitem__(self, i):
429 nl = self.nl._create_nodelist()
431 def __getslice__(self, i, j):
432 nl = self.nl._create_nodelist()
433 i = max(i, 0); j = max(j, 0)
436 nl = self.nl._create_nodelist()
439 nl = self.nl._create_nodelist()
442 class Target_or_Source:
443 """A class that implements $TARGET or $SOURCE expansions by in turn
444 wrapping a NLWrapper. This class handles the different methods used
445 to access an individual proxy Node, calling the NLWrapper to create
448 def __init__(self, nl):
450 def __getattr__(self, attr):
451 nl = self.nl._create_nodelist()
455 # If there is nothing in the list, then we have no attributes to
456 # pass through, so raise AttributeError for everything.
457 raise AttributeError, "NodeList has no attribute: %s" % attr
458 return getattr(nl0, attr)
460 nl = self.nl._create_nodelist()
467 nl = self.nl._create_nodelist()
474 def subst_dict(target, source):
475 """Create a dictionary for substitution of special
476 construction variables.
478 This translates the following special arguments:
480 target - the target (object or array of objects),
481 used to generate the TARGET and TARGETS
482 construction variables
484 source - the source (object or array of objects),
485 used to generate the SOURCES and SOURCE
486 construction variables
491 tnl = NLWrapper(target, lambda x: x.get_subst_proxy())
492 dict['TARGETS'] = Targets_or_Sources(tnl)
493 dict['TARGET'] = Target_or_Source(tnl)
496 def get_src_subst_proxy(node):
499 except AttributeError:
503 return node.get_subst_proxy()
504 snl = NLWrapper(source, get_src_subst_proxy)
505 dict['SOURCES'] = Targets_or_Sources(snl)
506 dict['SOURCE'] = Target_or_Source(snl)
510 # Constants for the "mode" parameter to scons_subst_list() and
511 # scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
512 # gives a command line suitable for passing to a shell. SUBST_SIG
513 # gives a command line appropriate for calculating the signature
514 # of a command line...if this changes, we should rebuild.
519 _rm = re.compile(r'\$[()]')
520 _remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)')
522 # Indexed by the SUBST_* constants above.
523 _regex_remove = [ _rm, None, _remove ]
525 # Regular expressions for splitting strings and handling substitutions,
526 # for use by the scons_subst() and scons_subst_list() functions:
528 # The first expression compiled matches all of the $-introduced tokens
529 # that we need to process in some way, and is used for substitutions.
530 # The expressions it matches are:
535 # "$variable" [must begin with alphabetic or underscore]
538 # The second expression compiled is used for splitting strings into tokens
539 # to be processed, and it matches all of the tokens listed above, plus
540 # the following that affect how arguments do or don't get joined together:
543 # "non-white-space" [without any dollar signs]
544 # "$" [single dollar sign]
546 _dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
547 _dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
548 _separate_args = re.compile(r'(%s|\s+|[^\s\$]+|\$)' % _dollar_exps_str)
550 # This regular expression is used to replace strings of multiple white
551 # space characters in the string result from the scons_subst() function.
552 _space_sep = re.compile(r'[\t ]+(?![^{]*})')
554 def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
555 """Expand a string containing construction variable substitutions.
557 This is the work-horse function for substitutions in file names
558 and the like. The companion scons_subst_list() function (below)
559 handles separating command lines into lists of arguments, so see
560 that function if that's what you're looking for.
562 if type(strSubst) == types.StringType and string.find(strSubst, '$') < 0:
566 """A class to construct the results of a scons_subst() call.
568 This binds a specific construction environment, mode, target and
569 source with two methods (substitute() and expand()) that handle
572 def __init__(self, env, mode, target, source, conv, gvars):
580 def expand_var_once(self, var, lvars):
585 return self.gvars[var]
589 def expand(self, s, lvars):
590 """Expand a single "token" as necessary, returning an
591 appropriate string containing the expansion.
593 This handles expanding different types of things (strings,
594 lists, callables) appropriately. It calls the wrapper
595 substitute() method to re-expand things as necessary, so that
596 the results of expansions of side-by-side strings still get
597 re-evaluated separately, not smushed together.
602 except (IndexError, ValueError):
611 if key[0] == '{' or string.find(key, '.') >= 0:
615 s = eval(key, self.gvars, lvars)
616 except (IndexError, NameError, TypeError):
618 except SyntaxError,e:
620 raise SCons.Errors.BuildError, (self.target[0], "Syntax error `%s' trying to evaluate `%s'" % (e,s))
622 raise SCons.Errors.UserError, "Syntax error `%s' trying to evaluate `%s'" % (e,s)
624 s = self.expand_var_once(key, lvars)
626 # Before re-expanding the result, handle
627 # recursive expansion by copying the local
628 # variable dictionary and overwriting a null
629 # string for the value of the variable name
632 # This could potentially be optimized by only
633 # copying lvars when s contains more expansions,
634 # but lvars is usually supposed to be pretty
635 # small, and deeply nested variable expansions
636 # are probably more the exception than the norm,
637 # so it should be tolerable for now.
639 var = string.split(key, '.')[0]
641 return self.substitute(s, lv)
645 def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
646 return conv(substitute(l, lvars))
648 return string.join(r)
651 s = s(target=self.target,
654 for_signature=(self.mode != SUBST_CMD))
656 # This probably indicates that it's a callable
657 # object that doesn't match our calling arguments
660 return self.substitute(s, lvars)
666 def substitute(self, args, lvars):
667 """Substitute expansions in an argument or list of arguments.
669 This serves as a wrapper for splitting up a string into
670 separate tokens. __cacheable__
672 if is_String(args) and not isinstance(args, CmdStringHolder):
674 def sub_match(match, conv=self.conv, expand=self.expand, lvars=lvars):
675 return conv(expand(match.group(1), lvars))
676 result = _dollar_exps.sub(sub_match, args)
678 # If the internal conversion routine doesn't return
679 # strings (it could be overridden to return Nodes, for
680 # example), then the 1.5.2 re module will throw this
681 # exception. Back off to a slower, general-purpose
682 # algorithm that works for all data types.
683 args = _separate_args.findall(args)
686 result.append(self.conv(self.expand(a, lvars)))
688 result = string.join(result, '')
694 return self.expand(args, lvars)
697 conv = _strconv[mode]
699 # Doing this every time is a bit of a waste, since the Executor
700 # has typically already populated the OverrideEnvironment with
701 # $TARGET/$SOURCE variables. We're keeping this (for now), though,
702 # because it supports existing behavior that allows us to call
703 # an Action directly with an arbitrary target+source pair, which
704 # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
705 # If we dropped that behavior (or found another way to cover it),
706 # we could get rid of this call completely and just rely on the
707 # Executor setting the variables.
708 d = subst_dict(target, source)
713 # We're (most likely) going to eval() things. If Python doesn't
714 # find a __builtin__ value in the global dictionary used for eval(),
715 # it copies the current __builtin__ values for you. Avoid this by
716 # setting it explicitly and then deleting, so we don't pollute the
717 # construction environment Dictionary(ies) that are typically used
719 gvars['__builtin__'] = __builtin__
721 ss = StringSubber(env, mode, target, source, conv, gvars)
722 result = ss.substitute(strSubst, lvars)
725 del gvars['__builtin__']
729 if is_String(result):
730 # Remove $(-$) pairs and any stuff in between,
731 # if that's appropriate.
732 remove = _regex_remove[mode]
734 result = remove.sub('', result)
735 if mode != SUBST_RAW:
736 # Compress strings of white space characters into
738 result = string.strip(_space_sep.sub(' ', result))
742 def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
743 """Substitute construction variables in a string (or list or other
744 object) and separate the arguments into a command list.
746 The companion scons_subst() function (above) handles basic
747 substitutions within strings, so see that function instead
748 if that's what you're looking for.
750 class ListSubber(UserList.UserList):
751 """A class to construct the results of a scons_subst_list() call.
753 Like StringSubber, this class binds a specific construction
754 environment, mode, target and source with two methods
755 (substitute() and expand()) that handle the expansion.
757 In addition, however, this class is used to track the state of
758 the result(s) we're gathering so we can do the appropriate thing
759 whenever we have to append another word to the result--start a new
760 line, start a new word, append to the current word, etc. We do
761 this by setting the "append" attribute to the right method so
762 that our wrapper methods only need ever call ListSubber.append(),
763 and the rest of the object takes care of doing the right thing
766 def __init__(self, env, mode, target, source, conv, gvars):
767 UserList.UserList.__init__(self, [])
775 if self.mode == SUBST_RAW:
776 self.add_strip = lambda x, s=self: s.append(x)
778 self.add_strip = lambda x, s=self: None
782 def expand(self, s, lvars, within_list):
783 """Expand a single "token" as necessary, appending the
784 expansion to the current result.
786 This handles expanding different types of things (strings,
787 lists, callables) appropriately. It calls the wrapper
788 substitute() method to re-expand things as necessary, so that
789 the results of expansions of side-by-side strings still get
790 re-evaluated separately, not smushed together.
796 except (IndexError, ValueError):
803 self.open_strip('$(')
805 self.close_strip('$)')
811 s = eval(key, self.gvars, lvars)
812 except (IndexError, NameError, TypeError):
814 except SyntaxError,e:
816 raise SCons.Errors.BuildError, (self.target[0], "Syntax error `%s' trying to evaluate `%s'" % (e,s))
818 raise SCons.Errors.UserError, "Syntax error `%s' trying to evaluate `%s'" % (e,s)
820 # Before re-expanding the result, handle
821 # recursive expansion by copying the local
822 # variable dictionary and overwriting a null
823 # string for the value of the variable name
826 var = string.split(key, '.')[0]
828 self.substitute(s, lv, 0)
834 self.substitute(a, lvars, 1)
838 s = s(target=self.target,
841 for_signature=(self.mode != SUBST_CMD))
843 # This probably indicates that it's a callable
844 # object that doesn't match our calling arguments
847 self.substitute(s, lvars, within_list)
853 def substitute(self, args, lvars, within_list):
854 """Substitute expansions in an argument or list of arguments.
856 This serves as a wrapper for splitting up a string into
860 if is_String(args) and not isinstance(args, CmdStringHolder):
861 args = _separate_args.findall(args)
863 if a[0] in ' \t\n\r\f\v':
871 self.expand(a, lvars, within_list)
873 self.expand(args, lvars, within_list)
876 """Arrange for the next word to start a new line. This
877 is like starting a new word, except that we have to append
878 another line to the result."""
879 UserList.UserList.append(self, [])
883 """Arrange for the next word to append to the end of the
884 current last word in the result."""
885 self.append = self.add_to_current_word
888 """Arrange for the next word to start a new word."""
889 self.append = self.add_new_word
891 def add_to_current_word(self, x):
892 """Append the string x to the end of the current last word
893 in the result. If that is not possible, then just add
894 it as a new word. Make sure the entire concatenated string
895 inherits the object attributes of x (in particular, the
896 escape function) by wrapping it as CmdStringHolder."""
898 if not self.in_strip or self.mode != SUBST_SIG:
900 current_word = self[-1][-1]
904 # All right, this is a hack and it should probably
905 # be refactored out of existence in the future.
906 # The issue is that we want to smoosh words together
907 # and make one file name that gets escaped if
908 # we're expanding something like foo$EXTENSION,
909 # but we don't want to smoosh them together if
910 # it's something like >$TARGET, because then we'll
911 # treat the '>' like it's part of the file name.
912 # So for now, just hard-code looking for the special
913 # command-line redirection characters...
915 last_char = str(current_word)[-1]
918 if last_char in '<>|':
922 literal1 = self.literal(self[-1][-1])
923 literal2 = self.literal(x)
926 y = CmdStringHolder(y, literal1 or literal2)
929 def add_new_word(self, x):
930 if not self.in_strip or self.mode != SUBST_SIG:
931 literal = self.literal(x)
934 x = CmdStringHolder(x, literal)
936 self.append = self.add_to_current_word
938 def literal(self, x):
941 except AttributeError:
946 def open_strip(self, x):
947 """Handle the "open strip" $( token."""
951 def close_strip(self, x):
952 """Handle the "close strip" $) token."""
957 conv = _strconv[mode]
959 # Doing this every time is a bit of a waste, since the Executor
960 # has typically already populated the OverrideEnvironment with
961 # $TARGET/$SOURCE variables. We're keeping this (for now), though,
962 # because it supports existing behavior that allows us to call
963 # an Action directly with an arbitrary target+source pair, which
964 # we use in Tool/tex.py to handle calling $BIBTEX when necessary.
965 # If we dropped that behavior (or found another way to cover it),
966 # we could get rid of this call completely and just rely on the
967 # Executor setting the variables.
968 d = subst_dict(target, source)
973 # We're (most likely) going to eval() things. If Python doesn't
974 # find a __builtin__ value in the global dictionary used for eval(),
975 # it copies the current __builtin__ values for you. Avoid this by
976 # setting it explicitly and then deleting, so we don't pollute the
977 # construction environment Dictionary(ies) that are typically used
979 gvars['__builtins__'] = __builtins__
981 ls = ListSubber(env, mode, target, source, conv, gvars)
982 ls.substitute(strSubst, lvars, 0)
985 del gvars['__builtins__']
991 def scons_subst_once(strSubst, env, key):
992 """Perform single (non-recursive) substitution of a single
993 construction variable keyword.
995 This is used when setting a variable when copying or overriding values
996 in an Environment. We want to capture (expand) the old value before
997 we override it, so people can do things like:
999 env2 = env.Copy(CCFLAGS = '$CCFLAGS -g')
1001 We do this with some straightforward, brute-force code here...
1003 if type(strSubst) == types.StringType and string.find(strSubst, '$') < 0:
1006 matchlist = ['$' + key, '${' + key + '}']
1007 val = env.get(key, '')
1008 def sub_match(match, val=val, matchlist=matchlist):
1013 return string.join(map(str, a))
1017 if is_List(strSubst):
1019 for arg in strSubst:
1021 if arg in matchlist:
1028 result.append(_dollar_exps.sub(sub_match, arg))
1032 elif is_String(strSubst):
1033 return _dollar_exps.sub(sub_match, strSubst)
1037 def render_tree(root, child_func, prune=0, margin=[0], visited={}):
1039 Render a tree of nodes into an ASCII tree view.
1040 root - the root node of the tree
1041 child_func - the function called to get the children of a node
1042 prune - don't visit the same node twice
1043 margin - the format of the left margin to use for children of root.
1044 1 results in a pipe, and 0 results in no pipe.
1045 visited - a dictionary of visited nodes in the current branch if not prune,
1046 or in the whole tree if prune.
1051 if visited.has_key(rname):
1054 children = child_func(root)
1056 for pipe in margin[:-1]:
1058 retval = retval + "| "
1060 retval = retval + " "
1062 retval = retval + "+-" + rname + "\n"
1064 visited = copy.copy(visited)
1067 for i in range(len(children)):
1068 margin.append(i<len(children)-1)
1069 retval = retval + render_tree(children[i], child_func, prune, margin, visited
1075 IDX = lambda N: N and 1 or 0
1077 def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
1079 Print a tree of nodes. This is like render_tree, except it prints
1080 lines directly instead of creating a string representation in memory,
1081 so that huge trees can be printed.
1083 root - the root node of the tree
1084 child_func - the function called to get the children of a node
1085 prune - don't visit the same node twice
1086 showtags - print status information to the left of each node line
1087 margin - the format of the left margin to use for children of root.
1088 1 results in a pipe, and 0 results in no pipe.
1089 visited - a dictionary of visited nodes in the current branch if not prune,
1090 or in the whole tree if prune.
1095 if visited.has_key(rname):
1102 print ' R = exists in repository only'
1103 print ' b = implicit builder'
1104 print ' B = explicit builder'
1105 print ' S = side effect'
1106 print ' P = precious'
1107 print ' A = always build'
1108 print ' C = current'
1112 tags.append(' E'[IDX(root.exists())])
1113 tags.append(' R'[IDX(root.rexists() and not root.exists())])
1114 tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
1115 [0,2][IDX(root.has_builder())]])
1116 tags.append(' S'[IDX(root.side_effect)])
1117 tags.append(' P'[IDX(root.precious)])
1118 tags.append(' A'[IDX(root.always_build)])
1119 tags.append(' C'[IDX(root.current())])
1126 return [" ","| "][m]
1127 margins = map(MMM, margin[:-1])
1129 print string.join(tags + margins + ['+-', rname], '')
1134 children = child_func(root)
1137 map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
1138 print_tree(C, cf, p, i, m, v),
1141 print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
1145 return type(e) is types.DictType or isinstance(e, UserDict)
1148 return type(e) is types.ListType or isinstance(e, UserList.UserList)
1150 if hasattr(types, 'UnicodeType'):
1152 return type(e) is types.StringType \
1153 or type(e) is types.UnicodeType \
1154 or isinstance(e, UserString)
1157 return type(e) is types.StringType or isinstance(e, UserString)
1160 return is_String(e) or not is_List(e)
1162 def flatten(sequence, scalarp=is_Scalar, result=None):
1165 for item in sequence:
1169 flatten(item, scalarp, result)
1173 """A simple generic Proxy class, forwarding all calls to
1174 subject. So, for the benefit of the python newbie, what does
1175 this really mean? Well, it means that you can take an object, let's
1176 call it 'objA', and wrap it in this Proxy class, with a statement
1179 proxyObj = Proxy(objA),
1181 Then, if in the future, you do something like this
1185 since Proxy does not have a 'var1' attribute (but presumably objA does),
1186 the request actually is equivalent to saying
1190 Inherit from this class to create a Proxy."""
1192 def __init__(self, subject):
1193 """Wrap an object as a Proxy object"""
1194 self.__subject = subject
1196 def __getattr__(self, name):
1197 """Retrieve an attribute from the wrapped object. If the named
1198 attribute doesn't exist, AttributeError is raised"""
1199 return getattr(self.__subject, name)
1202 """Retrieve the entire wrapped object"""
1203 return self.__subject
1205 def __cmp__(self, other):
1206 if issubclass(other.__class__, self.__subject.__class__):
1207 return cmp(self.__subject, other)
1208 return cmp(self.__dict__, other.__dict__)
1210 # attempt to load the windows registry module:
1218 RegOpenKeyEx = _winreg.OpenKeyEx
1219 RegEnumKey = _winreg.EnumKey
1220 RegEnumValue = _winreg.EnumValue
1221 RegQueryValueEx = _winreg.QueryValueEx
1222 RegError = _winreg.error
1231 RegOpenKeyEx = win32api.RegOpenKeyEx
1232 RegEnumKey = win32api.RegEnumKey
1233 RegEnumValue = win32api.RegEnumValue
1234 RegQueryValueEx = win32api.RegQueryValueEx
1235 RegError = win32api.error
1238 class _NoError(Exception):
1243 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
1244 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
1245 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
1246 HKEY_USERS = hkey_mod.HKEY_USERS
1248 def RegGetValue(root, key):
1249 """This utility function returns a value in the registry
1250 without having to open the key first. Only available on
1251 Windows platforms with a version of Python that can read the
1252 registry. Returns the same thing as
1253 SCons.Util.RegQueryValueEx, except you just specify the entire
1254 path to the value, and don't have to bother opening the key
1258 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1259 r'SOFTWARE\Microsoft\Windows\CurrentVersion')
1260 out = SCons.Util.RegQueryValueEx(k,
1264 out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1265 r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
1267 # I would use os.path.split here, but it's not a filesystem
1269 p = key.rfind('\\') + 1
1272 k = SCons.Util.RegOpenKeyEx(root, keyp)
1273 return SCons.Util.RegQueryValueEx(k,val)
1275 if sys.platform == 'win32':
1278 def __call__(self, file, path=None, pathext=None, reject=[]):
1282 path = os.environ['PATH']
1286 path = string.split(path, os.pathsep)
1289 pathext = os.environ['PATHEXT']
1291 pathext = '.COM;.EXE;.BAT;.CMD'
1292 if is_String(pathext):
1293 pathext = string.split(pathext, os.pathsep)
1295 if string.lower(ext) == string.lower(file[-len(ext):]):
1298 if not is_List(reject):
1301 f = os.path.join(dir, file)
1304 if os.path.isfile(fext):
1308 return os.path.normpath(fext)
1312 elif os.name == 'os2':
1315 def __call__(self, file, path=None, pathext=None, reject=[]):
1319 path = os.environ['PATH']
1323 path = string.split(path, os.pathsep)
1325 pathext = ['.exe', '.cmd']
1327 if string.lower(ext) == string.lower(file[-len(ext):]):
1330 if not is_List(reject):
1333 f = os.path.join(dir, file)
1336 if os.path.isfile(fext):
1340 return os.path.normpath(fext)
1347 def __call__(self, file, path=None, pathext=None, reject=[]):
1351 path = os.environ['PATH']
1355 path = string.split(path, os.pathsep)
1356 if not is_List(reject):
1359 f = os.path.join(d, file)
1360 if os.path.isfile(f):
1365 if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
1369 return os.path.normpath(f)
1373 WhereIs = _WhereIs()
1375 def PrependPath(oldpath, newpath, sep = os.pathsep):
1376 """This prepends newpath elements to the given oldpath. Will only
1377 add any particular path once (leaving the first one it encounters
1378 and ignoring the rest, to preserve path order), and will
1379 os.path.normpath and os.path.normcase all paths to help assure
1380 this. This can also handle the case where the given old path
1381 variable is a list instead of a string, in which case a list will
1382 be returned instead of a string.
1385 Old Path: "/foo/bar:/foo"
1386 New Path: "/biz/boom:/foo"
1387 Result: "/biz/boom:/foo:/foo/bar"
1393 if not is_List(orig):
1394 paths = string.split(paths, sep)
1397 if is_List(newpath):
1400 newpaths = string.split(newpath, sep)
1402 newpaths = newpaths + paths # prepend new paths
1406 # now we add them only if they are unique
1407 for path in newpaths:
1408 normpath = os.path.normpath(os.path.normcase(path))
1409 if path and not normpath in normpaths:
1411 normpaths.append(normpath)
1416 return string.join(paths, sep)
1418 def AppendPath(oldpath, newpath, sep = os.pathsep):
1419 """This appends new path elements to the given old path. Will
1420 only add any particular path once (leaving the last one it
1421 encounters and ignoring the rest, to preserve path order), and
1422 will os.path.normpath and os.path.normcase all paths to help
1423 assure this. This can also handle the case where the given old
1424 path variable is a list instead of a string, in which case a list
1425 will be returned instead of a string.
1428 Old Path: "/foo/bar:/foo"
1429 New Path: "/biz/boom:/foo"
1430 Result: "/foo/bar:/biz/boom:/foo"
1436 if not is_List(orig):
1437 paths = string.split(paths, sep)
1440 if is_List(newpath):
1443 newpaths = string.split(newpath, sep)
1445 newpaths = paths + newpaths # append new paths
1450 # now we add them only of they are unique
1451 for path in newpaths:
1452 normpath = os.path.normpath(os.path.normcase(path))
1453 if path and not normpath in normpaths:
1455 normpaths.append(normpath)
1462 return string.join(paths, sep)
1465 def dir_index(directory):
1467 for f in os.listdir(directory):
1468 fullname = os.path.join(directory, f)
1469 files.append(fullname)
1471 # os.listdir() isn't guaranteed to return files in any specific order,
1472 # but some of the test code expects sorted output.
1476 def fs_delete(path, remove=1):
1478 if os.path.exists(path):
1479 if os.path.isfile(path):
1480 if remove: os.unlink(path)
1481 display("Removed " + path)
1482 elif os.path.isdir(path) and not os.path.islink(path):
1483 # delete everything in the dir
1484 for p in dir_index(path):
1485 if os.path.isfile(p):
1486 if remove: os.unlink(p)
1487 display("Removed " + p)
1489 fs_delete(p, remove)
1490 # then delete dir itself
1491 if remove: os.rmdir(path)
1492 display("Removed directory " + path)
1494 print "scons: Could not remove '%s':" % str(path), e.strerror
1496 if sys.platform == 'cygwin':
1497 def get_native_path(path):
1498 """Transforms an absolute path into a native path for the system. In
1499 Cygwin, this converts from a Cygwin path to a Win32 one."""
1500 return string.replace(os.popen('cygpath -w ' + path).read(), '\n', '')
1502 def get_native_path(path):
1503 """Transforms an absolute path into a native path for the system.
1504 Non-Cygwin version, just leave the path alone."""
1507 display = DisplayEngine()
1512 elif is_String(arg):
1513 return string.split(arg)
1517 class CLVar(UserList.UserList):
1518 """A class for command-line construction variables.
1520 This is a list that uses Split() to split an initial string along
1521 white-space arguments, and similarly to split any strings that get
1522 added. This allows us to Do the Right Thing with Append() and
1523 Prepend() (as well as straight Python foo = env['VAR'] + 'arg1
1524 arg2') regardless of whether a user adds a list or a string to a
1525 command-line construction variable.
1527 def __init__(self, seq = []):
1528 UserList.UserList.__init__(self, Split(seq))
1529 def __coerce__(self, other):
1530 return (self, CLVar(other))
1532 return string.join(self.data)
1534 # A dictionary that preserves the order in which items are added.
1535 # Submitted by David Benjamin to ActiveState's Python Cookbook web site:
1536 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
1537 # Including fixes/enhancements from the follow-on discussions.
1538 class OrderedDict(UserDict):
1539 def __init__(self, dict = None):
1541 UserDict.__init__(self, dict)
1543 def __delitem__(self, key):
1544 UserDict.__delitem__(self, key)
1545 self._keys.remove(key)
1547 def __setitem__(self, key, item):
1548 UserDict.__setitem__(self, key, item)
1549 if key not in self._keys: self._keys.append(key)
1552 UserDict.clear(self)
1556 dict = OrderedDict()
1561 return zip(self._keys, self.values())
1564 return self._keys[:]
1568 key = self._keys[-1]
1570 raise KeyError('dictionary is empty')
1577 def setdefault(self, key, failobj = None):
1578 UserDict.setdefault(self, key, failobj)
1579 if key not in self._keys: self._keys.append(key)
1581 def update(self, dict):
1582 for (key, val) in dict.items():
1583 self.__setitem__(key, val)
1586 return map(self.get, self._keys)
1588 class Selector(OrderedDict):
1589 """A callable ordered dictionary that maps file suffixes to
1590 dictionary values. We preserve the order in which items are added
1591 so that get_suffix() calls always return the first suffix added."""
1592 def __call__(self, env, source):
1594 ext = splitext(str(source[0]))[1]
1600 # Try to perform Environment substitution on the keys of
1601 # the dictionary before giving up.
1603 for (k,v) in self.items():
1606 if s_dict.has_key(s_k):
1607 # We only raise an error when variables point
1608 # to the same suffix. If one suffix is literal
1609 # and a variable suffix contains this literal,
1610 # the literal wins and we don't raise an error.
1611 raise KeyError, (s_dict[s_k][0], k, s_k)
1614 return s_dict[ext][1]
1622 if sys.platform == 'cygwin':
1623 # On Cygwin, os.path.normcase() lies, so just report back the
1624 # fact that the underlying Win32 OS is case-insensitive.
1625 def case_sensitive_suffixes(s1, s2):
1628 def case_sensitive_suffixes(s1, s2):
1629 return (os.path.normcase(s1) != os.path.normcase(s2))
1631 def adjustixes(fname, pre, suf):
1633 path, fn = os.path.split(os.path.normpath(fname))
1634 if fn[:len(pre)] != pre:
1635 fname = os.path.join(path, pre + fn)
1636 # Only append a suffix if the file does not have one.
1637 if suf and not splitext(fname)[1] and fname[-len(suf):] != suf:
1643 """Return a list of the elements in s, but without duplicates.
1645 For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3],
1646 unique("abcabc") some permutation of ["a", "b", "c"], and
1647 unique(([1, 2], [2, 3], [1, 2])) some permutation of
1650 For best speed, all sequence elements should be hashable. Then
1651 unique() will usually work in linear time.
1653 If not possible, the sequence elements should enjoy a total
1654 ordering, and if list(s).sort() doesn't raise TypeError it's
1655 assumed that they do enjoy a total ordering. Then unique() will
1656 usually work in O(N*log2(N)) time.
1658 If that's not possible either, the sequence elements must support
1659 equality-testing. Then unique() will usually work in quadratic
1667 # Try using a dict first, as that's the fastest and will usually
1668 # work. If it doesn't work, it will usually fail quickly, so it
1669 # usually doesn't cost much to *try* it. It requires that all the
1670 # sequence elements be hashable, and support equality comparison.
1676 del u # move on to the next method
1680 # We can't hash all the elements. Second fastest is to sort,
1681 # which brings the equal elements together; then duplicates are
1682 # easy to weed out in a single pass.
1683 # NOTE: Python's list.sort() was designed to be efficient in the
1684 # presence of many duplicate elements. This isn't true of all
1685 # sort functions in all languages or libraries, so this approach
1686 # is more effective in Python than it may be elsewhere.
1691 del t # move on to the next method
1698 t[lasti] = last = t[i]
1703 # Brute force is all that's left.
1710 # Much of the logic here was originally based on recipe 4.9 from the
1711 # Python CookBook, but we had to dumb it way down for Python 1.5.2.
1714 def __init__(self, fileobj):
1715 self.fileobj = fileobj
1720 line = self.fileobj.readline()
1723 if line[-2:] == '\\\n':
1724 result.append(line[:-2])
1728 return string.join(result, '')
1730 def readlines(self):
1733 line = self.readline()