Package SCons :: Module Action
[hide private]
[frames] | no frames]

Source Code for Module SCons.Action

   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          plus the varlist.  This is what gets MD5 checksummed to decide 
  35          if a target needs 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      get_presig() 
  61          Fetches the "contents" of a subclass for signature calculation. 
  62          The varlist is added to this to produce the Action's contents. 
  63   
  64      strfunction() 
  65          Returns a substituted string representation of the Action. 
  66          This is used by the _ActionAction.show() command to display the 
  67          command/function that will be executed to generate the target(s). 
  68   
  69  There is a related independent ActionCaller class that looks like a 
  70  regular Action, and which serves as a wrapper for arbitrary functions 
  71  that we want to let the user specify the arguments to now, but actually 
  72  execute later (when an out-of-date check determines that it's needed to 
  73  be executed, for example).  Objects of this class are returned by an 
  74  ActionFactory class that provides a __call__() method as a convenient 
  75  way for wrapping up the functions. 
  76   
  77  """ 
  78   
  79  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  80  # 
  81  # Permission is hereby granted, free of charge, to any person obtaining 
  82  # a copy of this software and associated documentation files (the 
  83  # "Software"), to deal in the Software without restriction, including 
  84  # without limitation the rights to use, copy, modify, merge, publish, 
  85  # distribute, sublicense, and/or sell copies of the Software, and to 
  86  # permit persons to whom the Software is furnished to do so, subject to 
  87  # the following conditions: 
  88  # 
  89  # The above copyright notice and this permission notice shall be included 
  90  # in all copies or substantial portions of the Software. 
  91  # 
  92  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  93  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  94  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  95  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  96  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  97  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  98  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  99   
 100  __revision__ = "src/engine/SCons/Action.py 3765 2008/11/04 08:12:16 scons" 
 101   
 102  import cPickle 
 103  import dis 
 104  import os 
 105  import os.path 
 106  import string 
 107  import sys 
 108  import subprocess 
 109   
 110  from SCons.Debug import logInstanceCreation 
 111  import SCons.Errors 
 112  import SCons.Executor 
 113  import SCons.Util 
 114  import SCons.Subst 
 115   
 116  # we use these a lot, so try to optimize them 
 117  is_String = SCons.Util.is_String 
 118  is_List = SCons.Util.is_List 
 119   
120 -class _null:
121 pass
122 123 print_actions = 1 124 execute_actions = 1 125 print_actions_presub = 0 126
127 -def rfile(n):
128 try: 129 return n.rfile() 130 except AttributeError: 131 return n
132
133 -def default_exitstatfunc(s):
134 return s
135 136 try: 137 SET_LINENO = dis.SET_LINENO 138 HAVE_ARGUMENT = dis.HAVE_ARGUMENT 139 except AttributeError: 140 remove_set_lineno_codes = lambda x: x 141 else:
142 - def remove_set_lineno_codes(code):
143 result = [] 144 n = len(code) 145 i = 0 146 while i < n: 147 c = code[i] 148 op = ord(c) 149 if op >= HAVE_ARGUMENT: 150 if op != SET_LINENO: 151 result.append(code[i:i+3]) 152 i = i+3 153 else: 154 result.append(c) 155 i = i+1 156 return string.join(result, '')
157 158
159 -def _callable_contents(obj):
160 """Return the signature contents of a callable Python object. 161 """ 162 try: 163 # Test if obj is a method. 164 return _function_contents(obj.im_func) 165 166 except AttributeError: 167 try: 168 # Test if obj is a callable object. 169 return _function_contents(obj.__call__.im_func) 170 171 except AttributeError: 172 try: 173 # Test if obj is a code object. 174 return _code_contents(obj) 175 176 except AttributeError: 177 # Test if obj is a function object. 178 return _function_contents(obj)
179 180
181 -def _object_contents(obj):
182 """Return the signature contents of any Python object. 183 184 We have to handle the case where object contains a code object 185 since it can be pickled directly. 186 """ 187 try: 188 # Test if obj is a method. 189 return _function_contents(obj.im_func) 190 191 except AttributeError: 192 try: 193 # Test if obj is a callable object. 194 return _function_contents(obj.__call__.im_func) 195 196 except AttributeError: 197 try: 198 # Test if obj is a code object. 199 return _code_contents(obj) 200 201 except AttributeError: 202 try: 203 # Test if obj is a function object. 204 return _function_contents(obj) 205 206 except AttributeError: 207 # Should be a pickable Python object. 208 try: 209 return cPickle.dumps(obj) 210 except (cPickle.PicklingError, TypeError): 211 # This is weird, but it seems that nested classes 212 # are unpickable. The Python docs say it should 213 # always be a PicklingError, but some Python 214 # versions seem to return TypeError. Just do 215 # the best we can. 216 return str(obj)
217 218
219 -def _code_contents(code):
220 """Return the signature contents of a code object. 221 222 By providing direct access to the code object of the 223 function, Python makes this extremely easy. Hooray! 224 225 Unfortunately, older versions of Python include line 226 number indications in the compiled byte code. Boo! 227 So we remove the line number byte codes to prevent 228 recompilations from moving a Python function. 229 """ 230 231 contents = [] 232 233 # The code contents depends on the number of local variables 234 # but not their actual names. 235 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames))) 236 try: 237 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars))) 238 except AttributeError: 239 # Older versions of Python do not support closures. 240 contents.append(",0,0") 241 242 # The code contents depends on any constants accessed by the 243 # function. Note that we have to call _object_contents on each 244 # constants because the code object of nested functions can 245 # show-up among the constants. 246 # 247 # Note that we also always ignore the first entry of co_consts 248 # which contains the function doc string. We assume that the 249 # function does not access its doc string. 250 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')') 251 252 # The code contents depends on the variable names used to 253 # accessed global variable, as changing the variable name changes 254 # the variable actually accessed and therefore changes the 255 # function result. 256 contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')') 257 258 259 # The code contents depends on its actual code!!! 260 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')') 261 262 return string.join(contents, '')
263 264
265 -def _function_contents(func):
266 """Return the signature contents of a function.""" 267 268 contents = [_code_contents(func.func_code)] 269 270 # The function contents depends on the value of defaults arguments 271 if func.func_defaults: 272 contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')') 273 else: 274 contents.append(',()') 275 276 # The function contents depends on the closure captured cell values. 277 try: 278 closure = func.func_closure or [] 279 except AttributeError: 280 # Older versions of Python do not support closures. 281 closure = [] 282 283 #xxx = [_object_contents(x.cell_contents) for x in closure] 284 try: 285 xxx = map(lambda x: _object_contents(x.cell_contents), closure) 286 except AttributeError: 287 xxx = [] 288 contents.append(',(' + string.join(xxx, ',') + ')') 289 290 return string.join(contents, '')
291 292
293 -def _actionAppend(act1, act2):
294 # This function knows how to slap two actions together. 295 # Mainly, it handles ListActions by concatenating into 296 # a single ListAction. 297 a1 = Action(act1) 298 a2 = Action(act2) 299 if a1 is None or a2 is None: 300 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2)) 301 if isinstance(a1, ListAction): 302 if isinstance(a2, ListAction): 303 return ListAction(a1.list + a2.list) 304 else: 305 return ListAction(a1.list + [ a2 ]) 306 else: 307 if isinstance(a2, ListAction): 308 return ListAction([ a1 ] + a2.list) 309 else: 310 return ListAction([ a1, a2 ])
311
312 -def _do_create_keywords(args, kw):
313 """This converts any arguments after the action argument into 314 their equivalent keywords and adds them to the kw argument. 315 """ 316 v = kw.get('varlist', ()) 317 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O'] 318 if is_String(v): v = (v,) 319 kw['varlist'] = tuple(v) 320 if args: 321 # turn positional args into equivalent keywords 322 cmdstrfunc = args[0] 323 if cmdstrfunc is None or is_String(cmdstrfunc): 324 kw['cmdstr'] = cmdstrfunc 325 elif callable(cmdstrfunc): 326 kw['strfunction'] = cmdstrfunc 327 else: 328 raise SCons.Errors.UserError( 329 'Invalid command display variable type. ' 330 'You must either pass a string or a callback which ' 331 'accepts (target, source, env) as parameters.') 332 if len(args) > 1: 333 kw['varlist'] = args[1:] + kw['varlist'] 334 if kw.get('strfunction', _null) is not _null \ 335 and kw.get('cmdstr', _null) is not _null: 336 raise SCons.Errors.UserError( 337 'Cannot have both strfunction and cmdstr args to Action()')
338
339 -def _do_create_action(act, kw):
340 """This is the actual "implementation" for the 341 Action factory method, below. This handles the 342 fact that passing lists to Action() itself has 343 different semantics than passing lists as elements 344 of lists. 345 346 The former will create a ListAction, the latter 347 will create a CommandAction by converting the inner 348 list elements to strings.""" 349 350 if isinstance(act, ActionBase): 351 return act 352 353 if is_List(act): 354 #TODO(1.5) return CommandAction(act, **kw) 355 return apply(CommandAction, (act,), kw) 356 357 if callable(act): 358 try: 359 gen = kw['generator'] 360 del kw['generator'] 361 except KeyError: 362 gen = 0 363 if gen: 364 action_type = CommandGeneratorAction 365 else: 366 action_type = FunctionAction 367 return action_type(act, kw) 368 369 if is_String(act): 370 var=SCons.Util.get_environment_var(act) 371 if var: 372 # This looks like a string that is purely an Environment 373 # variable reference, like "$FOO" or "${FOO}". We do 374 # something special here...we lazily evaluate the contents 375 # of that Environment variable, so a user could put something 376 # like a function or a CommandGenerator in that variable 377 # instead of a string. 378 return LazyAction(var, kw) 379 commands = string.split(str(act), '\n') 380 if len(commands) == 1: 381 #TODO(1.5) return CommandAction(commands[0], **kw) 382 return apply(CommandAction, (commands[0],), kw) 383 # The list of string commands may include a LazyAction, so we 384 # reprocess them via _do_create_list_action. 385 return _do_create_list_action(commands, kw) 386 return None
387
388 -def _do_create_list_action(act, kw):
389 """A factory for list actions. Convert the input list into Actions 390 and then wrap them in a ListAction.""" 391 acts = [] 392 for a in act: 393 aa = _do_create_action(a, kw) 394 if aa is not None: acts.append(aa) 395 if not acts: 396 return None 397 elif len(acts) == 1: 398 return acts[0] 399 else: 400 return ListAction(acts)
401
402 -def Action(act, *args, **kw):
403 """A factory for action objects.""" 404 # Really simple: the _do_create_* routines do the heavy lifting. 405 _do_create_keywords(args, kw) 406 if is_List(act): 407 return _do_create_list_action(act, kw) 408 return _do_create_action(act, kw)
409
410 -class ActionBase:
411 """Base class for all types of action objects that can be held by 412 other objects (Builders, Executors, etc.) This provides the 413 common methods for manipulating and combining those actions.""" 414
415 - def __cmp__(self, other):
416 return cmp(self.__dict__, other)
417
418 - def genstring(self, target, source, env):
419 return str(self)
420
421 - def get_contents(self, target, source, env):
422 result = [ self.get_presig(target, source, env) ] 423 # This should never happen, as the Action() factory should wrap 424 # the varlist, but just in case an action is created directly, 425 # we duplicate this check here. 426 vl = self.varlist 427 if is_String(vl): vl = (vl,) 428 for v in vl: 429 result.append(env.subst('${'+v+'}')) 430 return string.join(result, '')
431
432 - def __add__(self, other):
433 return _actionAppend(self, other)
434
435 - def __radd__(self, other):
436 return _actionAppend(other, self)
437
438 - def presub_lines(self, env):
439 # CommandGeneratorAction needs a real environment 440 # in order to return the proper string here, since 441 # it may call LazyAction, which looks up a key 442 # in that env. So we temporarily remember the env here, 443 # and CommandGeneratorAction will use this env 444 # when it calls its _generate method. 445 self.presub_env = env 446 lines = string.split(str(self), '\n') 447 self.presub_env = None