Save memory by allowing Nodes to clean up their Executor's build environments after...
[scons.git] / src / engine / SCons / Node / __init__.py
1 """SCons.Node
2
3 The Node package for the SCons software construction utility.
4
5 This is, in many ways, the heart of SCons.
6
7 A Node is where we encapsulate all of the dependency information about
8 any thing that SCons can build, or about any thing which SCons can use
9 to build some other thing.  The canonical "thing," of course, is a file,
10 but a Node can also represent something remote (like a web page) or
11 something completely abstract (like an Alias).
12
13 Each specific type of "thing" is specifically represented by a subclass
14 of the Node base class:  Node.FS.File for files, Node.Alias for aliases,
15 etc.  Dependency information is kept here in the base class, and
16 information specific to files/aliases/etc. is in the subclass.  The
17 goal, if we've done this correctly, is that any type of "thing" should
18 be able to depend on any other type of "thing."
19
20 """
21
22 #
23 # __COPYRIGHT__
24 #
25 # Permission is hereby granted, free of charge, to any person obtaining
26 # a copy of this software and associated documentation files (the
27 # "Software"), to deal in the Software without restriction, including
28 # without limitation the rights to use, copy, modify, merge, publish,
29 # distribute, sublicense, and/or sell copies of the Software, and to
30 # permit persons to whom the Software is furnished to do so, subject to
31 # the following conditions:
32 #
33 # The above copyright notice and this permission notice shall be included
34 # in all copies or substantial portions of the Software.
35 #
36 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
37 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
38 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
39 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
40 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
41 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
42 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 #
44
45 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
46
47
48
49 import copy
50
51 from SCons.Debug import logInstanceCreation
52 import SCons.Sig
53 import SCons.Util
54
55 # Node states
56 #
57 # These are in "priority" order, so that the maximum value for any
58 # child/dependency of a node represents the state of that node if
59 # it has no builder of its own.  The canonical example is a file
60 # system directory, which is only up to date if all of its children
61 # were up to date.
62 pending = 1
63 executing = 2
64 up_to_date = 3
65 executed = 4
66 failed = 5
67 stack = 6 # nodes that are in the current Taskmaster execution stack
68
69 # controls whether implicit depedencies are cached:
70 implicit_cache = 0
71
72 # controls whether implicit dep changes are ignored:
73 implicit_deps_unchanged = 0
74
75 # controls whether the cached implicit deps are ignored:
76 implicit_deps_changed = 0
77
78 # A variable that can be set to an interface-specific function be called
79 # to annotate a Node with information about its creation.
80 def do_nothing(node): pass
81
82 Annotate = do_nothing
83
84 class Node:
85     """The base Node class, for entities that we know how to
86     build, or use to build other Nodes.
87     """
88
89     class Attrs:
90         pass
91
92     def __init__(self):
93         if __debug__: logInstanceCreation(self, 'Node')
94         # Note that we no longer explicitly initialize a self.builder
95         # attribute to None here.  That's because the self.builder
96         # attribute may be created on-the-fly later by a subclass (the
97         # canonical example being a builder to fetch a file from a
98         # source code system like CVS or Subversion).
99
100         # Each list of children that we maintain is accompanied by a
101         # dictionary used to look up quickly whether a node is already
102         # present in the list.  Empirical tests showed that it was
103         # fastest to maintain them as side-by-side Node attributes in
104         # this way, instead of wrapping up each list+dictionary pair in
105         # a class.  (Of course, we could always still do that in the
106         # future if we had a good reason to...).
107         self.sources = []       # source files used to build node
108         self.sources_dict = {}
109         self.depends = []       # explicit dependencies (from Depends)
110         self.depends_dict = {}
111         self.ignore = []        # dependencies to ignore
112         self.ignore_dict = {}
113         self.implicit = None    # implicit (scanned) dependencies (None means not scanned yet)
114         self.parents = {}
115         self.wkids = None       # Kids yet to walk, when it's an array
116         self.target_scanner = None      # explicit scanner from this node's Builder
117         self.source_scanner = None      # source scanner
118
119         self.env = None
120         self.state = None
121         self.precious = None
122         self.always_build = None
123         self.found_includes = {}
124         self.includes = None
125         self.overrides = {}     # construction variable overrides for building this node
126         self.attributes = self.Attrs() # Generic place to stick information about the Node.
127         self.side_effect = 0 # true iff this node is a side effect
128         self.side_effects = [] # the side effects of building this target
129         self.pre_actions = []
130         self.post_actions = []
131         self.linked = 0 # is this node linked to the build directory? 
132
133         # Let the interface in which the build engine is embedded
134         # annotate this Node with its own info (like a description of
135         # what line in what file created the node, for example).
136         Annotate(self)
137
138     def generate_build_dict(self):
139         """Return an appropriate dictionary of values for building
140         this Node."""
141         return {}
142
143     def get_build_env(self):
144         """Fetch the appropriate Environment to build this node."""
145         executor = self.get_executor()
146         return executor.get_build_env()
147
148     def set_executor(self, executor):
149         """Set the action executor for this node."""
150         self.executor = executor
151
152     def get_executor(self, create=1):
153         """Fetch the action executor for this node.  Create one if
154         there isn't already one, and requested to do so."""
155         try:
156             executor = self.executor
157         except AttributeError:
158             if not create:
159                 raise
160             import SCons.Executor
161             executor = SCons.Executor.Executor(self.builder,
162                                                self.builder.env,
163                                                {},
164                                                [self],
165                                                self.sources)
166             self.executor = executor
167         return executor
168
169     def _for_each_action(self, func):
170         """Call a function for each action required to build a node.
171
172         The purpose here is to have one place for the logic that
173         collects and executes all of the actions for a node's builder,
174         even though multiple sections of code elsewhere need this logic
175         to do different things."""
176         if not self.has_builder():
177             return
178         executor = self.get_executor()
179         executor(self, func)
180
181     def retrieve_from_cache(self):
182         """Try to retrieve the node's content from a cache
183
184         This method is called from multiple threads in a parallel build,
185         so only do thread safe stuff here. Do thread unsafe stuff in
186         built().
187
188         Returns true iff the node was successfully retrieved.
189         """
190         return 0
191         
192     def build(self):
193         """Actually build the node.
194
195         This method is called from multiple threads in a parallel build,
196         so only do thread safe stuff here. Do thread unsafe stuff in
197         built().
198         """
199         def do_action(action, targets, sources, env, s=self):
200             stat = action(targets, sources, env)
201             if stat:
202                 raise SCons.Errors.BuildError(node = s,
203                                               errstr = "Error %d" % stat)
204         self._for_each_action(do_action)
205
206     def built(self):
207         """Called just after this node is sucessfully built."""
208         self.store_bsig()
209
210         # Clear out the implicit dependency caches:
211         # XXX this really should somehow be made more general and put
212         #     under the control of the scanners.
213         if self.source_scanner:
214             self.found_includes = {}
215             self.includes = None
216
217             def get_parents(node, parent): return node.get_parents()
218             def clear_cache(node, parent):
219                 node.implicit = None
220                 node.del_bsig()
221             w = Walker(self, get_parents, ignore_cycle, clear_cache)
222             while w.next(): pass
223
224         # clear out the content signature, since the contents of this
225         # node were presumably just changed:
226         self.del_csig()
227
228     def postprocess(self):
229         """Clean up anything we don't need to hang onto after we've
230         been built."""
231         try:
232             executor = self.get_executor(create=None)
233         except AttributeError:
234             pass
235         else:
236             executor.cleanup()
237
238     def clear(self):
239         """Completely clear a Node of all its cached state (so that it
240         can be re-evaluated by interfaces that do continuous integration
241         builds).
242         """
243         self.set_state(None)
244         self.del_bsig()
245         self.del_csig()
246         try:
247             delattr(self, '_calculated_sig')
248         except AttributeError:
249             pass
250         try:
251             delattr(self, '_tempbsig')
252         except AttributeError:
253             pass
254         self.includes = None
255         self.found_includes = {}
256         self.implicit = None
257
258     def visited(self):
259         """Called just after this node has been visited
260         without requiring a build.."""
261         pass
262
263     def depends_on(self, nodes):
264         """Does this node depend on any of 'nodes'?"""
265         for node in nodes:
266             if node in self.children():
267                 return 1
268
269         return 0
270
271     def builder_set(self, builder):
272         self.builder = builder
273
274     def has_builder(self):
275         """Return whether this Node has a builder or not.
276
277         In Boolean tests, this turns out to be a *lot* more efficient
278         than simply examining the builder attribute directly ("if
279         node.builder: ..."). When the builder attribute is examined
280         directly, it ends up calling __getattr__ for both the __len__
281         and __nonzero__ attributes on instances of our Builder Proxy
282         class(es), generating a bazillion extra calls and slowing
283         things down immensely.
284         """
285         try:
286             b = self.builder
287         except AttributeError:
288             # There was no explicit builder for this Node, so initialize
289             # the self.builder attribute to None now.
290             self.builder = None
291             b = self.builder
292         return not b is None
293
294     def is_derived(self):
295         """
296         Returns true iff this node is derived (i.e. built).
297
298         This should return true only for nodes whose path should be in
299         the build directory when duplicate=0 and should contribute their build
300         signatures when they are used as source files to other derived files. For
301         example: source with source builders are not derived in this sense,
302         and hence should not return true.
303         """
304         return self.has_builder() or self.side_effect
305
306     def is_pseudo_derived(self):
307         """
308         Returns true iff this node is built, but should use a source path
309         when duplicate=0 and should contribute a content signature (i.e.
310         source signature) when used as a source for other derived files.
311         """
312         return 0
313
314     def alter_targets(self):
315         """Return a list of alternate targets for this Node.
316         """
317         return [], None
318
319     def get_found_includes(self, env, scanner, target):
320         """Return the scanned include lines (implicit dependencies)
321         found in this node.
322
323         The default is no implicit dependencies.  We expect this method
324         to be overridden by any subclass that can be scanned for
325         implicit dependencies.
326         """
327         return []
328
329     def get_implicit_deps(self, env, scanner, target):
330         """Return a list of implicit dependencies for this node.
331
332         This method exists to handle recursive invocation of the scanner
333         on the implicit dependencies returned by the scanner, if the
334         scanner's recursive flag says that we should.
335         """
336         if not scanner:
337             return []
338
339         try:
340             recurse = scanner.recursive
341         except AttributeError:
342             recurse = None
343
344         nodes = [self]
345         seen = {}
346         seen[self] = 1
347         deps = []
348         while nodes:
349            n = nodes.pop(0)
350            d = filter(lambda x, seen=seen: not seen.has_key(x),
351                       n.get_found_includes(env, scanner, target))
352            if d:
353                deps.extend(d)
354                for n in d:
355                    seen[n] = 1
356                if recurse:
357                    nodes.extend(d)
358
359         return deps
360
361     # cache used to make implicit_factory fast.
362     implicit_factory_cache = {}
363     
364     def implicit_factory(self, path):
365         """
366         Turn a cache implicit dependency path into a node.
367         This is called so many times that doing caching
368         here is a significant perforamnce boost.
369         """
370         try:
371             return self.implicit_factory_cache[path]
372         except KeyError:
373             n = self.builder.source_factory(path)
374             self.implicit_factory_cache[path] = n
375             return n
376
377     def scan(self):
378         """Scan this node's dependents for implicit dependencies."""
379         # Don't bother scanning non-derived files, because we don't
380         # care what their dependencies are.
381         # Don't scan again, if we already have scanned.
382         if not self.implicit is None:
383             return
384         self.implicit = []
385         self.implicit_dict = {}
386         self._children_reset()
387         if not self.has_builder():
388             return
389
390         if implicit_cache and not implicit_deps_changed:
391             implicit = self.get_stored_implicit()
392             if implicit is not None:
393                 implicit = map(self.implicit_factory, implicit)
394                 self._add_child(self.implicit, self.implicit_dict, implicit)
395                 calc = SCons.Sig.default_calc
396                 if implicit_deps_unchanged or calc.current(self, calc.bsig(self)):
397                     return
398                 else:
399                     # one of this node's sources has changed, so
400                     # we need to recalculate the implicit deps,
401                     # and the bsig:
402                     self.implicit = []
403                     self.implicit_dict = {}
404                     self._children_reset()
405                     self.del_bsig()
406
407         build_env = self.get_build_env()
408
409         for child in self.children(scan=0):
410             scanner = child.source_scanner
411             if scanner:
412                 self._add_child(self.implicit,
413                                 self.implicit_dict,
414                                 child.get_implicit_deps(build_env,
415                                                         scanner,
416                                                         self))
417
418         # scan this node itself for implicit dependencies
419         self._add_child(self.implicit,
420                         self.implicit_dict,
421                         self.get_implicit_deps(build_env,
422                                                self.target_scanner,
423                                                self))
424
425         if implicit_cache:
426             self.store_implicit()
427
428     def scanner_key(self):
429         return None
430
431     def env_set(self, env, safe=0):
432         if safe and self.env:
433             return
434         self.env = env
435
436     def calculator(self):
437         import SCons.Defaults
438         
439         env = self.env or SCons.Defaults.DefaultEnvironment()
440         return env.get_calculator()
441
442     def calc_signature(self, calc):
443         """
444         Select and calculate the appropriate build signature for a node.
445
446         self - the node
447         calc - the signature calculation module
448         returns - the signature
449         """
450         try:
451             return self._calculated_sig
452         except AttributeError:
453             if self.is_derived():
454                 import SCons.Defaults
455                 
456                 env = self.env or SCons.Defaults.DefaultEnvironment()
457                 if env.use_build_signature():
458                     sig = self.rfile().calc_bsig(calc, self)
459                 else:
460                     sig = self.rfile().calc_csig(calc, self)
461             elif not self.rexists():
462                 sig = None
463             else:
464                 sig = self.rfile().calc_csig(calc, self)
465             self._calculated_sig = sig
466             return sig
467
468     def calc_bsig(self, calc, cache=None):
469         """Return the node's build signature, calculating it first
470         if necessary.
471
472         Note that we don't save it in the "real" build signature
473         attribute if we have to calculate it here; the "real" build
474         signature only gets updated after a file is actually built.
475         """
476         if cache is None: cache = self
477         try:
478             return cache.bsig
479         except AttributeError:
480             try:
481                 return cache._tempbsig
482             except AttributeError:
483                 cache._tempbsig = calc.bsig(self, cache)
484                 return cache._tempbsig
485
486     def get_bsig(self):
487         """Get the node's build signature (based on the signatures
488         of its dependency files and build information)."""
489         try:
490             return self.bsig
491         except AttributeError:
492             return None
493
494     def set_bsig(self, bsig):
495         """Set the node's build signature (based on the signatures
496         of its dependency files and build information)."""
497         self.bsig = bsig
498         try:
499             delattr(self, '_tempbsig')
500         except AttributeError:
501             pass
502
503     def store_bsig(self):
504         """Make the build signature permanent (that is, store it in the
505         .sconsign file or equivalent)."""
506         pass
507
508     def del_bsig(self):
509         """Delete the bsig from this node."""
510         try:
511             delattr(self, 'bsig')
512         except AttributeError:
513             pass
514
515     def get_csig(self):
516         """Get the signature of the node's content."""
517         try:
518             return self.csig
519         except AttributeError:
520             return None
521
522     def calc_csig(self, calc, cache=None):
523         """Return the node's content signature, calculating it first
524         if necessary.
525         """
526         if cache is None: cache = self
527         try:
528             return cache.csig
529         except AttributeError:
530             cache.csig = calc.csig(self, cache)
531             return cache.csig
532
533     def set_csig(self, csig):
534         """Set the signature of the node's content."""
535         self.csig = csig
536
537     def store_csig(self):
538         """Make the content signature permanent (that is, store it in the
539         .sconsign file or equivalent)."""
540         pass
541
542     def del_csig(self):
543         """Delete the csig from this node."""
544         try:
545             delattr(self, 'csig')
546         except AttributeError:
547             pass
548
549     def get_prevsiginfo(self):
550         """Fetch the previous signature information from the
551         .sconsign entry."""
552         return SCons.Sig._SConsign.null_siginfo
553
554     def get_timestamp(self):
555         return 0
556
557     def store_timestamp(self):
558         """Make the timestamp permanent (that is, store it in the
559         .sconsign file or equivalent)."""
560         pass
561
562     def store_implicit(self):
563         """Make the implicit deps permanent (that is, store them in the
564         .sconsign file or equivalent)."""
565         pass
566
567     def get_stored_implicit(self):
568         """Fetch the stored implicit dependencies"""
569         return None
570
571     def set_precious(self, precious = 1):
572         """Set the Node's precious value."""
573         self.precious = precious
574
575     def set_always_build(self, always_build = 1):
576         """Set the Node's always_build value."""
577         self.always_build = always_build
578
579     def exists(self):
580         """Does this node exists?"""
581         # All node exist by default:
582         return 1
583     
584     def rexists(self):
585         """Does this node exist locally or in a repositiory?"""
586         # There are no repositories by default:
587         return self.exists()
588     
589     def prepare(self):
590         """Prepare for this Node to be created.
591         The default implemenation checks that all children either exist
592         or are derived.
593         """
594         def missing(node):
595             return not node.is_derived() and \
596                    not node.is_pseudo_derived() and \
597                    not node.linked and \
598                    not node.rexists()
599         missing_sources = filter(missing, self.children())
600         if missing_sources:
601             desc = "No Builder for target `%s', needed by `%s'." % (missing_sources[0], self)
602             raise SCons.Errors.StopError, desc
603
604     def remove(self):
605         """Remove this Node:  no-op by default."""
606         return None
607
608     def add_dependency(self, depend):
609         """Adds dependencies."""
610         try:
611             self._add_child(self.depends, self.depends_dict, depend)
612         except TypeError, e:
613             e = e.args[0]
614             if SCons.Util.is_List(e):
615                 s = map(str, e)
616             else:
617                 s = str(e)
618             raise SCons.Errors.UserError("attempted to add a non-Node dependency to %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
619
620     def add_ignore(self, depend):
621         """Adds dependencies to ignore."""
622         try:
623             self._add_child(self.ignore, self.ignore_dict, depend)
624         except TypeError, e:
625             e = e.args[0]
626             if SCons.Util.is_List(e):
627                 s = map(str, e)
628             else:
629                 s = str(e)
630             raise SCons.Errors.UserError("attempted to ignore a non-Node dependency of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
631
632     def add_source(self, source):
633         """Adds sources."""
634         try:
635             self._add_child(self.sources, self.sources_dict, source)
636         except TypeError, e:
637             e = e.args[0]
638             if SCons.Util.is_List(e):
639                 s = map(str, e)
640             else:
641                 s = str(e)
642             raise SCons.Errors.UserError("attempted to add a non-Node as source of %s:\n\t%s is a %s, not a Node" % (str(self), s, type(e)))
643
644     def _add_child(self, collection, dict, child):
645         """Adds 'child' to 'collection', first checking 'dict' to see
646         if it's already present."""
647         if type(child) is not type([]):
648             child = [child]
649         for c in child:
650             if not isinstance(c, Node):
651                 raise TypeError, c
652         added = None
653         for c in child:
654             if not dict.has_key(c):
655                 collection.append(c)
656                 dict[c] = 1
657                 added = 1
658             c.parents[self] = 1
659         if added:
660             self._children_reset()
661
662     def add_wkid(self, wkid):
663         """Add a node to the list of kids waiting to be evaluated"""
664         if self.wkids != None:
665             self.wkids.append(wkid)
666
667     def _children_reset(self):
668         try:
669             delattr(self, '_children')
670         except AttributeError:
671             pass
672
673     def children(self, scan=1):
674         """Return a list of the node's direct children, minus those
675         that are ignored by this node."""
676         if scan:
677             self.scan()
678         try:
679             return self._children
680         except AttributeError:
681             c = filter(lambda x, i=self.ignore: x not in i,
682                               self.all_children(scan=0))
683             self._children = c
684             return c
685
686     def all_children(self, scan=1):
687         """Return a list of all the node's direct children."""
688         # The return list may contain duplicate Nodes, especially in
689         # source trees where there are a lot of repeated #includes
690         # of a tangle of .h files.  Profiling shows, however, that
691         # eliminating the duplicates with a brute-force approach that
692         # preserves the order (that is, something like:
693         #
694         #       u = []
695         #       for n in list:
696         #           if n not in u:
697         #               u.append(n)"
698         #
699         # takes more cycles than just letting the underlying methods
700         # hand back cached values if a Node's information is requested
701         # multiple times.  (Other methods of removing duplicates, like
702         # using dictionary keys, lose the order, and the only ordered
703         # dictionary patterns I found all ended up using "not in"
704         # internally anyway...)
705         if scan:
706             self.scan()
707         if self.implicit is None:
708             return self.sources + self.depends
709         else:
710             return self.sources + self.depends + self.implicit
711
712     def get_parents(self):
713         return self.parents.keys()
714
715     def set_state(self, state):
716         self.state = state
717
718     def get_state(self):
719         return self.state
720
721     def current(self, calc=None):
722         return None
723
724     def rfile(self):
725         return self
726
727     def rstr(self):
728         return str(self)
729
730     def is_literal(self):
731         """Always pass the string representation of a Node to
732         the command interpreter literally."""
733         return 1
734
735     def add_pre_action(self, act):
736         """Adds an Action performed on this Node only before
737         building it."""
738         self.pre_actions.append(act)
739
740     def add_post_action(self, act):
741         """Adds and Action performed on this Node only after
742         building it."""
743         self.post_actions.append(act)
744
745     def render_include_tree(self):
746         """
747         Return a text representation, suitable for displaying to the
748         user, of the include tree for the sources of this node.
749         """
750         if self.is_derived() and self.env:
751             env = self.get_build_env()
752             for s in self.sources:
753                 def f(node, env=env, scanner=s.source_scanner, target=self):
754                     return node.get_found_includes(env, scanner, target)
755                 return SCons.Util.render_tree(s, f, 1)
756         else:
757             return None
758
759     def get_abspath(self):
760         """
761         Return an absolute path to the Node.  This will return simply
762         str(Node) by default, but for Node types that have a concept of
763         relative path, this might return something different.
764         """
765         return str(self)
766
767     def for_signature(self):
768         """
769         Return a string representation of the Node that will always
770         be the same for this particular Node, no matter what.  This
771         is by contrast to the __str__() method, which might, for
772         instance, return a relative path for a file Node.  The purpose
773         of this method is to generate a value to be used in signature
774         calculation for the command line used to build a target, and
775         we use this method instead of str() to avoid unnecessary
776         rebuilds.  This method does not need to return something that
777         would actually work in a command line; it can return any kind of
778         nonsense, so long as it does not change.
779         """
780         return str(self)
781
782     def get_string(self, for_signature):
783         """This is a convenience function designed primarily to be
784         used in command generators (i.e., CommandGeneratorActions or
785         Environment variables that are callable), which are called
786         with a for_signature argument that is nonzero if the command
787         generator is being called to generate a signature for the
788         command line, which determines if we should rebuild or not.
789
790         Such command generators shoud use this method in preference
791         to str(Node) when converting a Node to a string, passing
792         in the for_signature parameter, such that we will call
793         Node.for_signature() or str(Node) properly, depending on whether
794         we are calculating a signature or actually constructing a
795         command line."""
796         if for_signature:
797             return self.for_signature()
798         return str(self)
799
800     def get_subst_proxy(self):
801         """
802         This method is expected to return an object that will function
803         exactly like this Node, except that it implements any additional
804         special features that we would like to be in effect for
805         Environment variable substitution.  The principle use is that
806         some Nodes would like to implement a __getattr__() method,
807         but putting that in the Node type itself has a tendency to kill
808         performance.  We instead put it in a proxy and return it from
809         this method.  It is legal for this method to return self
810         if no new functionality is needed for Environment substitution.
811         """
812         return self
813         
814
815 def get_children(node, parent): return node.children()
816 def ignore_cycle(node, stack): pass
817 def do_nothing(node, parent): pass
818
819 class Walker:
820     """An iterator for walking a Node tree.
821
822     This is depth-first, children are visited before the parent.
823     The Walker object can be initialized with any node, and
824     returns the next node on the descent with each next() call.
825     'kids_func' is an optional function that will be called to
826     get the children of a node instead of calling 'children'.
827     'cycle_func' is an optional function that will be called
828     when a cycle is detected.
829
830     This class does not get caught in node cycles caused, for example,
831     by C header file include loops.
832     """
833     def __init__(self, node, kids_func=get_children,
834                              cycle_func=ignore_cycle,
835                              eval_func=do_nothing):
836         self.kids_func = kids_func
837         self.cycle_func = cycle_func
838         self.eval_func = eval_func
839         node.wkids = copy.copy(kids_func(node, None))
840         self.stack = [node]
841         self.history = {} # used to efficiently detect and avoid cycles
842         self.history[node] = None
843
844     def next(self):
845         """Return the next node for this walk of the tree.
846
847         This function is intentionally iterative, not recursive,
848         to sidestep any issues of stack size limitations.
849         """
850
851         while self.stack:
852             if self.stack[-1].wkids:
853                 node = self.stack[-1].wkids.pop(0)
854                 if not self.stack[-1].wkids:
855                     self.stack[-1].wkids = None
856                 if self.history.has_key(node):
857                     self.cycle_func(node, self.stack)
858                 else:
859                     node.wkids = copy.copy(self.kids_func(node, self.stack[-1]))
860                     self.stack.append(node)
861                     self.history[node] = None
862             else:
863                 node = self.stack.pop()
864                 del self.history[node]
865                 if node:
866                     if self.stack:
867                         parent = self.stack[-1]
868                     else:
869                         parent = None
870                     self.eval_func(node, parent)
871                 return node
872
873     def is_done(self):
874         return not self.stack
875
876
877 arg2nodes_lookups = []