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 5357 2011/09/09 21:31:03 bdeegan"
101
102 import SCons.compat
103
104 import dis
105 import os
106
107 import pickle
108 import re
109 import sys
110 import subprocess
111
112 from SCons.Debug import logInstanceCreation
113 import SCons.Errors
114 import SCons.Executor
115 import SCons.Util
116 import SCons.Subst
117
118
119 is_String = SCons.Util.is_String
120 is_List = SCons.Util.is_List
121
124
125 print_actions = 1
126 execute_actions = 1
127 print_actions_presub = 0
128
130 try:
131 return n.rfile()
132 except AttributeError:
133 return n
134
137
138 try:
139 SET_LINENO = dis.SET_LINENO
140 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
141 except AttributeError:
142 remove_set_lineno_codes = lambda x: x
143 else:
159
160 strip_quotes = re.compile('^[\'"](.*)[\'"]$')
161
162
164 """Return the signature contents of a callable Python object.
165 """
166 try:
167
168 return _function_contents(obj.im_func)
169
170 except AttributeError:
171 try:
172
173 return _function_contents(obj.__call__.im_func)
174
175 except AttributeError:
176 try:
177
178 return _code_contents(obj)
179
180 except AttributeError:
181
182 return _function_contents(obj)
183
184
186 """Return the signature contents of any Python object.
187
188 We have to handle the case where object contains a code object
189 since it can be pickled directly.
190 """
191 try:
192
193 return _function_contents(obj.im_func)
194
195 except AttributeError:
196 try:
197
198 return _function_contents(obj.__call__.im_func)
199
200 except AttributeError:
201 try:
202
203 return _code_contents(obj)
204
205 except AttributeError:
206 try:
207
208 return _function_contents(obj)
209
210 except AttributeError:
211
212 try:
213 return pickle.dumps(obj)
214 except (pickle.PicklingError, TypeError):
215
216
217
218
219
220 return str(obj)
221
222
223 -def _code_contents(code):
224 """Return the signature contents of a code object.
225
226 By providing direct access to the code object of the
227 function, Python makes this extremely easy. Hooray!
228
229 Unfortunately, older versions of Python include line
230 number indications in the compiled byte code. Boo!
231 So we remove the line number byte codes to prevent
232 recompilations from moving a Python function.
233 """
234
235 contents = []
236
237
238
239 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
240 try:
241 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
242 except AttributeError:
243
244 contents.append(",0,0")
245
246
247
248
249
250
251
252
253
254 contents.append(',(' + ','.join(map(_object_contents,code.co_consts[1:])) + ')')
255
256
257
258
259
260 contents.append(',(' + ','.join(map(_object_contents,code.co_names)) + ')')
261
262
263
264 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
265
266 return ''.join(contents)
267
268
270 """Return the signature contents of a function."""
271
272 contents = [_code_contents(func.func_code)]
273
274
275 if func.func_defaults:
276 contents.append(',(' + ','.join(map(_object_contents,func.func_defaults)) + ')')
277 else:
278 contents.append(',()')
279
280
281 try:
282 closure = func.func_closure or []
283 except AttributeError:
284
285 closure = []
286
287
288 try:
289 xxx = [_object_contents(x.cell_contents) for x in closure]
290 except AttributeError:
291 xxx = []
292 contents.append(',(' + ','.join(xxx) + ')')
293
294 return ''.join(contents)
295
296
298
299
300
301 a1 = Action(act1)
302 a2 = Action(act2)
303 if a1 is None:
304 return a2
305 if a2 is None:
306 return a1
307 if isinstance(a1, ListAction):
308 if isinstance(a2, ListAction):
309 return ListAction(a1.list + a2.list)
310 else:
311 return ListAction(a1.list + [ a2 ])
312 else:
313 if isinstance(a2, ListAction):
314 return ListAction([ a1 ] + a2.list)
315 else:
316 return ListAction([ a1, a2 ])
317
319 """This converts any arguments after the action argument into
320 their equivalent keywords and adds them to the kw argument.
321 """
322 v = kw.get('varlist', ())
323
324 if is_String(v): v = (v,)
325 kw['varlist'] = tuple(v)
326 if args:
327
328 cmdstrfunc = args[0]
329 if cmdstrfunc is None or is_String(cmdstrfunc):
330 kw['cmdstr'] = cmdstrfunc
331 elif callable(cmdstrfunc):
332 kw['strfunction'] = cmdstrfunc
333 else:
334 raise SCons.Errors.UserError(
335 'Invalid command display variable type. '
336 'You must either pass a string or a callback which '
337 'accepts (target, source, env) as parameters.')
338 if len(args) > 1:
339 kw['varlist'] = args[1:] + kw['varlist']
340 if kw.get('strfunction', _null) is not _null \
341 and kw.get('cmdstr', _null) is not _null:
342 raise SCons.Errors.UserError(
343 'Cannot have both strfunction and cmdstr args to Action()')
344
346 """This is the actual "implementation" for the
347 Action factory method, below. This handles the
348 fact that passing lists to Action() itself has
349 different semantics than passing lists as elements
350 of lists.
351
352 The former will create a ListAction, the latter
353 will create a CommandAction by converting the inner
354 list elements to strings."""
355
356 if isinstance(act, ActionBase):
357 return act
358
359 if is_List(act):
360 return CommandAction(act, **kw)
361
362 if callable(act):
363 try:
364 gen = kw['generator']
365 del kw['generator']
366 except KeyError:
367 gen = 0
368 if gen:
369 action_type = CommandGeneratorAction
370 else:
371 action_type = FunctionAction
372 return action_type(act, kw)
373
374 if is_String(act):
375 var=SCons.Util.get_environment_var(act)
376 if var:
377
378
379
380
381
382
383 return LazyAction(var, kw)
384 commands = str(act).split('\n')
385 if len(commands) == 1:
386 return CommandAction(commands[0], **kw)
387
388
389 return _do_create_list_action(commands, kw)
390
391 if isinstance(act, int) or isinstance(act, float):
392 raise TypeError("Don't know how to create an Action from a number (%s)"%act)
393
394 return None
395
397 """A factory for list actions. Convert the input list into Actions
398 and then wrap them in a ListAction."""
399 acts = []
400 for a in act:
401 aa = _do_create_action(a, kw)
402 if aa is not None: acts.append(aa)
403 if not acts:
404 return ListAction([])
405 elif len(acts) == 1:
406 return acts[0]
407 else:
408 return ListAction(acts)
409
411 """A factory for action objects."""
412
413 _do_create_keywords(args, kw)
414 if is_List(act):
415 return _do_create_list_action(act, kw)
416 return _do_create_action(act, kw)
417
419 """Base class for all types of action objects that can be held by
420 other objects (Builders, Executors, etc.) This provides the
421 common methods for manipulating and combining those actions."""
422
424 return cmp(self.__dict__, other)
425
428
429 batch_key = no_batch_key
430
433
434 - def get_contents(self, target, source, env):
435 result = [ self.get_presig(target, source, env) ]
436
437
438
439 vl = self.get_varlist(target, source, env)
440 if is_String(vl): vl = (vl,)
441 for v in vl:
442 result.append(env.subst('${'+v+'}'))
443 return ''.join(result)
444
446 return _actionAppend(self, other)
447
449 return _actionAppend(other, self)
450
452
453
454
455
456
457
458 self.presub_env = env
459 lines = str(self).split('\n')
460 self.presub_env = None
461 return lines
462
463 - def get_varlist(self, target, source, env, executor=None):
465
467 """
468 Returns the type of targets ($TARGETS, $CHANGED_TARGETS) used
469 by this action.
470 """
471 return self.targets
472
474 """Base class for actions that create output objects."""
475 - def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
476 presub=_null, chdir=None, exitstatfunc=None,
477 batch_key=None, targets='$TARGETS',
478 **kw):
479 self.cmdstr = cmdstr
480 if strfunction is not _null:
481 if strfunction is None:
482 self.cmdstr = None
483 else:
484 self.strfunction = strfunction
485 self.varlist = varlist
486 self.presub = presub
487 self.chdir = chdir
488 if not exitstatfunc:
489 exitstatfunc = default_exitstatfunc
490 self.exitstatfunc = exitstatfunc
491
492 self.targets = targets
493
494 if batch_key:
495 if not callable(batch_key):
496
497
498
499
500 def default_batch_key(self, env, target, source):
501 return (id(self), id(env))
502 batch_key = default_batch_key
503 SCons.Util.AddMethod(self, batch_key, 'batch_key')
504
506
507
508
509
510
511
512
513
514 try:
515 sys.stdout.write(unicode(s + "\n"))
516 except UnicodeDecodeError:
517 sys.stdout.write(s + "\n")
518
526 if not is_List(target):
527 target = [target]
528 if not is_List(source):
529 source = [source]
530
531 if presub is _null:
532 presub = self.presub
533 if presub is _null:
534 presub = print_actions_presub
535 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
536 if show is _null: show = print_actions
537 if execute is _null: execute = execute_actions
538 if chdir is _null: chdir = self.chdir
539 save_cwd = None
540 if chdir:
541 save_cwd = os.getcwd()
542 try:
543 chdir = str(chdir.abspath)
544 except AttributeError:
545 if not is_String(chdir):
546 if executor:
547 chdir = str(executor.batches[0].targets[0].dir)
548 else:
549 chdir = str(target[0].dir)
550 if presub:
551 if executor:
552 target = executor.get_all_targets()
553 source = executor.get_all_sources()
554 t = ' and '.join(map(str, target))
555 l = '\n '.join(self.presub_lines(env))
556 out = u"Building %s with action:\n %s\n" % (t, l)
557 sys.stdout.write(out)
558 cmd = None
559 if show and self.strfunction:
560 if executor:
561 target = executor.get_all_targets()
562 source = executor.get_all_sources()
563 try:
564 cmd = self.strfunction(target, source, env, executor)
565 except TypeError:
566 cmd = self.strfunction(target, source, env)
567 if cmd:
568 if chdir:
569 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
570 try:
571 get = env.get
572 except AttributeError:
573 print_func = self.print_cmd_line
574 else:
575 print_func = get('PRINT_CMD_LINE_FUNC')
576 if not print_func:
577 print_func = self.print_cmd_line
578 print_func(cmd, target, source, env)
579 stat = 0
580 if execute:
581 if chdir:
582 os.chdir(chdir)
583 try:
584 stat = self.execute(target, source, env, executor=executor)
585 if isinstance(stat, SCons.Errors.BuildError):
586 s = exitstatfunc(stat.status)
587 if s:
588 stat.status = s
589 else:
590 stat = s
591 else:
592 stat = exitstatfunc(stat)
593 finally:
594 if save_cwd:
595 os.chdir(save_cwd)
596 if cmd and save_cwd:
597 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
598
599 return stat
600
601
603 """Takes a list of command line arguments and returns a pretty
604 representation for printing."""
605 cl = []
606 for arg in map(str, cmd_list):
607 if ' ' in arg or '\t' in arg:
608 arg = '"' + arg + '"'
609 cl.append(arg)
610 return ' '.join(cl)
611
612
613
614
615
616
617 default_ENV = None
632
633
634
635
636
637 -def _subproc(scons_env, cmd, error = 'ignore', **kw):
638 """Do common setup for a subprocess.Popen() call"""
639
640 io = kw.get('stdin')
641 if is_String(io) and io == 'devnull':
642 kw['stdin'] = open(os.devnull)
643 io = kw.get('stdout')
644 if is_String(io) and io == 'devnull':
645 kw['stdout'] = open(os.devnull, 'w')
646 io = kw.get('stderr')
647 if is_String(io) and io == 'devnull':
648 kw['stderr'] = open(os.devnull, 'w')
649
650
651 ENV = kw.get('env', None)
652 if ENV is None: ENV = get_default_ENV(scons_env)
653
654
655 new_env = {}
656 for key, value in ENV.items():
657 if is_List(value):
658
659
660
661 value = SCons.Util.flatten_sequence(value)
662 new_env[key] = os.pathsep.join(map(str, value))
663 else:
664
665
666
667
668
669
670 new_env[key] = str(value)
671 kw['env'] = new_env
672
673 try:
674 return subprocess.Popen(cmd, **kw)
675 except EnvironmentError, e:
676 if error == 'raise': raise
677
678 class dummyPopen(object):
679 def __init__(self, e): self.exception = e
680 def communicate(self): return ('','')
681 def wait(self): return -self.exception.errno
682 stdin = None
683 class f(object):
684 def read(self): return ''
685 def readline(self): return ''
686 stdout = stderr = f()
687 return dummyPopen(e)
688
690 """Class for command-execution actions."""
692
693
694
695
696
697
698
699
700
701 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
702
703 _ActionAction.__init__(self, **kw)
704 if is_List(cmd):
705 if list(filter(is_List, cmd)):
706 raise TypeError("CommandAction should be given only " \
707 "a single command")
708 self.cmd_list = cmd
709
711 if is_List(self.cmd_list):
712 return ' '.join(map(str, self.cmd_list))
713 return str(self.cmd_list)
714
715 - def process(self, target, source, env, executor=None):
716 if executor:
717 result = env.subst_list(self.cmd_list, 0, executor=executor)
718 else:
719 result = env.subst_list(self.cmd_list, 0, target, source)
720 silent = None
721 ignore = None
722 while True:
723 try: c = result[0][0][0]
724 except IndexError: c = None
725 if c == '@': silent = 1
726 elif c == '-': ignore = 1
727 else: break
728 result[0][0] = result[0][0][1:]
729 try:
730 if not result[0][0]:
731 result[0] = result[0][1:]
732 except IndexError:
733 pass
734 return result, ignore, silent
735
736 - def strfunction(self, target, source, env, executor=None):
737 if self.cmdstr is None:
738 return None
739 if self.cmdstr is not _null:
740 from SCons.Subst import SUBST_RAW
741 if executor:
742 c = env.subst(self.cmdstr, SUBST_RAW, executor=executor)
743 else:
744 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
745 if c:
746 return c
747 cmd_list, ignore, silent = self.process(target, source, env, executor)
748 if silent:
749 return ''
750 return _string_from_cmd_list(cmd_list[0])
751
752 - def execute(self, target, source, env, executor=None):
753 """Execute a command action.
754
755 This will handle lists of commands as well as individual commands,
756 because construction variable substitution may turn a single
757 "command" into a list. This means that this class can actually
758 handle lists of commands, even though that's not how we use it
759 externally.
760 """
761 escape_list = SCons.Subst.escape_list
762 flatten_sequence = SCons.Util.flatten_sequence
763
764 try:
765 shell = env['SHELL']
766 except KeyError:
767 raise SCons.Errors.UserError('Missing SHELL construction variable.')
768
769 try:
770 spawn = env['SPAWN']
771 except KeyError:
772 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
773 else:
774 if is_String(spawn):
775 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
776
777 escape = env.get('ESCAPE', lambda x: x)
778
779 ENV = get_default_ENV(env)
780
781
782 for key, value in ENV.items():
783 if not is_String(value):
784 if is_List(value):
785
786
787
788 value = flatten_sequence(value)
789 ENV[key] = os.pathsep.join(map(str, value))
790 else:
791
792
793
794
795 ENV[key] = str(value)
796
797 if executor:
798 target = executor.get_all_targets()
799 source = executor.get_all_sources()
800 cmd_list, ignore, silent = self.process(target, list(map(rfile, source)), env, executor)
801
802
803 for cmd_line in filter(len, cmd_list):
804
805 cmd_line = escape_list(cmd_line, escape)
806 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
807 if not ignore and result:
808 msg = "Error %s" % result
809 return SCons.Errors.BuildError(errstr=msg,
810 status=result,
811 action=self,
812 command=cmd_line)
813 return 0
814
815 - def get_presig(self, target, source, env, executor=None):
816 """Return the signature contents of this action's command line.
817
818 This strips $(-$) and everything in between the string,
819 since those parts don't affect signatures.
820 """
821 from SCons.Subst import SUBST_SIG
822 cmd = self.cmd_list
823 if is_List(cmd):
824 cmd = ' '.join(map(str, cmd))
825 else:
826 cmd = str(cmd)
827 if executor:
828 return env.subst_target_source(cmd, SUBST_SIG, executor=executor)
829 else:
830 return env.subst_target_source(cmd, SUBST_SIG, target, source)
831
833 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
834 if is_String(icd) and icd[:1] == '$':
835 icd = env.subst(icd)
836 if not icd or icd in ('0', 'None'):
837 return []
838 from SCons.Subst import SUBST_SIG
839 if executor:
840 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, executor=executor)
841 else:
842 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
843 res = []
844 for cmd_line in cmd_list:
845 if cmd_line:
846 d = str(cmd_line[0])
847 m = strip_quotes.match(d)
848 if m:
849 d = m.group(1)
850 d = env.WhereIs(d)
851 if d:
852 res.append(env.fs.File(d))
853 return res
854
856 """Class for command-generator actions."""
858 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
859 self.generator = generator
860 self.gen_kw = kw
861 self.varlist = kw.get('varlist', ())
862 self.targets = kw.get('targets', '$TARGETS')
863
864 - def _generate(self, target, source, env, for_signature, executor=None):
865
866
867 if not is_List(target):
868 target = [target]
869
870 if executor:
871 target = executor.get_all_targets()
872 source = executor.get_all_sources()
873 ret = self.generator(target=target,
874 source=source,
875 env=env,
876 for_signature=for_signature)
877 gen_cmd = Action(ret, **self.gen_kw)
878 if not gen_cmd:
879 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
880 return gen_cmd
881
883 try:
884 env = self.presub_env
885 except AttributeError:
886 env = None
887 if env is None:
888 env = SCons.Defaults.DefaultEnvironment()
889 act = self._generate([], [], env, 1)
890 return str(act)
891
894
895 - def genstring(self, target, source, env, executor=None):
896 return self._generate(target, source, env, 1, executor).genstring(target, source, env)
897
900 act = self._generate(target, source, env, 0, executor)
901 if act is None:
902 raise UserError("While building `%s': "
903 "Cannot deduce file extension from source files: %s"
904 % (repr(list(map(str, target))), repr(list(map(str, source)))))
905 return act(target, source, env, exitstatfunc, presub,
906 show, execute, chdir, executor)
907
908 - def get_presig(self, target, source, env, executor=None):
909 """Return the signature contents of this action's command line.
910
911 This strips $(-$) and everything in between the string,
912 since those parts don't affect signatures.
913 """
914 return self._generate(target, source, env, 1, executor).get_presig(target, source, env)
915
918
919 - def get_varlist(self, target, source, env, executor=None):
920 return self._generate(target, source, env, 1, executor).get_varlist(target, source, env, executor)
921
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944 -class LazyAction(CommandGeneratorAction, CommandAction):
945
952
958
960 if env:
961 c = env.get(self.var, '')
962 else:
963 c = ''
964 gen_cmd = Action(c, **self.gen_kw)
965 if not gen_cmd:
966 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
967 return gen_cmd
968
969 - def _generate(self, target, source, env, for_signature, executor=None):
971
972 - def __call__(self, target, source, env, *args, **kw):
975
979
980 - def get_varlist(self, target, source, env, executor=None):
983
984
986 """Class for Python function actions."""
987
989 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
990
991 self.execfunction = execfunction
992 try:
993 self.funccontents = _callable_contents(execfunction)
994 except AttributeError:
995 try:
996
997 self.gc = execfunction.get_contents
998 except AttributeError:
999
1000 self.funccontents = _object_contents(execfunction)
1001
1002 _ActionAction.__init__(self, **kw)
1003
1005 try:
1006 return self.execfunction.__name__
1007 except AttributeError:
1008 try:
1009 return self.execfunction.__class__.__name__
1010 except AttributeError:
1011 return "unknown_python_function"
1012
1013 - def strfunction(self, target, source, env, executor=None):
1033 return '[' + ", ".join(map(quote, a)) + ']'
1034 try:
1035 strfunc = self.execfunction.strfunction
1036 except AttributeError:
1037 pass
1038 else:
1039 if strfunc is None:
1040 return None
1041 if callable(strfunc):
1042 return strfunc(target, source, env)
1043 name = self.function_name()
1044 tstr = array(target)
1045 sstr = array(source)
1046 return "%s(%s, %s)" % (name, tstr, sstr)
1047
1049 name = self.function_name()
1050 if name == 'ActionCaller':
1051 return str(self.execfunction)
1052 return "%s(target, source, env)" % name
1053
1054 - def execute(self, target, source, env, executor=None):
1055 exc_info = (None,None,None)
1056 try:
1057 if executor:
1058 target = executor.get_all_targets()
1059 source = executor.get_all_sources()
1060 rsources = list(map(rfile, source))
1061 try:
1062 result = self.execfunction(target=target, source=rsources, env=env)
1063 except KeyboardInterrupt, e:
1064 raise
1065 except SystemExit, e:
1066 raise
1067 except Exception, e:
1068 result = e
1069 exc_info = sys.exc_info()
1070
1071 if result:
1072 result = SCons.Errors.convert_to_BuildError(result, exc_info)
1073 result.node=target
1074 result.action=self
1075 try:
1076 result.command=self.strfunction(target, source, env, executor)
1077 except TypeError:
1078 result.command=self.strfunction(target, source, env)
1079
1080
1081
1082
1083
1084
1085
1086 if (exc_info[1] and
1087 not isinstance(exc_info[1],EnvironmentError)):
1088 raise result
1089
1090 return result
1091 finally:
1092
1093
1094
1095 del exc_info
1096
1097
1099 """Return the signature contents of this callable action."""
1100 try:
1101 return self.gc(target, source, env)
1102 except AttributeError:
1103 return self.funccontents
1104
1107
1109 """Class for lists of other actions."""
1116 self.list = list(map(list_of_actions, actionlist))
1117
1118
1119 self.varlist = ()
1120 self.targets = '$TARGETS'
1121
1123 return '\n'.join([a.genstring(target, source, env) for a in self.list])
1124
1126 return '\n'.join(map(str, self.list))
1127
1131
1133 """Return the signature contents of this action list.
1134
1135 Simple concatenation of the signatures of the elements.
1136 """
1137 return "".join([x.get_contents(target, source, env) for x in self.list])
1138
1150
1156
1157 - def get_varlist(self, target, source, env, executor=None):
1163
1165 """A class for delaying calling an Action function with specific
1166 (positional and keyword) arguments until the Action is actually
1167 executed.
1168
1169 This class looks to the rest of the world like a normal Action object,
1170 but what it's really doing is hanging on to the arguments until we
1171 have a target, source and env to use for the expansion.
1172 """
1174 self.parent = parent
1175 self.args = args
1176 self.kw = kw
1177
1178 - def get_contents(self, target, source, env):
1179 actfunc = self.parent.actfunc
1180 try:
1181
1182 contents = str(actfunc.func_code.co_code)
1183 except AttributeError:
1184
1185 try:
1186 contents = str(actfunc.__call__.im_func.func_code.co_code)
1187 except AttributeError:
1188
1189
1190 contents = str(actfunc)
1191 contents = remove_set_lineno_codes(contents)
1192 return contents
1193
1194 - def subst(self, s, target, source, env):
1195
1196
1197 if is_List(s):
1198 result = []
1199 for elem in s:
1200 result.append(self.subst(elem, target, source, env))
1201 return self.parent.convert(result)
1202
1203
1204
1205
1206 if s == '$__env__':
1207 return env
1208 elif is_String(s):
1209 return env.subst(s, 1, target, source)
1210 return self.parent.convert(s)
1211
1213 return [self.subst(x, target, source, env) for x in self.args]
1214
1215 - def subst_kw(self, target, source, env):
1216 kw = {}
1217 for key in self.kw.keys():
1218 kw[key] = self.subst(self.kw[key], target, source, env)
1219 return kw
1220
1221 - def __call__(self, target, source, env, executor=None):
1222 args = self.subst_args(target, source, env)
1223 kw = self.subst_kw(target, source, env)
1224 return self.parent.actfunc(*args, **kw)
1225
1227 args = self.subst_args(target, source, env)
1228 kw = self.subst_kw(target, source, env)
1229 return self.parent.strfunc(*args, **kw)
1230
1232 return 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