1 """SCons.Action
2
3 This encapsulates information about executing any sort of action that
4 can build one or more target Nodes (typically files) from one or more
5 source Nodes (also typically files) given a specific Environment.
6
7 The base class here is ActionBase. The base class supplies just a few
8 OO utility methods and some generic methods for displaying information
9 about an Action in response to the various commands that control printing.
10
11 A second-level base class is _ActionAction. This extends ActionBase
12 by providing the methods that can be used to show and perform an
13 action. True Action objects will subclass _ActionAction; Action
14 factory class objects will subclass ActionBase.
15
16 The heavy lifting is handled by subclasses for the different types of
17 actions we might execute:
18
19 CommandAction
20 CommandGeneratorAction
21 FunctionAction
22 ListAction
23
24 The subclasses supply the following public interface methods used by
25 other modules:
26
27 __call__()
28 THE public interface, "calling" an Action object executes the
29 command or Python function. This also takes care of printing
30 a pre-substitution command for debugging purposes.
31
32 get_contents()
33 Fetches the "contents" of an Action for signature calculation.
34 This is what gets MD5 checksumm'ed to decide if a target needs
35 to be rebuilt because its action changed.
36
37 genstring()
38 Returns a string representation of the Action *without*
39 command substitution, but allows a CommandGeneratorAction to
40 generate the right action based on the specified target,
41 source and env. This is used by the Signature subsystem
42 (through the Executor) to obtain an (imprecise) representation
43 of the Action operation for informative purposes.
44
45
46 Subclasses also supply the following methods for internal use within
47 this module:
48
49 __str__()
50 Returns a string approximation of the Action; no variable
51 substitution is performed.
52
53 execute()
54 The internal method that really, truly, actually handles the
55 execution of a command or Python function. This is used so
56 that the __call__() methods can take care of displaying any
57 pre-substitution representations, and *then* execute an action
58 without worrying about the specific Actions involved.
59
60 strfunction()
61 Returns a substituted string representation of the Action.
62 This is used by the _ActionAction.show() command to display the
63 command/function that will be executed to generate the target(s).
64
65 There is a related independent ActionCaller class that looks like a
66 regular Action, and which serves as a wrapper for arbitrary functions
67 that we want to let the user specify the arguments to now, but actually
68 execute later (when an out-of-date check determines that it's needed to
69 be executed, for example). Objects of this class are returned by an
70 ActionFactory class that provides a __call__() method as a convenient
71 way for wrapping up the functions.
72
73 """
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 __revision__ = "src/engine/SCons/Action.py 2928 2008/04/29 22:44:09 knight"
99
100 import cPickle
101 import dis
102 import os
103 import os.path
104 import string
105 import sys
106
107 from SCons.Debug import logInstanceCreation
108 import SCons.Errors
109 import SCons.Executor
110 import SCons.Util
111
114
115 _null = _Null
116
117 print_actions = 1
118 execute_actions = 1
119 print_actions_presub = 0
120
121 default_ENV = None
122
124 try:
125 return n.rfile()
126 except AttributeError:
127 return n
128
131
132 try:
133 SET_LINENO = dis.SET_LINENO
134 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
135 except AttributeError:
136 remove_set_lineno_codes = lambda x: x
137 else:
153
154
156 """Return the signature contents of a callable Python object.
157 """
158 try:
159
160 return _function_contents(obj.im_func)
161
162 except AttributeError:
163 try:
164
165 return _function_contents(obj.__call__.im_func)
166
167 except AttributeError:
168 try:
169
170 return _code_contents(obj)
171
172 except AttributeError:
173
174 return _function_contents(obj)
175
176
178 """Return the signature contents of any Python object.
179
180 We have to handle the case where object contains a code object
181 since it can be pickled directly.
182 """
183 try:
184
185 return _function_contents(obj.im_func)
186
187 except AttributeError:
188 try:
189
190 return _function_contents(obj.__call__.im_func)
191
192 except AttributeError:
193 try:
194
195 return _code_contents(obj)
196
197 except AttributeError:
198 try:
199
200 return _function_contents(obj)
201
202 except AttributeError:
203
204 try:
205 return cPickle.dumps(obj)
206 except (cPickle.PicklingError, TypeError):
207
208
209
210
211
212 return str(obj)
213
214
215 -def _code_contents(code):
216 """Return the signature contents of a code object.
217
218 By providing direct access to the code object of the
219 function, Python makes this extremely easy. Hooray!
220
221 Unfortunately, older versions of Python include line
222 number indications in the compiled byte code. Boo!
223 So we remove the line number byte codes to prevent
224 recompilations from moving a Python function.
225 """
226
227 contents = []
228
229
230
231 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
232 try:
233 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
234 except AttributeError:
235
236 contents.append(",0,0")
237
238
239
240
241
242
243
244
245
246 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')')
247
248
249
250
251
252 contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
253
254
255
256 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
257
258 return string.join(contents, '')
259
260
262 """Return the signature contents of a function."""
263
264 contents = [_code_contents(func.func_code)]
265
266
267 if func.func_defaults:
268 contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')')
269 else:
270 contents.append(',()')
271
272
273 try:
274 closure = func.func_closure or []
275 except AttributeError:
276
277 closure = []
278
279
280 xxx = map(lambda x: _object_contents(x.cell_contents), closure)
281 contents.append(',(' + string.join(xxx, ',') + ')')
282
283 return string.join(contents, '')
284
285
287
288
289
290 a1 = Action(act1)
291 a2 = Action(act2)
292 if a1 is None or a2 is None:
293 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
294 if isinstance(a1, ListAction):
295 if isinstance(a2, ListAction):
296 return ListAction(a1.list + a2.list)
297 else:
298 return ListAction(a1.list + [ a2 ])
299 else:
300 if isinstance(a2, ListAction):
301 return ListAction([ a1 ] + a2.list)
302 else:
303 return ListAction([ a1, a2 ])
304
306 """This is the actual "implementation" for the
307 Action factory method, below. This handles the
308 fact that passing lists to Action() itself has
309 different semantics than passing lists as elements
310 of lists.
311
312 The former will create a ListAction, the latter
313 will create a CommandAction by converting the inner
314 list elements to strings."""
315
316 if isinstance(act, ActionBase):
317 return act
318 if SCons.Util.is_List(act):
319 return apply(CommandAction, (act,)+args, kw)
320 if callable(act):
321 try:
322 gen = kw['generator']
323 del kw['generator']
324 except KeyError:
325 gen = 0
326 if gen:
327 action_type = CommandGeneratorAction
328 else:
329 action_type = FunctionAction
330 return apply(action_type, (act,)+args, kw)
331 if SCons.Util.is_String(act):
332 var=SCons.Util.get_environment_var(act)
333 if var:
334
335
336
337
338
339
340 return apply(LazyAction, (var,)+args, kw)
341 commands = string.split(str(act), '\n')
342 if len(commands) == 1:
343 return apply(CommandAction, (commands[0],)+args, kw)
344 else:
345 listCmdActions = map(lambda x, args=args, kw=kw:
346 apply(CommandAction, (x,)+args, kw),
347 commands)
348 return ListAction(listCmdActions)
349 return None
350
352 """A factory for action objects."""
353 if SCons.Util.is_List(act):
354 acts = map(lambda a, args=args, kw=kw:
355 apply(_do_create_action, (a,)+args, kw),
356 act)
357 acts = filter(None, acts)
358 if len(acts) == 1:
359 return acts[0]
360 else:
361 return ListAction(acts)
362 else:
363 return apply(_do_create_action, (act,)+args, kw)
364
366 """Base class for all types of action objects that can be held by
367 other objects (Builders, Executors, etc.) This provides the
368 common methods for manipulating and combining those actions."""
369
371 return cmp(self.__dict__, other)
372
375
377 return _actionAppend(self, other)
378
380 return _actionAppend(other, self)
381
383
384
385
386
387
388
389 self.presub_env = env
390 lines = string.split(str(self), '\n')
391 self.presub_env = None
392 return lines
393
394 - def get_executor(self, env, overrides, tlist, slist, executor_kw):
395 """Return the Executor for this Action."""
396 return SCons.Executor.Executor(self, env, overrides,
397 tlist, slist, executor_kw)
398
400 """Base class for actions that create output objects."""
401 - def __init__(self, strfunction=_null, presub=_null, chdir=None, exitstatfunc=None, **kw):
409
411 sys.stdout.write(s + "\n")
412