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 5110 2010/07/25 16:14:38 bdeegan"
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
616
617
618
619
620
621 -def _subproc(scons_env, cmd, error = 'ignore', **kw):
622 """Do common setup for a subprocess.Popen() call"""
623
624 io = kw.get('stdin')
625 if is_String(io) and io == 'devnull':
626 kw['stdin'] = open(os.devnull)
627 io = kw.get('stdout')
628 if is_String(io) and io == 'devnull':
629 kw['stdout'] = open(os.devnull, 'w')
630 io = kw.get('stderr')
631 if is_String(io) and io == 'devnull':
632 kw['stderr'] = open(os.devnull, 'w')
633
634
635 ENV = kw.get('env', None)
636 if ENV is None: ENV = get_default_ENV(scons_env)
637
638
639 new_env = {}
640 for key, value in ENV.items():
641 if is_List(value):
642
643
644
645 value = SCons.Util.flatten_sequence(value)
646 new_env[key] = string.join(map(str, value), os.pathsep)
647 else:
648
649
650
651
652
653
654 new_env[key] = str(value)
655 kw['env'] = new_env
656
657 try:
658
659 return apply(subprocess.Popen, (cmd,), kw)
660 except EnvironmentError, e:
661 if error == 'raise': raise
662
663 class dummyPopen:
664 def __init__(self, e): self.exception = e
665 def communicate(self): return ('','')
666 def wait(self): return -self.exception.errno
667 stdin = None
668 class f:
669 def read(self): return ''
670 def readline(self): return ''
671 stdout = stderr = f()
672 return dummyPopen(e)
673
675 """Class for command-execution actions."""
677
678
679
680
681
682
683
684
685
686 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
687
688
689 apply(_ActionAction.__init__, (self,), kw)
690 if is_List(cmd):
691 if filter(is_List, cmd):
692 raise TypeError, "CommandAction should be given only " \
693 "a single command"
694 self.cmd_list = cmd
695
697 if is_List(self.cmd_list):
698 return string.join(map(str, self.cmd_list), ' ')
699 return str(self.cmd_list)
700
701 - def process(self, target, source, env, executor=None):
702 if executor:
703 result = env.subst_list(self.cmd_list, 0, executor=executor)
704 else:
705 result = env.subst_list(self.cmd_list, 0, target, source)
706 silent = None
707 ignore = None
708 while 1:
709 try: c = result[0][0][0]
710 except IndexError: c = None
711 if c == '@': silent = 1
712 elif c == '-': ignore = 1
713 else: break
714 result[0][0] = result[0][0][1:]
715 try:
716 if not result[0][0]:
717 result[0] = result[0][1:]
718 except IndexError:
719 pass
720 return result, ignore, silent
721
722 - def strfunction(self, target, source, env, executor=None):
723 if self.cmdstr is None:
724 return None
725 if self.cmdstr is not _null:
726 from SCons.Subst import SUBST_RAW
727 if executor:
728 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
729 else:
730 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
731 if c:
732 return c
733 cmd_list, ignore, silent = self.process(target, source, env, executor)
734 if silent:
735 return ''
736 return _string_from_cmd_list(cmd_list[0])
737
738 - def execute(self, target, source, env, executor=None):
739 """Execute a command action.
740
741 This will handle lists of commands as well as individual commands,
742 because construction variable substitution may turn a single
743 "command" into a list. This means that this class can actually
744 handle lists of commands, even though that's not how we use it
745 externally.
746 """
747 escape_list = SCons.Subst.escape_list
748 flatten_sequence = SCons.Util.flatten_sequence
749
750 try:
751 shell = env['SHELL']
752 except KeyError:
753 raise SCons.Errors.UserError('Missing SHELL construction variable.')
754
755 try:
756 spawn = env['SPAWN']
757 except KeyError:
758 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
759 else:
760 if is_String(spawn):
761 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
762
763 escape = env.get('ESCAPE', lambda x: x)
764
765 ENV = get_default_ENV(env)
766
767
768 for key, value in ENV.items():
769 if not is_String(value):
770 if is_List(value):
771
772
773
774 value = flatten_sequence(value)
775 ENV[key] = string.join(map(str, value), os.pathsep)
776 else:
777
778
779
780
781 ENV[key] = str(value)
782
783 if executor:
784 target = executor.get_all_targets()
785 source = executor.get_all_sources()
786 cmd_list, ignore, silent = self.process(target, map(rfile, source), env, executor)
787
788
789 for cmd_line in filter(len, cmd_list):
790
791 cmd_line = escape_list(cmd_line, escape)
792 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
793 if not ignore and result:
794 msg = "Error %s" % result
795 return SCons.Errors.BuildError(errstr=msg,
796 status=result,
797 action=self,
798 command=cmd_line)
799 return 0
800
801 - def get_presig(self, target, source, env, executor=None):
802 """Return the signature contents of this action's command line.
803
804 This strips $(-$) and everything in between the string,
805 since those parts don't affect signatures.
806 """
807 from SCons.Subst import SUBST_SIG
808 cmd = self.cmd_list
809 if is_List(cmd):
810 cmd = string.join(map(str, cmd))
811 else:
812 cmd = str(cmd)
813 if executor:
814 return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
815 else:
816 return env.subst_target_source(cmd, SUBST_SIG, target, source)
817
819 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
820 if is_String(icd) and icd[:1] == '$':
821 icd = env.subst(icd)
822 if not icd or icd in ('0', 'None'):
823 return []
824 from SCons.Subst import SUBST_SIG
825 if executor:
826 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
827 else:
828 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
829 res = []
830 for cmd_line in cmd_list:
831 if cmd_line:
832 d = str(cmd_line[0])
833 m = strip_quotes.match(d)
834 if m:
835 d = m.group(1)
836 d = env.WhereIs(d)
837 if d:
838 res.append(env.fs.File(d))
839 return res
840
842 """Class for command-generator actions."""
844 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
845 self.generator = generator
846 self.gen_kw = kw
847 self.varlist = kw.get('varlist', ())
848 self.targets = kw.get('targets', '$TARGETS')
849
850 - def _generate(self, target, source, env, for_signature, executor=None):
851
852
853 if not is_List(target):
854 target = [target]
855
856 if executor:
857 target = executor.get_all_targets()
858 source = executor.get_all_sources()
859 ret = self.generator(target=target,
860 source=source,
861 env=env,
862 for_signature=for_signature)
863
864 gen_cmd = apply(Action, (ret,), self.gen_kw)
865 if not gen_cmd:
866 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
867 return gen_cmd
868
870 try:
871 env = self.presub_env
872 except AttributeError:
873 env = None
874 if env is None:
875 env = SCons.Defaults.DefaultEnvironment()
876 act = self._generate([], [], env, 1)
877 return str(act)
878
881
882 - def genstring(self, target, source, env, executor=None):
883 return self._generate(target, source, env, 1, executor).genstring(target, source, env)
884
887 act = self._generate(target, source, env, 0, executor)
888 if act is None:
889 raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source))))
890 return act(target, source, env, exitstatfunc, presub,
891 show, execute, chdir, executor)
892
893 - def get_presig(self, target, source, env, executor=None):
894 """Return the signature contents of this action's command line.
895
896 This strips $(-$) and everything in between the string,
897 since those parts don't affect signatures.
898 """
899 return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
900
903
904 - def get_varlist(self, target, source, env, executor=None):
905 return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
906
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929 -class LazyAction(CommandGeneratorAction, CommandAction):
930
937
943
945 if env:
946 c = env.get(self.var, '')
947 else:
948 c = ''
949
950 gen_cmd = apply(Action, (c,), self.gen_kw)
951 if not gen_cmd:
952 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
953 return gen_cmd
954
955 - def _generate(self, target, source, env, for_signature, executor=None):
957
958 - def __call__(self, target, source, env, *args, **kw):
959 args = (self, target, source, env) + args
960 c = self.get_parent_class(env)
961
962 return apply(c.__call__, args, kw)
963
967
968 - def get_varlist(self, target, source, env, executor=None):
971
972
974 """Class for Python function actions."""
975
977 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
978
979 self.execfunction = execfunction
980 try:
981 self.funccontents = _callable_contents(execfunction)
982 except AttributeError:
983 try:
984
985 self.gc = execfunction.get_contents
986 except AttributeError:
987
988 self.funccontents = _object_contents(execfunction)
989
990
991 apply(_ActionAction.__init__, (self,), kw)
992
994 try:
995 return self.execfunction.__name__
996 except AttributeError:
997 try:
998 return self.execfunction.__class__.__name__
999 except AttributeError:
1000 return "unknown_python_function"
1001
1002 - def strfunction(self, target, source, env, executor=None):
1022 return '[' + string.join(map(quote, a), ", ") + ']'
1023 try:
1024 strfunc = self.execfunction.strfunction
1025 except AttributeError:
1026 pass
1027 else:
1028 if strfunc is None:
1029 return None
1030 if callable(strfunc):
1031 return strfunc(target, source, env)
1032 name = self.function_name()
1033 tstr = array(target)
1034 sstr = array(source)
1035 return "%s(%s, %s)" % (name, tstr, sstr)
1036
1038 name = self.function_name()
1039 if name == 'ActionCaller':
1040 return str(self.execfunction)
1041 return "%s(target, source, env)" % name
1042
1043 - def execute(self, target, source, env, executor=None):
1044 exc_info = (None,None,None)
1045 try:
1046 if executor:
1047 target = executor.get_all_targets()
1048 source = executor.get_all_sources()
1049 rsources = map(rfile, source)
1050 try:
1051 result = self.execfunction(target=target, source=rsources, env=env)
1052 except KeyboardInterrupt, e:
1053 raise
1054 except SystemExit, e:
1055 raise
1056 except Exception, e:
1057 result = e
1058 exc_info = sys.exc_info()
1059
1060 if result:
1061 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1062 result.node=target
1063 result.action=self
1064 try:
1065 result.command=self.strfunction(target, source, env, executor)
1066 except TypeError:
1067 result.command=self.strfunction(target, source, env)
1068
1069
1070
1071
1072
1073
1074
1075 if (exc_info[1] and
1076 not isinstance(exc_info[1],EnvironmentError)):
1077 raise result
1078
1079 return result
1080 finally:
1081
1082
1083
1084 del exc_info
1085
1086
1088 """Return the signature contents of this callable action."""
1089 try:
1090 return self.gc(target, source, env)
1091 except AttributeError:
1092 return self.funccontents
1093
1096
1098 """Class for lists of other actions."""
1105 self.list = map(list_of_actions, list)
1106
1107
1108 self.varlist = ()
1109 self.targets = '$TARGETS'
1110
1112 return string.join(map(lambda a, t=target, s=source, e=env:
1113 a.genstring(t, s, e),
1114 self.list),
1115 '\n')
1116
1118 return string.join(map(str, self.list), '\n')
1119
1123
1125 """Return the signature contents of this action list.
1126
1127 Simple concatenation of the signatures of the elements.
1128 """
1129 return string.join(map(lambda x, t=target, s=source, e=env:
1130 x.get_contents(t, s, e),
1131 self.list),
1132 "")
1133
1145
1151
1152 - def get_varlist(self, target, source, env, executor=None):
1158
1160 """A class for delaying calling an Action function with specific
1161 (positional and keyword) arguments until the Action is actually
1162 executed.
1163
1164 This class looks to the rest of the world like a normal Action object,
1165 but what it's really doing is hanging on to the arguments until we
1166 have a target, source and env to use for the expansion.
1167 """
1169 self.parent = parent
1170 self.args = args
1171 self.kw = kw
1172
1173 - def get_contents(self, target, source, env):
1174 actfunc = self.parent.actfunc
1175 try:
1176
1177 contents = str(actfunc.func_code.co_code)
1178 except AttributeError:
1179
1180 try:
1181 contents = str(actfunc.__call__.im_func.func_code.co_code)
1182 except AttributeError:
1183
1184
1185 contents = str(actfunc)
1186 contents = remove_set_lineno_codes(contents)
1187 return contents
1188
1189 - def subst(self, s, target, source, env):
1190
1191
1192 if is_List(s):
1193 result = []
1194 for elem in s:
1195 result.append(self.subst(elem, target, source, env))
1196 return self.parent.convert(result)
1197
1198
1199
1200
1201 if s == '$__env__':
1202 return env
1203 elif is_String(s):
1204 return env.subst(s, 1, target, source)
1205 return self.parent.convert(s)
1206
1208 return map(lambda x, self=self, t=target, s=source, e=env:
1209 self.subst(x, t, s, e),
1210 self.args)
1211
1212 - def subst_kw(self, target, source, env):
1213 kw = {}
1214 for key in self.kw.keys():
1215 kw[key] = self.subst(self.kw[key], target, source, env)
1216 return kw
1217
1218 - def __call__(self, target, source, env, executor=None):
1219 args = self.subst_args(target, source, env)
1220 kw = self.subst_kw(target, source, env)
1221
1222 return apply(self.parent.actfunc, args, kw)
1223
1225 args = self.subst_args(target, source, env)
1226 kw = self.subst_kw(target, source, env)
1227
1228 return apply(self.parent.strfunc, args, kw)
1229
1231
1232 return apply(self.parent.strfunc, self.args, self.kw)
1233
1235 """A factory class that will wrap up an arbitrary function
1236 as an SCons-executable Action object.
1237
1238 The real heavy lifting here is done by the ActionCaller class.
1239 We just collect the (positional and keyword) arguments that we're
1240 called with and give them to the ActionCaller object we create,
1241 so it can hang onto them until it needs them.
1242 """
1243 - def __init__(self, actfunc, strfunc, convert=lambda x: x):
1244 self.actfunc = actfunc
1245 self.strfunc = strfunc
1246 self.convert = convert
1247
1252
1253
1254
1255
1256
1257
1258