| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/python2.4 |
| 2 # Copyright 2008, Google Inc. |
| 3 # All rights reserved. |
| 4 # |
| 5 # Redistribution and use in source and binary forms, with or without |
| 6 # modification, are permitted provided that the following conditions are |
| 7 # met: |
| 8 # |
| 9 # * Redistributions of source code must retain the above copyright |
| 10 # notice, this list of conditions and the following disclaimer. |
| 11 # * Redistributions in binary form must reproduce the above |
| 12 # copyright notice, this list of conditions and the following disclaimer |
| 13 # in the documentation and/or other materials provided with the |
| 14 # distribution. |
| 15 # * Neither the name of Google Inc. nor the names of its |
| 16 # contributors may be used to endorse or promote products derived from |
| 17 # this software without specific prior written permission. |
| 18 # |
| 19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 |
| 31 """Defer tool for SCons.""" |
| 32 |
| 33 |
| 34 import os |
| 35 import sys |
| 36 import types |
| 37 |
| 38 |
| 39 __defer_groups = {} |
| 40 |
| 41 |
| 42 def _InitializeDefer(self): |
| 43 """Re-initializes deferred function handling. |
| 44 |
| 45 Args: |
| 46 self: Parent environment |
| 47 """ |
| 48 # Clear the list of deferred groups |
| 49 __defer_groups.clear() |
| 50 |
| 51 |
| 52 def _ExecuteDefer(self): |
| 53 """Executes deferred functions. |
| 54 |
| 55 Args: |
| 56 self: Parent environment |
| 57 """ |
| 58 # Save directory, so SConscript functions can occur in the right subdirs |
| 59 oldcwd = os.getcwd() |
| 60 |
| 61 # Loop through deferred functions |
| 62 while __defer_groups: |
| 63 did_work = False |
| 64 for name, group in __defer_groups.items(): |
| 65 if group.after.intersection(__defer_groups.keys()): |
| 66 continue # Still have dependencies |
| 67 if group.func_env_cwd: |
| 68 # Run all the functions in our named group |
| 69 for func, env, cwd in group.func_env_cwd: |
| 70 os.chdir(cwd) |
| 71 func(env) |
| 72 did_work = True |
| 73 del __defer_groups[name] |
| 74 break |
| 75 if not did_work: |
| 76 print 'Error in _ExecuteDefer: dependency cycle detected.' |
| 77 for name, group in __defer_groups.items(): |
| 78 print ' %s after: %s' % (name, group.after) |
| 79 # TODO(rspangler): should throw exception? |
| 80 sys.exit(1) |
| 81 |
| 82 # Restore directory |
| 83 os.chdir(oldcwd) |
| 84 |
| 85 |
| 86 class DeferFunc(object): |
| 87 """Named list of functions to be deferred.""" |
| 88 |
| 89 def __init__(self): |
| 90 """Initialize deferred function object.""" |
| 91 object.__init__(self) |
| 92 self.func_env_cwd = [] |
| 93 self.after = set() |
| 94 |
| 95 |
| 96 def Defer(self, *args, **kwargs): |
| 97 """Adds a deferred function or modifies defer dependencies. |
| 98 |
| 99 Args: |
| 100 self: Environment in which Defer() was called |
| 101 args: Positional arguments |
| 102 kwargs: Named arguments |
| 103 |
| 104 The deferred function will be passed the environment used to call Defer(), |
| 105 and will be executed in the same working directory as the calling SConscript. |
| 106 |
| 107 All deferred functions run after all SConscripts. Additional dependencies |
| 108 may be specified with the after= keyword. |
| 109 |
| 110 Usage: |
| 111 |
| 112 env.Defer(func) |
| 113 # Defer func() until after all SConscripts |
| 114 |
| 115 env.Defer(func, after=otherfunc) |
| 116 # Defer func() until otherfunc() runs |
| 117 |
| 118 env.Defer(func, 'bob') |
| 119 # Defer func() until after SConscripts, put in group 'bob' |
| 120 |
| 121 env.Defer(func2, after='bob') |
| 122 # Defer func2() until after all funcs in 'bob' group have run |
| 123 |
| 124 env.Defer(func3, 'sam') |
| 125 # Defer func3() until after SConscripts, put in group 'sam' |
| 126 |
| 127 env.Defer('bob', after='sam') |
| 128 # Defer all functions in group 'bob' until after all functions in group |
| 129 # 'sam' have run. |
| 130 |
| 131 env.Defer(func4, after=['bob', 'sam']) |
| 132 # Defer func4() until after all functions in groups 'bob' and 'sam' have |
| 133 # run. |
| 134 """ |
| 135 # Get name of group to defer and/or the a function |
| 136 name = None |
| 137 func = None |
| 138 for a in args: |
| 139 if isinstance(a, str): |
| 140 name = a |
| 141 elif isinstance(a, types.FunctionType): |
| 142 func = a |
| 143 if func and not name: |
| 144 name = func.__name__ |
| 145 |
| 146 # Get list of names and/or functions this function should defer until after |
| 147 after = [] |
| 148 for a in self.Flatten(kwargs.get('after')): |
| 149 if isinstance(a, str): |
| 150 after.append(a) |
| 151 elif isinstance(a, types.FunctionType): |
| 152 after.append(a.__name__) |
| 153 elif a is not None: |
| 154 # Deferring |
| 155 # TODO(rspangler): should throw an exception |
| 156 print ('Warning: Defer can only wait for functions or names; ignoring' |
| 157 'after = ', a) |
| 158 |
| 159 # Find the deferred function |
| 160 if name not in __defer_groups: |
| 161 __defer_groups[name] = DeferFunc() |
| 162 group = __defer_groups[name] |
| 163 |
| 164 # If we were given a function, also save environment and current directory |
| 165 if func: |
| 166 group.func_env_cwd.append((func, self, os.getcwd())) |
| 167 |
| 168 # Add dependencies for the function |
| 169 group.after.update(after) |
| 170 |
| 171 |
| 172 def generate(env): |
| 173 # NOTE: SCons requires the use of this name, which fails gpylint. |
| 174 """SCons entry point for this tool.""" |
| 175 |
| 176 env.AddMethod(_InitializeDefer) |
| 177 env.AddMethod(_ExecuteDefer) |
| 178 env.AddMethod(Defer) |
| OLD | NEW |