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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 __revision__ = "src/engine/SCons/Action.py 4720 2010/03/24 03:14:11 jars"
101
102 import cPickle
103 import dis
104 import os
105 import re
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
117 is_String = SCons.Util.is_String
118 is_List = SCons.Util.is_List
119
122
123 print_actions = 1
124 execute_actions = 1
125 print_actions_presub = 0
126
128 try:
129 return n.rfile()
130 except AttributeError:
131 return n
132
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:
157
158 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
159
160
162 """Return the signature contents of a callable Python object.
163 """
164 try:
165
166 return _function_contents(obj.im_func)
167
168 except AttributeError:
169 try:
170
171 return _function_contents(obj.__call__.im_func)
172
173 except AttributeError:
174 try:
175
176 return _code_contents(obj)
177
178 except AttributeError:
179
180 return _function_contents(obj)
181
182
184 """Return the signature contents of any Python object.
185
186 We have to handle the case where object contains a code object
187 since it can be pickled directly.
188 """
189 try:
190
191 return _function_contents(obj.im_func)
192
193 except AttributeError:
194 try:
195
196 return _function_contents(obj.__call__.im_func)
197
198 except AttributeError:
199 try:
200
201 return _code_contents(obj)
202
203 except AttributeError:
204 try:
205
206 return _function_contents(obj)
207
208 except AttributeError:
209
210 try:
211 return cPickle.dumps(obj)
212 except (cPickle.PicklingError, TypeError):
213
214
215
216
217
218 return str(obj)
219
220
221 -def _code_contents(code):
222 """Return the signature contents of a code object.
223
224 By providing direct access to the code object of the
225 function, Python makes this extremely easy. Hooray!
226
227 Unfortunately, older versions of Python include line
228 number indications in the compiled byte code. Boo!
229 So we remove the line number byte codes to prevent
230 recompilations from moving a Python function.
231 """
232
233 contents = []
234
235
236
237 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
238 try:
239 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
240 except AttributeError:
241
242 contents.append(",0,0")
243
244
245
246
247
248
249
250
251
252 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')')
253
254
255
256
257
258 contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
259
260
261
262 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
263
264 return string.join(contents, '')
265
266
268 """Return the signature contents of a function."""
269
270 contents = [_code_contents(func.func_code)]
271
272
273 if func.func_defaults:
274 contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')')
275 else:
276 contents.append(',()')
277
278
279 try:
280 closure = func.func_closure or []
281 except AttributeError:
282
283 closure = []
284
285
286 try:
287 xxx = map(lambda x: _object_contents(x.cell_contents), closure)
288 except AttributeError:
289 xxx = []
290 contents.append(',(' + string.join(xxx, ',') + ')')
291
292 return string.join(contents, '')
293
294
296
297
298
299 a1 = Action(act1)
300 a2 = Action(act2)
301 if a1 is None or a2 is None:
302 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
303 if isinstance(a1, ListAction):
304 if isinstance(a2, ListAction):
305 return ListAction(a1.list + a2.list)
306 else:
307 return ListAction(a1.list + [ a2 ])
308 else:
309 if isinstance(a2, ListAction):
310 return ListAction([ a1 ] + a2.list)
311 else:
312 return ListAction([ a1, a2 ])
313
315 """This converts any arguments after the action argument into
316 their equivalent keywords and adds them to the kw argument.
317 """
318 v = kw.get('varlist', ())
319
320 if is_String(v): v = (v,)
321 kw['varlist'] = tuple(v)
322 if args:
323
324 cmdstrfunc = args[0]
325 if cmdstrfunc is None or is_String(cmdstrfunc):
326 kw['cmdstr'] = cmdstrfunc
327 elif callable(cmdstrfunc):
328 kw['strfunction'] = cmdstrfunc
329 else:
330 raise SCons.Errors.UserError(
331 'Invalid command display variable type. '
332 'You must either pass a string or a callback which '
333 'accepts (target, source, env) as parameters.')
334 if len(args) > 1:
335 kw['varlist'] = args[1:] + kw['varlist']
336 if kw.get('strfunction', _null) is not _null \
337 and kw.get('cmdstr', _null) is not _null:
338 raise SCons.Errors.UserError(
339 'Cannot have both strfunction and cmdstr args to Action()')
340
342 """This is the actual "implementation" for the
343 Action factory method, below. This handles the
344 fact that passing lists to Action() itself has
345 different semantics than passing lists as elements
346 of lists.
347
348 The former will create a ListAction, the latter
349 will create a CommandAction by converting the inner
350 list elements to strings."""
351
352 if isinstance(act, ActionBase):
353 return act
354
355 if is_List(act):
356
357 return apply(CommandAction, (act,), kw)
358
359 if callable(act):
360 try:
361 gen = kw['generator']
362 del kw['generator']
363 except KeyError:
364 gen = 0
365 if gen:
366 action_type = CommandGeneratorAction
367 else:
368 action_type = FunctionAction
369 return action_type(act, kw)
370
371 if is_String(act):
372 var=SCons.Util.get_environment_var(act)
373 if var:
374
375
376
377
378
379
380 return LazyAction(var, kw)
381 commands = string.split(str(act), '\n')
382 if len(commands) == 1:
383
384 return apply(CommandAction, (commands[0],), kw)
385
386
387 return _do_create_list_action(commands, kw)
388 return None
389
391 """A factory for list actions. Convert the input list into Actions
392 and then wrap them in a ListAction."""
393 acts = []
394 for a in act:
395 aa = _do_create_action(a, kw)
396 if aa is not None: acts.append(aa)
397 if not acts:
398 return ListAction([])
399 elif len(acts) == 1:
400 return acts[0]
401 else:
402 return ListAction(acts)
403
405 """A factory for action objects."""
406
407 _do_create_keywords(args, kw)
408 if is_List(act):
409 return _do_create_list_action(act, kw)
410 return _do_create_action(act, kw)
411
413 """Base class for all types of action objects that can be held by
414 other objects (Builders, Executors, etc.) This provides the
415 common methods for manipulating and combining those actions."""
416
418 return cmp(self.__dict__, other)
419
422
423 batch_key = no_batch_key
424
427
428 - def get_contents(self, target, source, env):
429 result = [ self.get_presig(target, source, env) ]
430
431
432
433 vl = self.get_varlist(target, source, env)
434 if is_String(vl): vl = (vl,)
435 for v in vl:
436 result.append(env.subst('${'+v+'}'))
437 return string.join(result, '')
438
440 return _actionAppend(self, other)
441
443 return _actionAppend(other, self)
444
446
447
448
449
450
451
452 self.presub_env = env
453 lines = string.split(str(self), '\n')
454 self.presub_env = None
455 return lines
456
457 - def get_varlist(self, target, source, env, executor=None):
459
461 """
462 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
463 by this action.
464 """
465 return self.targets
466
468 """Base class for actions that create output objects."""
469 - def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
470 presub=_null, chdir=None, exitstatfunc=None,
471 batch_key=None, targets='$TARGETS',
472 **kw):
473 self.cmdstr = cmdstr
474 if strfunction is not _null:
475 if strfunction is None:
476 self.cmdstr = None
477 else:
478 self.strfunction = strfunction
479 self.varlist = varlist
480 self.presub = presub
481 self.chdir = chdir
482 if not exitstatfunc:
483 exitstatfunc = default_exitstatfunc
484 self.exitstatfunc = exitstatfunc
485
486 self.targets = targets
487
488 if batch_key:
489 if not callable(batch_key):
490
491
492
493
494 def default_batch_key(self, env, target, source):
495 return (id(self), id(env))
496 batch_key = default_batch_key
497 SCons.Util.AddMethod(self, batch_key, 'batch_key')
498
500 sys.stdout.write(s + "\n")
501
509 if not is_List(target):
510 target = [target]
511 if not is_List(source):
512 source = [source]
513
514 if presub is _null:
515 presub = self.presub
516 if presub is _null:
517 presub = print_actions_presub
518 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
519 if show is _null: show = print_actions
520 if execute is _null: execute = execute_actions
521 if chdir is _null: chdir = self.chdir
522 save_cwd = None
523 if chdir:
524 save_cwd = os.getcwd()
525 try:
526 chdir = str(chdir.abspath)
527 except AttributeError:
528 if not is_String(chdir):
529 if executor:
530 chdir = str(executor.batches[0].targets[0].dir)
531 else:
532 chdir = str(target[0].dir)
533 if presub:
534 if executor:
535 target = executor.get_all_targets()
536 source = executor.get_all_sources()
537 t = string.join(map(str, target), ' and ')
538 l = string.join(self.presub_lines(env), '\n ')
539 out = "Building %s with action:\n %s\n" % (t, l)
540 sys.stdout.write(out)
541 cmd = None
542 if show and self.strfunction:
543 if executor:
544 target = executor.get_all_targets()
545 source = executor.get_all_sources()
546 try:
547 cmd = self.strfunction(target, source, env, executor)
548 except TypeError:
549 cmd = self.strfunction(target, source, env)
550 if cmd:
551 if chdir:
552 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
553 try:
554 get = env.get
555 except AttributeError:
556 print_func = self.print_cmd_line
557 else:
558 print_func = get('PRINT_CMD_LINE_FUNC')
559 if not print_func:
560 print_func = self.print_cmd_line
561 print_func(cmd, target, source, env)
562 stat = 0
563 if execute:
564 if chdir:
565 os.chdir(chdir)
566 try:
567 stat = self.execute(target, source, env, executor=executor)
568 if isinstance(stat, SCons.Errors.BuildError):
569 s = exitstatfunc(stat.status)
570 if s:
571 stat.status = s
572 else:
573 stat = s
574 else:
575 stat = exitstatfunc(stat)
576 finally:
577 if save_cwd:
578 os.chdir(save_cwd)
579 if cmd and save_cwd:
580 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
581
582 return stat
583
584
586 """Takes a list of command line arguments and returns a pretty
587 representation for printing."""
588 cl = []
589 for arg in map(str, cmd_list):
590 if ' ' in arg or '\t' in arg:
591 arg = '"' + arg + '"'
592 cl.append(arg)
593 return string.join(cl)
594
595
596
597
598
599
600 default_ENV = None
615
616
617
618
619
620 -def _subproc(env, cmd, error = 'ignore', **kw):
621 """Do common setup for a subprocess.Popen() call"""
622
623 io = kw.get('stdin')
624 if is_String(io) and io == 'devnull':
625 kw['stdin'] = open(os.devnull)
626 io = kw.get('stdout')
627 if is_String(io) and io == 'devnull':
628 kw['stdout'] = open(os.devnull, 'w')
629 io = kw.get('stderr')
630 if is_String(io) and io == 'devnull':
631 kw['stderr'] = open(os.devnull, 'w')
632
633
634 ENV = kw.get('env', None)
635 if ENV is None: ENV = get_default_ENV(env)
636
637
638 new_env = {}
639 for key, value in ENV.items():
640 if is_List(value):
641
642
643
644 value = SCons.Util.flatten_sequence(value)
645 new_env[key] = string.join(map(str, value), os.pathsep)
646 else:
647
648
649
650
651
652
653 new_env[key] = str(value)
654 kw['env'] = new_env
655
656 try:
657
658 return apply(subprocess.Popen, (cmd,), kw)
659 except EnvironmentError, e:
660 if error == 'raise': raise
661
662 class dummyPopen:
663 def __init__(self, e): self.exception = e
664 def communicate(self): return ('','')
665 def wait(self): return -self.exception.errno
666 stdin = None
667 class f:
668 def read(self): return ''
669 def readline(self): return ''
670 stdout = stderr = f()
671 return dummyPopen(e)
672
674 """Class for command-execution actions."""
676
677
678
679
680
681
682
683
684
685 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
686
687
688 apply(_ActionAction.__init__, (self,), kw)
689 if is_List(cmd):
690 if filter(is_List, cmd):
691 raise TypeError, "CommandAction should be given only " \
692 "a single command"
693 self.cmd_list = cmd
694
696 if is_List(self.cmd_list):
697 return string.join(map(str, self.cmd_list), ' ')
698 return str(self.cmd_list)
699
700 - def process(self, target, source, env, executor=None):
701 if executor:
702 result = env.subst_list(self.cmd_list, 0, executor=executor)
703 else:
704 result = env.subst_list(self.cmd_list, 0, target, source)
705 silent = None
706 ignore = None
707 while 1:
708 try: c = result[0][0][0]
709 except IndexError: c = None
710 if c == '@': silent = 1
711 elif c == '-': ignore = 1
712 else: break
713 result[0][0] = result[0][0][1:]
714 try:
715 if not result[0][0]:
716 result[0] = result[0][1:]
717 except IndexError:
718 pass
719 return result, ignore, silent
720
721 - def strfunction(self, target, source, env, executor=None):
722 if self.cmdstr is None:
723 return None
724 if self.cmdstr is not _null:
725 from SCons.Subst import SUBST_RAW
726 if executor:
727 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
728 else:
729 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
730 if c:
731 return c
732 cmd_list, ignore, silent = self.process(target, source, env, executor)
733 if silent:
734 return ''
735 return _string_from_cmd_list(cmd_list[0])
736
737 - def execute(self, target, source, env, executor=None):
738 """Execute a command action.
739
740 This will handle lists of commands as well as individual commands,
741 because construction variable substitution may turn a single
742 "command" into a list. This means that this class can actually
743 handle lists of commands, even though that's not how we use it
744 externally.
745 """
746 escape_list = SCons.Subst.escape_list
747 flatten_sequence = SCons.Util.flatten_sequence
748
749 try:
750 shell = env['SHELL']
751 except KeyError:
752 raise SCons.Errors.UserError('Missing SHELL construction variable.')
753
754 try:
755 spawn = env['SPAWN']
756 except KeyError:
757 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
758 else:
759 if is_String(spawn):
760 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
761
762 escape = env.get('ESCAPE', lambda x: x)
763
764 ENV = get_default_ENV(env)
765
766
767 for key, value in ENV.items():
768 if not is_String(value):
769 if is_List(value):
770
771
772
773 value = flatten_sequence(value)
774 ENV[key] = string.join(map(str, value), os.pathsep)
775 else:
776
777
778
779
780 ENV[key] = str(value)
781
782 if executor:
783 target = executor.get_all_targets()
784 source = executor.get_all_sources()
785 cmd_list, ignore, silent = self.process(target, map(rfile, source), env, executor)
786
787
788 for cmd_line in filter(len, cmd_list):
789
790 cmd_line = escape_list(cmd_line, escape)
791 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
792 if not ignore and result:
793 msg = "Error %s" % result
794 return SCons.Errors.BuildError(errstr=msg,
795 status=result,
796 action=self,
797 command=cmd_line)
798 return 0
799
800 - def get_presig(self, target, source, env, executor=None):
801 """Return the signature contents of this action's command line.
802
803 This strips $(-$) and everything in between the string,
804 since those parts don't affect signatures.
805 """
806 from SCons.Subst import SUBST_SIG
807 cmd = self.cmd_list
808 if is_List(cmd):
809 cmd = string.join(map(str, cmd))
810 else:
811 cmd = str(cmd)
812 if executor:
813 return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
814 else:
815 return env.subst_target_source(cmd, SUBST_SIG, target, source)
816
818 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
819 if is_String(icd) and icd[:1] == '$':
820 icd = env.subst(icd)
821 if not icd or icd in ('0', 'None'):
822 return []
823 from SCons.Subst import SUBST_SIG
824 if executor:
825 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
826 else:
827 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
828 res = []
829 for cmd_line in cmd_list:
830 if cmd_line:
831 d = str(cmd_line[0])
832 m = strip_quotes.match(d)
833 if m:
834 d = m.group(1)
835 d = env.WhereIs(d)
836 if d:
837 res.append(env.fs.File(d))
838 return res
839
841 """Class for command-generator actions."""
843 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
844 self.generator = generator
845 self.gen_kw = kw
846 self.varlist = kw.get('varlist', ())
847 self.targets = kw.get('targets', '$TARGETS')
848
849 - def _generate(self, target, source, env, for_signature, executor=None):
850
851
852 if not is_List(target):
853 target = [target]
854
855 if executor:
856 target = executor.get_all_targets()
857 source = executor.get_all_sources()
858 ret = self.generator(target=target,
859 source=source,
860 env=env,
861 for_signature=for_signature)
862
863 gen_cmd = apply(Action, (ret,), self.gen_kw)
864 if not gen_cmd:
865 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
866 return gen_cmd
867
869 try:
870 env = self.presub_env
871 except AttributeError:
872 env = None
873 if env is None:
874 env = SCons.Defaults.DefaultEnvironment()
875 act = self._generate([], [], env, 1)
876 return str(act)
877
880
881 - def genstring(self, target, source, env, executor=None):
882 return self._generate(target, source, env, 1, executor).genstring(target, source, env)
883
886 act = self._generate(target, source, env, 0, executor)
887 if act is None:
888 raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
889 return act(target, source, env, exitstatfunc, presub,
890 show, execute, chdir, executor)
891
892 - def get_presig(self, target, source, env, executor=None):
893 """Return the signature contents of this action's command line.
894
895 This strips $(-$) and everything in between the string,
896 since those parts don't affect signatures.
897 """
898 return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
899
902
903 - def get_varlist(self, target, source, env, executor=None):
904 return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
905
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928 -class LazyAction(CommandGeneratorAction, CommandAction):
929
936
942
944 if env:
945 c = env.get(self.var, '')
946 else:
947 c = ''
948
949 gen_cmd = apply(Action, (c,), self.gen_kw)
950 if not gen_cmd:
951 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
952 return gen_cmd
953
954 - def _generate(self, target, source, env, for_signature, executor=None):
956
957 - def __call__(self, target, source, env, *args, **kw):
958 args = (self, target, source, env) + args
959 c = self.get_parent_class(env)
960
961 return apply(c.__call__, args, kw)
962
966
967 - def get_varlist(self, target, source, env, executor=None):
970
971
973 """Class for Python function actions."""
974
976 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
977
978 self.execfunction = execfunction
979 try:
980 self.funccontents = _callable_contents(execfunction)
981 except AttributeError:
982 try:
983
984 self.gc = execfunction.get_contents
985 except AttributeError:
986
987 self.funccontents = _object_contents(execfunction)
988
989
990 apply(_ActionAction.__init__, (self,), kw)
991
993 try:
994 return self.execfunction.__name__
995 except AttributeError:
996 try:
997 return self.execfunction.__class__.__name__
998 except AttributeError:
999 return "unknown_python_function"
1000
1001 - def strfunction(self, target, source, env, executor=None):
1021 return '[' + string.join(map(quote, a), ", ") + ']'
1022 try:
1023 strfunc = self.execfunction.strfunction
1024 except AttributeError:
1025 pass
1026 else:
1027 if strfunc is None:
1028 return None
1029 if callable(strfunc):
1030 return strfunc(target, source, env)
1031 name = self.function_name()
1032 tstr = array(target)
1033 sstr = array(source)
1034 return "%s(%s, %s)" % (name, tstr, sstr)
1035
1037 name = self.function_name()
1038 if name == 'ActionCaller':
1039 return str(self.execfunction)
1040 return "%s(target, source, env)" % name
1041
1042 - def execute(self, target, source, env, executor=None):
1043 exc_info = (None,None,None)
1044 try:
1045 if executor:
1046 target = executor.get_all_targets()
1047 source = executor.get_all_sources()
1048 rsources = map(rfile, source)
1049 try:
1050 result = self.execfunction(target=target, source=rsources, env=env)
1051 except KeyboardInterrupt, e:
1052 raise
1053 except SystemExit, e:
1054 raise
1055 except Exception, e:
1056 result = e
1057 exc_info = sys.exc_info()
1058
1059 if result:
1060 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1061 result.node=target
1062 result.action=self
1063 try:
1064 result.command=self.strfunction(target, source, env, executor)
1065 except TypeError:
1066 result.command=self.strfunction(target, source, env)
1067
1068
1069
1070
1071
1072
1073
1074 if (exc_info[1] and
1075 not isinstance(exc_info[1],EnvironmentError)):
1076 raise result
1077
1078 return result
1079 finally:
1080
1081
1082
1083 del exc_info
1084
1085
1087 """Return the signature contents of this callable action."""
1088 try:
1089 return self.gc(target, source, env)
1090 except AttributeError:
1091 return self.funccontents
1092
1095
1097 """Class for lists of other actions."""
1104 self.list = map(list_of_actions, list)
1105
1106
1107 self.varlist = ()
1108 self.targets = '$TARGETS'
1109
1111 return string.join(map(lambda a, t=target, s=source, e=env:
1112 a.genstring(t, s, e),
1113 self.list),
1114 '\n')
1115
1117 return string.join(map(str, self.list), '\n')
1118
1122
1124 """Return the signature contents of this action list.
1125
1126 Simple concatenation of the signatures of the elements.
1127 """
1128 return string.join(map(lambda x, t=target, s=source, e=env:
1129 x.get_contents(t, s, e),
1130 self.list),
1131 "")
1132
1144
1150
1151 - def get_varlist(self, target, source, env, executor=None):
1157
1159 """A class for delaying calling an Action function with specific
1160 (positional and keyword) arguments until the Action is actually
1161 executed.
1162
1163 This class looks to the rest of the world like a normal Action object,
1164 but what it's really doing is hanging on to the arguments until we
1165 have a target, source and env to use for the expansion.
1166 """
1168 self.parent = parent
1169 self.args = args
1170 self.kw = kw
1171
1172 - def get_contents(self, target, source, env):
1173 actfunc = self.parent.actfunc
1174 try:
1175
1176 contents = str(actfunc.func_code.co_code)
1177 except AttributeError:
1178
1179 try:
1180 contents = str(actfunc.__call__.im_func.func_code.co_code)
1181 except AttributeError:
1182
1183
1184 contents = str(actfunc)
1185 contents = remove_set_lineno_codes(contents)
1186 return contents
1187
1188 - def subst(self, s, target, source, env):
1189
1190
1191 if is_List(s):
1192 result = []
1193 for elem in s:
1194 result.append(self.subst(elem, target, source, env))
1195 return self.parent.convert(result)
1196
1197
1198
1199
1200 if s == '$__env__':
1201 return env
1202 elif is_String(s):
1203 return env.subst(s, 1, target, source)
1204 return self.parent.convert(s)
1205
1207 return map(lambda x, self=self, t=target, s=source, e=env:
1208 self.subst(x, t, s, e),
1209 self.args)
1210
1211 - def subst_kw(self, target, source, env):
1212 kw = {}
1213 for key in self.kw.keys():
1214 kw[key] = self.subst(self.kw[key], target, source, env)
1215 return kw
1216
1217 - def __call__(self, target, source, env, executor=None):
1218 args = self.subst_args(target, source, env)
1219 kw = self.subst_kw(target, source, env)
1220
1221 return apply(self.parent.actfunc, args, kw)
1222
1224 args = self.subst_args(target, source, env)
1225 kw = self.subst_kw(target, source, env)
1226
1227 return apply(self.parent.strfunc, args, kw)
1228
1230
1231 return apply(self.parent.strfunc, self.args, self.kw)
1232
1234 """A factory class that will wrap up an arbitrary function
1235 as an SCons-executable Action object.
1236
1237 The real heavy lifting here is done by the ActionCaller class.
1238 We just collect the (positional and keyword) arguments that we're
1239 called with and give them to the ActionCaller object we create,
1240 so it can hang onto them until it needs them.
1241 """
1242 - def __init__(self, actfunc, strfunc, convert=lambda x: x):
1243 self.actfunc = actfunc
1244 self.strfunc = strfunc
1245 self.convert = convert
1246
1251
1252
1253
1254
1255
1256
1257