| OLD | NEW |
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright 2008, Google Inc. | 2 # Copyright 2008, Google Inc. |
| 3 # All rights reserved. | 3 # All rights reserved. |
| 4 # | 4 # |
| 5 # Redistribution and use in source and binary forms, with or without | 5 # Redistribution and use in source and binary forms, with or without |
| 6 # modification, are permitted provided that the following conditions are | 6 # modification, are permitted provided that the following conditions are |
| 7 # met: | 7 # met: |
| 8 # | 8 # |
| 9 # * Redistributions of source code must retain the above copyright | 9 # * Redistributions of source code must retain the above copyright |
| 10 # notice, this list of conditions and the following disclaimer. | 10 # notice, this list of conditions and the following disclaimer. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 """Defer tool for SCons.""" | 31 """Defer tool for SCons.""" |
| 32 | 32 |
| 33 | 33 |
| 34 import os | 34 import os |
| 35 import sys | 35 import sys |
| 36 import types | 36 import types |
| 37 import SCons.Errors | 37 import SCons.Errors |
| 38 | 38 |
| 39 | 39 |
| 40 # Current group name being executed by ExecuteDefer(). Set to None outside |
| 41 # of ExecuteDefer(). |
| 42 _execute_defer_context = None |
| 43 |
| 44 |
| 40 class DeferGroup: | 45 class DeferGroup: |
| 41 """Named list of functions to be deferred.""" | 46 """Named list of functions to be deferred.""" |
| 42 # If we derive DeferGroup from object, instances of it return type | 47 # If we derive DeferGroup from object, instances of it return type |
| 43 # <class 'defer.DeferGroup'>, which prevents SCons.Util.semi_deepcopy() | 48 # <class 'defer.DeferGroup'>, which prevents SCons.Util.semi_deepcopy() |
| 44 # from calling its __semi_deepcopy__ function. | 49 # from calling its __semi_deepcopy__ function. |
| 45 # TODO(sgk): Make semi_deepcopy() capable of handling classes derived from | 50 # TODO(sgk): Make semi_deepcopy() capable of handling classes derived from |
| 46 # object. | 51 # object. |
| 47 | 52 |
| 48 def __init__(self): | 53 def __init__(self): |
| 49 """Initialize deferred function object.""" | 54 """Initialize deferred function object.""" |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 """ | 125 """ |
| 121 return env.GetDeferRoot()['_DEFER_GROUPS'] | 126 return env.GetDeferRoot()['_DEFER_GROUPS'] |
| 122 | 127 |
| 123 | 128 |
| 124 def ExecuteDefer(self): | 129 def ExecuteDefer(self): |
| 125 """Executes deferred functions. | 130 """Executes deferred functions. |
| 126 | 131 |
| 127 Args: | 132 Args: |
| 128 self: Current environment context. | 133 self: Current environment context. |
| 129 """ | 134 """ |
| 135 # Check for re-entrancy |
| 136 global _execute_defer_context |
| 137 if _execute_defer_context: |
| 138 raise SCons.Errors.UserError('Re-entrant call to ExecuteDefer().') |
| 139 |
| 130 # Save directory, so SConscript functions can occur in the right subdirs | 140 # Save directory, so SConscript functions can occur in the right subdirs |
| 131 oldcwd = os.getcwd() | 141 oldcwd = os.getcwd() |
| 132 | 142 |
| 133 # If defer root is set and isn't this environment, we're being called from a | 143 # If defer root is set and isn't this environment, we're being called from a |
| 134 # sub-environment. That's not where we should be called. | 144 # sub-environment. That's not where we should be called. |
| 135 if self.GetDeferRoot() != self: | 145 if self.GetDeferRoot() != self: |
| 136 print ('Warning: Ignoring call to ExecuteDefer() from child of the ' | 146 print ('Warning: Ignoring call to ExecuteDefer() from child of the ' |
| 137 'environment passed to SetDeferRoot().') | 147 'environment passed to SetDeferRoot().') |
| 138 return | 148 return |
| 139 | 149 |
| 140 # Get list of defer groups from ourselves. | 150 # Get list of defer groups from ourselves. |
| 141 defer_groups = GetDeferGroups(self) | 151 defer_groups = GetDeferGroups(self) |
| 142 | 152 |
| 143 # Loop through deferred functions | 153 # Loop through deferred functions |
| 144 while defer_groups: | 154 try: |
| 145 did_work = False | 155 while defer_groups: |
| 146 for name, group in defer_groups.items(): | 156 did_work = False |
| 147 if group.after.intersection(defer_groups.keys()): | |
| 148 continue # Still have dependencies | |
| 149 if group.func_env_cwd: | |
| 150 # Run all the functions in our named group | |
| 151 for func, env, cwd in group.func_env_cwd: | |
| 152 os.chdir(cwd) | |
| 153 func(env) | |
| 154 did_work = True | |
| 155 del defer_groups[name] | |
| 156 break | |
| 157 if not did_work: | |
| 158 errmsg = 'Error in ExecuteDefer: dependency cycle detected.\n' | |
| 159 for name, group in defer_groups.items(): | 157 for name, group in defer_groups.items(): |
| 160 errmsg += ' %s after: %s\n' % (name, group.after) | 158 if group.after.intersection(defer_groups.keys()): |
| 161 raise SCons.Errors.UserError(errmsg) | 159 continue # Still have dependencies |
| 160 |
| 161 # Set defer context |
| 162 _execute_defer_context = name |
| 163 |
| 164 # Remove this group from the list of defer groups now, in case one of |
| 165 # the functions it calls adds back a function into that defer group. |
| 166 del defer_groups[name] |
| 167 |
| 168 if group.func_env_cwd: |
| 169 # Run all the functions in our named group |
| 170 for func, env, cwd in group.func_env_cwd: |
| 171 os.chdir(cwd) |
| 172 func(env) |
| 173 |
| 174 # The defer groups have been altered, so restart the search for |
| 175 # functions that can be executed. |
| 176 did_work = True |
| 177 break |
| 178 |
| 179 if not did_work: |
| 180 errmsg = 'Error in ExecuteDefer: dependency cycle detected.\n' |
| 181 for name, group in defer_groups.items(): |
| 182 errmsg += ' %s after: %s\n' % (name, group.after) |
| 183 raise SCons.Errors.UserError(errmsg) |
| 184 finally: |
| 185 # No longer in a defer context |
| 186 _execute_defer_context = None |
| 162 | 187 |
| 163 # Restore directory | 188 # Restore directory |
| 164 os.chdir(oldcwd) | 189 os.chdir(oldcwd) |
| 165 | 190 |
| 166 | 191 |
| 167 def PrintDefer(self, print_functions=True): | 192 def PrintDefer(self, print_functions=True): |
| 168 """Prints the current defer dependency graph. | 193 """Prints the current defer dependency graph. |
| 169 | 194 |
| 170 Args: | 195 Args: |
| 171 self: Environment in which PrintDefer() was called. | 196 self: Environment in which PrintDefer() was called. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 defer_groups[name] = DeferGroup() | 290 defer_groups[name] = DeferGroup() |
| 266 group = defer_groups[name] | 291 group = defer_groups[name] |
| 267 | 292 |
| 268 # If we were given a function, also save environment and current directory | 293 # If we were given a function, also save environment and current directory |
| 269 if func: | 294 if func: |
| 270 group.func_env_cwd.append((func, self, os.getcwd())) | 295 group.func_env_cwd.append((func, self, os.getcwd())) |
| 271 | 296 |
| 272 # Add dependencies for the function | 297 # Add dependencies for the function |
| 273 group.after.update(after) | 298 group.after.update(after) |
| 274 | 299 |
| 300 # If we are already inside a call to ExecuteDefer(), any functions which are |
| 301 # deferring until after the current function must also be deferred until |
| 302 # after this new function. In short, this means that if b() defers until |
| 303 # after a() and a() calls Defer() to defer c(), then b() must also defer |
| 304 # until after c(). |
| 305 if _execute_defer_context and name != _execute_defer_context: |
| 306 for other_name, other_group in GetDeferGroups(self).items(): |
| 307 if other_name == name: |
| 308 continue # Don't defer after ourselves |
| 309 if _execute_defer_context in other_group.after: |
| 310 other_group.after.add(name) |
| 311 |
| 275 | 312 |
| 276 def generate(env): | 313 def generate(env): |
| 277 # NOTE: SCons requires the use of this name, which fails gpylint. | 314 # NOTE: SCons requires the use of this name, which fails gpylint. |
| 278 """SCons entry point for this tool.""" | 315 """SCons entry point for this tool.""" |
| 279 env.Append(_DEFER_GROUPS={}) | 316 env.Append(_DEFER_GROUPS={}) |
| 280 | 317 |
| 281 env.AddMethod(Defer) | 318 env.AddMethod(Defer) |
| 282 env.AddMethod(ExecuteDefer) | 319 env.AddMethod(ExecuteDefer) |
| 283 env.AddMethod(GetDeferRoot) | 320 env.AddMethod(GetDeferRoot) |
| 284 env.AddMethod(PrintDefer) | 321 env.AddMethod(PrintDefer) |
| 285 env.AddMethod(SetDeferRoot) | 322 env.AddMethod(SetDeferRoot) |
| OLD | NEW |