Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: site_scons/site_tools/defer.py

Issue 9094: Adding in new software construction toolkit version. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « site_scons/site_tools/concat_source.py ('k') | site_scons/site_tools/environment_tools.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 18 matching lines...) Expand all
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 __defer_groups = {} 39
40 class DeferGroup:
41 """Named list of functions to be deferred."""
42 # If we derive DeferGroup from object, instances of it return type
43 # <class 'defer.DeferGroup'>, which prevents SCons.Util.semi_deepcopy()
44 # from calling its __semi_deepcopy__ function.
45 # TODO(sgk): Make semi_deepcopy() capable of handling classes derived from
46 # object.
47
48 def __init__(self):
49 """Initialize deferred function object."""
50 self.func_env_cwd = []
51 self.after = set()
52
53 def __semi_deepcopy__(self):
54 """Makes a semi-deep-copy of this object.
55
56 Returns:
57 A semi-deep-copy of this object.
58
59 This means it copies the sets and lists contained by this object, but
60 doesn't make copies of the function pointers and environments pointed to by
61 those lists.
62
63 Needed so env.Clone() makes a copy of the defer list, so that functions
64 and after-relationships subsequently added to the clone are not added to
65 the parent.
66 """
67 c = DeferGroup()
68 c.func_env_cwd = self.func_env_cwd[:]
69 c.after = self.after.copy()
70 return c
40 71
41 72
42 def _InitializeDefer(self): 73 def SetDeferRoot(self):
43 """Re-initializes deferred function handling. 74 """Sets the current environment as the root environment for defer.
44 75
45 Args: 76 Args:
46 self: Parent environment 77 self: Current environment context.
78
79 Functions deferred by environments cloned from the root environment (that is,
80 function deferred by children of the root environment) will be executed when
81 ExecuteDefer() is called from the root environment.
82
83 Functions deferred by environments from which the root environment was cloned
84 (that is, functions deferred by parents of the root environment) will be
85 passed the root environment instead of the original parent environment.
86 (Otherwise, they would have no way to determine the root environment.)
47 """ 87 """
48 # Clear the list of deferred groups 88 # Set the current environment as the root for holding defer groups
49 __defer_groups.clear() 89 self['_DEFER_ROOT_ENV'] = self
90
91 # Deferred functions this environment got from its parents will be run in the
92 # new root context.
93 for group in GetDeferGroups(self).values():
94 new_list = [(func, self, cwd) for (func, env, cwd) in group.func_env_cwd]
95 group.func_env_cwd = new_list
50 96
51 97
52 def _ExecuteDefer(self): 98 def GetDeferRoot(self):
99 """Returns the root environment for defer.
100
101 Args:
102 self: Current environment context.
103
104 Returns:
105 The root environment for defer. If one of this environment's parents
106 called SetDeferRoot(), returns that environment. Otherwise returns the
107 current environment.
108 """
109 return self.get('_DEFER_ROOT_ENV', self)
110
111
112 def GetDeferGroups(env):
113 """Returns the dict of defer groups from the root defer environment.
114
115 Args:
116 env: Environment context.
117
118 Returns:
119 The dict of defer groups from the root defer environment.
120 """
121 return env.GetDeferRoot()['_DEFER_GROUPS']
122
123
124 def ExecuteDefer(self):
53 """Executes deferred functions. 125 """Executes deferred functions.
54 126
55 Args: 127 Args:
56 self: Parent environment 128 self: Current environment context.
57 """ 129 """
58 # Save directory, so SConscript functions can occur in the right subdirs 130 # Save directory, so SConscript functions can occur in the right subdirs
59 oldcwd = os.getcwd() 131 oldcwd = os.getcwd()
60 132
133 # 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.
135 if self.GetDeferRoot() != self:
136 print ('Warning: Ignoring call to ExecuteDefer() from child of the '
137 'environment passed to SetDeferRoot().')
138 return
139
140 # Get list of defer groups from ourselves.
141 defer_groups = GetDeferGroups(self)
142
61 # Loop through deferred functions 143 # Loop through deferred functions
62 while __defer_groups: 144 while defer_groups:
63 did_work = False 145 did_work = False
64 for name, group in __defer_groups.items(): 146 for name, group in defer_groups.items():
65 if group.after.intersection(__defer_groups.keys()): 147 if group.after.intersection(defer_groups.keys()):
66 continue # Still have dependencies 148 continue # Still have dependencies
67 if group.func_env_cwd: 149 if group.func_env_cwd:
68 # Run all the functions in our named group 150 # Run all the functions in our named group
69 for func, env, cwd in group.func_env_cwd: 151 for func, env, cwd in group.func_env_cwd:
70 os.chdir(cwd) 152 os.chdir(cwd)
71 func(env) 153 func(env)
72 did_work = True 154 did_work = True
73 del __defer_groups[name] 155 del defer_groups[name]
74 break 156 break
75 if not did_work: 157 if not did_work:
76 errmsg = 'Error in _ExecuteDefer: dependency cycle detected.\n' 158 errmsg = 'Error in ExecuteDefer: dependency cycle detected.\n'
77 for name, group in __defer_groups.items(): 159 for name, group in defer_groups.items():
78 errmsg += ' %s after: %s\n' % (name, group.after) 160 errmsg += ' %s after: %s\n' % (name, group.after)
79 raise SCons.Errors.UserError(errmsg) 161 raise SCons.Errors.UserError(errmsg)
80 162
81 # Restore directory 163 # Restore directory
82 os.chdir(oldcwd) 164 os.chdir(oldcwd)
83 165
84 166
85 class DeferFunc(object): 167 def PrintDefer(self, print_functions=True):
86 """Named list of functions to be deferred.""" 168 """Prints the current defer dependency graph.
87 169
88 def __init__(self): 170 Args:
89 """Initialize deferred function object.""" 171 self: Environment in which PrintDefer() was called.
90 object.__init__(self) 172 print_functions: Print individual functions in defer groups.
91 self.func_env_cwd = [] 173 """
92 self.after = set() 174 # Get the defer dict
175 # Get list of defer groups from ourselves.
176 defer_groups = GetDeferGroups(self)
177 dgkeys = defer_groups.keys()
178 dgkeys.sort()
179 for k in dgkeys:
180 print ' +- %s' % k
181 group = defer_groups[k]
182 after = list(group.after)
183 if after:
184 print ' | after'
185 after.sort()
186 for a in after:
187 print ' | +- %s' % a
188 if print_functions and group.func_env_cwd:
189 print ' functions'
190 for func, env, cwd in group.func_env_cwd:
191 print ' | +- %s %s' % (func.__name__, cwd)
93 192
94 193
95 def Defer(self, *args, **kwargs): 194 def Defer(self, *args, **kwargs):
96 """Adds a deferred function or modifies defer dependencies. 195 """Adds a deferred function or modifies defer dependencies.
97 196
98 Args: 197 Args:
99 self: Environment in which Defer() was called 198 self: Environment in which Defer() was called
100 args: Positional arguments 199 args: Positional arguments
101 kwargs: Named arguments 200 kwargs: Named arguments
102 201
103 The deferred function will be passed the environment used to call Defer(), 202 The deferred function will be passed the environment used to call Defer(),
104 and will be executed in the same working directory as the calling SConscript. 203 and will be executed in the same working directory as the calling SConscript.
204 (Exception: if this environment is cloned and the clone calls SetDeferRoot()
205 and then ExecuteDefer(), the function will be passed the root environment,
206 instead of the environment used to call Defer().)
105 207
106 All deferred functions run after all SConscripts. Additional dependencies 208 All deferred functions run after all SConscripts. Additional dependencies
107 may be specified with the after= keyword. 209 may be specified with the after= keyword.
108 210
109 Usage: 211 Usage:
110 212
111 env.Defer(func) 213 env.Defer(func)
112 # Defer func() until after all SConscripts 214 # Defer func() until after all SConscripts
113 215
114 env.Defer(func, after=otherfunc) 216 env.Defer(func, after=otherfunc)
(...skipping 20 matching lines...) Expand all
135 name = None 237 name = None
136 func = None 238 func = None
137 for a in args: 239 for a in args:
138 if isinstance(a, str): 240 if isinstance(a, str):
139 name = a 241 name = a
140 elif isinstance(a, types.FunctionType): 242 elif isinstance(a, types.FunctionType):
141 func = a 243 func = a
142 if func and not name: 244 if func and not name:
143 name = func.__name__ 245 name = func.__name__
144 246
247 # TODO(rspangler): Why not allow multiple functions? Should be ok
248
145 # Get list of names and/or functions this function should defer until after 249 # Get list of names and/or functions this function should defer until after
146 after = [] 250 after = []
147 for a in self.Flatten(kwargs.get('after')): 251 for a in self.Flatten(kwargs.get('after')):
148 if isinstance(a, str): 252 if isinstance(a, str):
253 # TODO(rspangler): Should check if '$' in a, and if so, subst() it and
254 # recurse into it.
149 after.append(a) 255 after.append(a)
150 elif isinstance(a, types.FunctionType): 256 elif isinstance(a, types.FunctionType):
151 after.append(a.__name__) 257 after.append(a.__name__)
152 elif a is not None: 258 elif a is not None:
153 # Deferring 259 # Deferring
154 raise ValueError('Defer after=%r is not a function or name' % a) 260 raise ValueError('Defer after=%r is not a function or name' % a)
155 261
156 # Find the deferred function 262 # Find the deferred function
157 if name not in __defer_groups: 263 defer_groups = GetDeferGroups(self)
158 __defer_groups[name] = DeferFunc() 264 if name not in defer_groups:
159 group = __defer_groups[name] 265 defer_groups[name] = DeferGroup()
266 group = defer_groups[name]
160 267
161 # If we were given a function, also save environment and current directory 268 # If we were given a function, also save environment and current directory
162 if func: 269 if func:
163 group.func_env_cwd.append((func, self, os.getcwd())) 270 group.func_env_cwd.append((func, self, os.getcwd()))
164 271
165 # Add dependencies for the function 272 # Add dependencies for the function
166 group.after.update(after) 273 group.after.update(after)
167 274
168 275
169 def generate(env): 276 def generate(env):
170 # NOTE: SCons requires the use of this name, which fails gpylint. 277 # NOTE: SCons requires the use of this name, which fails gpylint.
171 """SCons entry point for this tool.""" 278 """SCons entry point for this tool."""
279 env.Append(_DEFER_GROUPS={})
172 280
173 env.AddMethod(_InitializeDefer)
174 env.AddMethod(_ExecuteDefer)
175 env.AddMethod(Defer) 281 env.AddMethod(Defer)
282 env.AddMethod(ExecuteDefer)
283 env.AddMethod(GetDeferRoot)
284 env.AddMethod(PrintDefer)
285 env.AddMethod(SetDeferRoot)
OLDNEW
« no previous file with comments | « site_scons/site_tools/concat_source.py ('k') | site_scons/site_tools/environment_tools.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698